Contract Source Code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "IERC20.sol";
import "Initializable.sol";
import "IRelayEncoder.sol";
import "IxTokens.sol";
import "IXcmTransactor.sol";
import "ILedger.sol";
import "IAuthManager.sol";
import "ILido.sol";
contract Controller is Initializable {
// Event emitted when weight updated
event WeightUpdated (
uint8 index,
uint64 newValue
);
// Event emitted when bond called on relay chain
event Bond (
address caller,
bytes32 stash,
bytes32 controller,
uint256 amount
);
// Event emitted when bond extra called on relay chain
event BondExtra (
address caller,
bytes32 stash,
uint256 amount
);
// Event emitted when unbond on relay chain
event Unbond (
address caller,
bytes32 stash,
uint256 amount
);
// Event emitted when rebond called on relay chain
event Rebond (
address caller,
bytes32 stash,
uint256 amount
);
// Event emitted when withdraw called on relay chain
event Withdraw (
address caller,
bytes32 stash
);
// Event emitted when nominate called on relay chain
event Nominate (
address caller,
bytes32 stash,
bytes32[] validators
);
// Event emitted when chill called on relay chain
event Chill (
address caller,
bytes32 stash
);
// Event emitted when transfer vKSM from parachain to relay chain called
event TransferToRelaychain (
address from,
bytes32 to,
uint256 amount
);
// Event emitted when transfer KSM from relay chain to parachain called
event TransferToParachain (
bytes32 from,
address to,
uint256 amount
);
// ledger controller account
uint16 public rootDerivativeIndex;
// vKSM precompile
IERC20 internal VKSM;
// relay call builder precompile
IRelayEncoder internal RELAY_ENCODER;
// xcm transactor precompile
IXcmTransactor internal XCM_TRANSACTOR;
// xTokens precompile
IxTokens internal X_TOKENS;
// LIDO address
address public LIDO;
// first hex for encodeTransfer (defines parachain ID, 2023 for Kusama)
bytes public hex1;
// second hex for encodeTransfer (defines asset for transfer, fungible)
bytes public hex2;
// hex for determination pallet (0x1801 for Kusama)
bytes public asDerevativeHex;
// Second layer derivative-proxy account to index
mapping(address => uint16) public senderToIndex;
// Index to second layer derivative-proxy account
mapping(uint16 => bytes32) public indexToAccount;
// Enumerator for weights
enum WEIGHT {
AS_DERIVATIVE, // 410_000_000
BOND_BASE, // 600_000_000
BOND_EXTRA_BASE, // 1_100_000_000
UNBOND_BASE, // 1_250_000_000
WITHDRAW_UNBONDED_BASE, // 500_000_000
WITHDRAW_UNBONDED_PER_UNIT, // 60_000
REBOND_BASE, // 1_200_000_000
REBOND_PER_UNIT, // 40_000
CHILL_BASE, // 900_000_000
NOMINATE_BASE, // 1_000_000_000
NOMINATE_PER_UNIT, // 31_000_000
TRANSFER_TO_PARA_BASE, // 700_000_000
TRANSFER_TO_RELAY_BASE // 4_000_000_000
}
// Constant for max weight
uint64 public MAX_WEIGHT;// = 1_835_300_000;
// Array with current weights
uint64[] public weights;
// Parachain side fee on reverse transfer
uint256 public REVERSE_TRANSFER_FEE;// = 4_000_000
// Relay side fee on transfer
uint256 public TRANSFER_FEE;// = 18_900_000_000
// Controller manager role
bytes32 internal constant ROLE_CONTROLLER_MANAGER = keccak256("ROLE_CONTROLLER_MANAGER");
// Allows function calls only for registered ledgers
modifier onlyRegistred() {
require(senderToIndex[msg.sender] != 0, "CONTROLLER: UNREGISTERED_SENDER");
_;
}
// Allows function calls only for members with role
modifier auth(bytes32 role) {
require(IAuthManager(ILido(LIDO).AUTH_MANAGER()).has(role, msg.sender), "CONTROLLER: UNAUTHOROZED");
_;
}
// Allows function calls only for LIDO contract
modifier onlyLido() {
require(msg.sender == LIDO, "CONTROLLER: CALLER_NOT_LIDO");
_;
}
/**
* @notice Initialize ledger contract.
* @param _rootDerivativeIndex - stash account id
* @param _vKSM - vKSM contract address
* @param _relayEncoder - relayEncoder(relaychain calls builder) contract address
* @param _xcmTransactor - xcmTransactor(relaychain calls relayer) contract address
* @param _xTokens - minimal allowed nominator balance
* @param _hex1 - first hex for encodeTransfer
* @param _hex2 - second hex for encodeTransfer
* @param _asDerevativeHex - hex for as derevative call
*/
function initialize(
uint16 _rootDerivativeIndex,
address _vKSM,
address _relayEncoder,
address _xcmTransactor,
address _xTokens,
bytes calldata _hex1,
bytes calldata _hex2,
bytes calldata _asDerevativeHex
) external initializer {
require(address(VKSM) == address(0), "CONTROLLER: ALREADY_INITIALIZED");
rootDerivativeIndex = _rootDerivativeIndex;
VKSM = IERC20(_vKSM);
RELAY_ENCODER = IRelayEncoder(_relayEncoder);
XCM_TRANSACTOR = IXcmTransactor(_xcmTransactor);
X_TOKENS = IxTokens(_xTokens);
hex1 = _hex1;
hex2 = _hex2;
asDerevativeHex = _asDerevativeHex;
}
/**
* @notice Get current weight by enum
* @param weightType - enum index of weight
*/
function getWeight(WEIGHT weightType) public view returns(uint64) {
return weights[uint256(weightType)];
}
/**
* @notice Set new max weight. Can be called only by ROLE_CONTROLLER_MANAGER
* @param _maxWeight - max weight
*/
function setMaxWeight(uint64 _maxWeight) external auth(ROLE_CONTROLLER_MANAGER) {
MAX_WEIGHT = _maxWeight;
}
/**
* @notice Set new REVERSE_TRANSFER_FEE
* @param _reverseTransferFee - new fee
*/
function setReverseTransferFee(uint256 _reverseTransferFee) external auth(ROLE_CONTROLLER_MANAGER) {
REVERSE_TRANSFER_FEE = _reverseTransferFee;
}
/**
* @notice Set new TRANSFER_FEE
* @param _transferFee - new fee
*/
function setTransferFee(uint256 _transferFee) external auth(ROLE_CONTROLLER_MANAGER) {
TRANSFER_FEE = _transferFee;
}
/**
* @notice Set new hexes parametes for encodeTransfer
* @param _hex1 - first hex for encodeTransfer
* @param _hex2 - second hex for encodeTransfer
* @param _asDerevativeHex - hex for as derevative call
*/
function updateHexParameters(bytes calldata _hex1, bytes calldata _hex2, bytes calldata _asDerevativeHex) external auth(ROLE_CONTROLLER_MANAGER) {
hex1 = _hex1;
hex2 = _hex2;
asDerevativeHex = _asDerevativeHex;
}
/**
* @notice Set LIDO address. Function can be called only once
* @param _lido - LIDO address
*/
function setLido(address _lido) external {
require(LIDO == address(0) && _lido != address(0), "CONTROLLER: LIDO_ALREADY_INITIALIZED");
LIDO = _lido;
}
/**
* @notice Update weights array. Weight updated only if weight = _weight | 1 << 65
* @param _weights - weights array
*/
function setWeights(
uint128[] calldata _weights
) external auth(ROLE_CONTROLLER_MANAGER) {
require(_weights.length == uint256(type(WEIGHT).max) + 1, "CONTROLLER: WRONG_WEIGHTS_SIZE");
for (uint256 i = 0; i < _weights.length; ++i) {
if ((_weights[i] >> 64) > 0) { // if _weights[i] = _weights[i] | 1 << 65 we must update i-th weight
if (weights.length == i) {
weights.push(0);
}
weights[i] = uint64(_weights[i]);
emit WeightUpdated(uint8(i), weights[i]);
}
}
}
/**
* @notice Register new ledger contract
* @param index - index of ledger contract
* @param accountId - relay chain address of ledger
* @param paraAddress - parachain address of ledger
*/
function newSubAccount(uint16 index, bytes32 accountId, address paraAddress) external onlyLido {
require(indexToAccount[index + 1] == bytes32(0), "CONTROLLER: ALREADY_REGISTERED");
senderToIndex[paraAddress] = index + 1;
indexToAccount[index + 1] = accountId;
}
/**
* @notice Unregister ledger contract
* @param paraAddress - parachain address of ledger
*/
function deleteSubAccount(address paraAddress) external onlyLido {
require(senderToIndex[paraAddress] > 0, "CONTROLLER: UNREGISTERED_LEDGER");
delete indexToAccount[senderToIndex[paraAddress]];
delete senderToIndex[paraAddress];
}
/**
* @notice Nominate validators from ledger on relay chain
* @param validators - validators addresses to nominate
*/
function nominate(bytes32[] calldata validators) external onlyRegistred {
uint256[] memory convertedValidators = new uint256[](validators.length);
for (uint256 i = 0; i < validators.length; ++i) {
convertedValidators[i] = uint256(validators[i]);
}
callThroughDerivative(
getSenderIndex(),
getWeight(WEIGHT.NOMINATE_BASE) + getWeight(WEIGHT.NOMINATE_PER_UNIT) * uint64(validators.length),
RELAY_ENCODER.encode_nominate(convertedValidators)
);
emit Nominate(msg.sender, getSenderAccount(), validators);
}
/**
* @notice Bond KSM of ledger on relay chain
* @param controller - controller which used to bond
* @param amount - amount of KSM to bond
*/
function bond(bytes32 controller, uint256 amount) external onlyRegistred {
callThroughDerivative(
getSenderIndex(),
getWeight(WEIGHT.BOND_BASE),
RELAY_ENCODER.encode_bond(uint256(controller), amount, bytes(hex"00"))
);
emit Bond(msg.sender, getSenderAccount(), controller, amount);
}
/**
* @notice Bond extra KSM of ledger on relay chain
* @param amount - extra amount of KSM to bond
*/
function bondExtra(uint256 amount) external onlyRegistred {
callThroughDerivative(
getSenderIndex(),
getWeight(WEIGHT.BOND_EXTRA_BASE),
RELAY_ENCODER.encode_bond_extra(amount)
);
emit BondExtra(msg.sender, getSenderAccount(), amount);
}
/**
* @notice Unbond KSM of ledger on relay chain
* @param amount - amount of KSM to unbond
*/
function unbond(uint256 amount) external onlyRegistred {
callThroughDerivative(
getSenderIndex(),
getWeight(WEIGHT.UNBOND_BASE),
RELAY_ENCODER.encode_unbond(amount)
);
emit Unbond(msg.sender, getSenderAccount(), amount);
}
/**
* @notice Withdraw unbonded tokens (move unbonded tokens to free)
* @param slashingSpans - number of slashes received by ledger in case if we trying set ledger bonded balance < min,
in other cases = 0
*/
function withdrawUnbonded(uint32 slashingSpans) external onlyRegistred {
callThroughDerivative(
getSenderIndex(),
getWeight(WEIGHT.WITHDRAW_UNBONDED_BASE) + getWeight(WEIGHT.WITHDRAW_UNBONDED_PER_UNIT) * slashingSpans,
RELAY_ENCODER.encode_withdraw_unbonded(slashingSpans)
);
emit Withdraw(msg.sender, getSenderAccount());
}
/**
* @notice Rebond KSM of ledger from unbonded chunks on relay chain
* @param amount - amount of KSM to rebond
* @param unbondingChunks - amount of unbonding chunks to rebond
*/
function rebond(uint256 amount, uint256 unbondingChunks) external onlyRegistred {
callThroughDerivative(
getSenderIndex(),
getWeight(WEIGHT.REBOND_BASE) + getWeight(WEIGHT.REBOND_PER_UNIT) * uint64(unbondingChunks),
RELAY_ENCODER.encode_rebond(amount)
);
emit Rebond(msg.sender, getSenderAccount(), amount);
}
/**
* @notice Put ledger to chill mode
*/
function chill() external onlyRegistred {
callThroughDerivative(
getSenderIndex(),
getWeight(WEIGHT.CHILL_BASE),
RELAY_ENCODER.encode_chill()
);
emit Chill(msg.sender, getSenderAccount());
}
/**
* @notice Transfer KSM from relay chain to parachain
* @param amount - amount of KSM to transfer
*/
function transferToParachain(uint256 amount) external onlyRegistred {
// to - msg.sender, from - getSenderIndex()
uint256 parachain_fee = REVERSE_TRANSFER_FEE;
callThroughDerivative(
getSenderIndex(),
getWeight(WEIGHT.TRANSFER_TO_PARA_BASE),
//encodeReverseTransfer(msg.sender, amount)
encodeLimitReserveTransfer(msg.sender, amount, getWeight(WEIGHT.TRANSFER_TO_PARA_BASE))
);
// compensate parachain side fee on reverse transfer
if (amount <= parachain_fee) {
// if amount less than fee just transfer amount
VKSM.transfer(msg.sender, amount);
}
else {
// else just compensate fee
VKSM.transfer(msg.sender, parachain_fee);
}
emit TransferToParachain(getSenderAccount(), msg.sender, amount);
}
/**
* @notice Transfer vKSM from parachain to relay chain
* @param amount - amount of vKSM to transfer
*/
function transferToRelaychain(uint256 amount) external onlyRegistred {
// to - getSenderIndex(), from - msg.sender
VKSM.transferFrom(msg.sender, address(this), amount);
IxTokens.Multilocation memory destination;
destination.parents = 1;
destination.interior = new bytes[](1);
destination.interior[0] = bytes.concat(bytes1(hex"01"), getSenderAccount(), bytes1(hex"00")); // X2, NetworkId: Any
X_TOKENS.transfer_with_fee(address(VKSM), amount, TRANSFER_FEE, destination, getWeight(WEIGHT.TRANSFER_TO_RELAY_BASE));
emit TransferToRelaychain(msg.sender, getSenderAccount(), amount);
}
/**
* @notice Get index of registered ledger
*/
function getSenderIndex() internal returns(uint16) {
return senderToIndex[msg.sender] - 1;
}
/**
* @notice Get relay chain address of msg.sender
*/
function getSenderAccount() internal returns(bytes32) {
return indexToAccount[senderToIndex[msg.sender]];
}
/**
* @notice Send call to relay cahin through xcm transactor
* @param index - index of ledger on relay chain
* @param weight - fees on tx execution
* @param call - bytes for tx execution
*/
function callThroughDerivative(uint16 index, uint64 weight, bytes memory call) internal {
bytes memory le_index = new bytes(2);
le_index[0] = bytes1(uint8(index));
le_index[1] = bytes1(uint8(index >> 8));
uint64 total_weight = weight + getWeight(WEIGHT.AS_DERIVATIVE);
require(total_weight <= MAX_WEIGHT, "CONTROLLER: TOO_MUCH_WEIGHT");
XCM_TRANSACTOR.transact_through_derivative(
0, // The transactor to be used
rootDerivativeIndex, // The index to be used
address(VKSM), // Address of the currencyId of the asset to be used for fees
total_weight, // The weight we want to buy in the destination chain
bytes.concat(asDerevativeHex, le_index, call) // The inner call to be executed in the destination chain
);
}
/**
* @notice Encoding bytes to call transfer on relay chain
* @param to - address of KSM receiver
* @param amount - amount of KSM to send
*/
function encodeReverseTransfer(address to, uint256 amount) internal returns(bytes memory) {
return bytes.concat(
hex1,
abi.encodePacked(to),
hex2,
scaleCompactUint(amount),
hex"00000000"
);
}
/**
* @notice Encoding bytes to call limit reserve transfer on relay chain
* @param to - address of KSM receiver
* @param amount - amount of KSM to send
* @param weight - weight for xcm call
*/
function encodeLimitReserveTransfer(address to, uint256 amount, uint64 weight) internal returns(bytes memory) {
return bytes.concat(
hex1,
abi.encodePacked(to),
hex2,
scaleCompactUint(amount),
hex"0000000001",
scaleCompactUint(uint256(weight))
);
}
/**
* @notice Converting uint256 value to le bytes
* @param value - uint256 value
* @param len - length of output bytes array
*/
function toLeBytes(uint256 value, uint256 len) internal returns(bytes memory) {
bytes memory out = new bytes(len);
for (uint256 idx = 0; idx < len; ++idx) {
out[idx] = bytes1(uint8(value));
value = value >> 8;
}
return out;
}
/**
* @notice Converting uint256 value to bytes
* @param value - uint256 value
*/
function scaleCompactUint(uint256 value) internal returns(bytes memory) {
if (value < 1<<6) {
return toLeBytes(value << 2, 1);
}
else if(value < 1 << 14) {
return toLeBytes((value << 2) + 1, 2);
}
else if(value < 1 << 30) {
return toLeBytes((value << 2) + 2, 4);
}
else {
uint256 numBytes = 0;
{
uint256 m = value;
for (; numBytes < 256 && m != 0; ++numBytes) {
m = m >> 8;
}
}
bytes memory out = new bytes(numBytes + 1);
out[0] = bytes1(uint8(((numBytes - 4) << 2) + 3));
for (uint256 i = 0; i < numBytes; ++i) {
out[i + 1] = bytes1(uint8(value & 0xFF));
value = value >> 8;
}
return out;
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
// SPDX-License-Identifier: MIT
// solhint-disable-next-line compiler-version
pragma solidity ^0.8.0;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
*/
bool private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Modifier to protect an initializer function from being invoked twice.
*/
modifier initializer() {
require(_initializing || !_initialized, "Initializable: contract is already initialized");
bool isTopLevelCall = !_initializing;
if (isTopLevelCall) {
_initializing = true;
_initialized = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @author The Moonbeam Team
/// @title The interface through which solidity contracts will interact with Relay Encoder
/// We follow this same interface including four-byte function selectors, in the precompile that
/// wraps the pallet
interface IRelayEncoder {
// dev Encode 'bond' relay call
// Selector: 31627376
// @param controller_address: Address of the controller
// @param amount: The amount to bond
// @param reward_destination: the account that should receive the reward
// @returns The bytes associated with the encoded call
function encode_bond(uint256 controller_address, uint256 amount, bytes memory reward_destination) external pure returns (bytes memory result);
// dev Encode 'bond_extra' relay call
// Selector: 49def326
// @param amount: The extra amount to bond
// @returns The bytes associated with the encoded call
function encode_bond_extra(uint256 amount) external pure returns (bytes memory result);
// dev Encode 'unbond' relay call
// Selector: bc4b2187
// @param amount: The amount to unbond
// @returns The bytes associated with the encoded call
function encode_unbond(uint256 amount) external pure returns (bytes memory result);
// dev Encode 'withdraw_unbonded' relay call
// Selector: 2d220331
// @param slashes: Weight hint, number of slashing spans
// @returns The bytes associated with the encoded call
function encode_withdraw_unbonded(uint32 slashes) external pure returns (bytes memory result);
// dev Encode 'validate' relay call
// Selector: 3a0d803a
// @param comission: Comission of the validator as parts_per_billion
// @param blocked: Whether or not the validator is accepting more nominations
// @returns The bytes associated with the encoded call
// selector: 3a0d803a
function encode_validate(uint256 comission, bool blocked) external pure returns (bytes memory result);
// dev Encode 'nominate' relay call
// Selector: a7cb124b
// @param nominees: An array of AccountIds corresponding to the accounts we will nominate
// @param blocked: Whether or not the validator is accepting more nominations
// @returns The bytes associated with the encoded call
function encode_nominate(uint256 [] memory nominees) external pure returns (bytes memory result);
// dev Encode 'chill' relay call
// Selector: bc4b2187
// @returns The bytes associated with the encoded call
function encode_chill() external pure returns (bytes memory result);
// dev Encode 'set_payee' relay call
// Selector: 9801b147
// @param reward_destination: the account that should receive the reward
// @returns The bytes associated with the encoded call
function encode_set_payee(bytes memory reward_destination) external pure returns (bytes memory result);
// dev Encode 'set_controller' relay call
// Selector: 7a8f48c2
// @param controller: The controller address
// @returns The bytes associated with the encoded call
function encode_set_controller(uint256 controller) external pure returns (bytes memory result);
// dev Encode 'rebond' relay call
// Selector: add6b3bf
// @param amount: The amount to rebond
// @returns The bytes associated with the encoded call
function encode_rebond(uint256 amount) external pure returns (bytes memory result);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title Xtokens Interface
*
* The interface through which solidity contracts will interact with xtokens pallet
*
*/
interface IxTokens {
// A multilocation is defined by its number of parents and the encoded junctions (interior)
struct Multilocation {
uint8 parents;
bytes [] interior;
}
/** Transfer a token through XCM based on its currencyId
*
* @dev The token transfer burns/transfers the corresponding amount before sending
* @param currency_address The ERC20 address of the currency we want to transfer
* @param amount The amount of tokens we want to transfer
* @param destination The Multilocation to which we want to send the tokens
* @param weight The weight we want to buy in the destination chain
*/
function transfer(address currency_address, uint256 amount, Multilocation memory destination, uint64 weight) external;
/** Transfer a token through XCM based on its currencyId
*
* @dev The token transfer burns/transfers the corresponding amount before sending
* @param currency_address The ERC20 address of the currency we want to transfer
* @param amount The amount of tokens we want to transfer
* @param fee The amount of fees
* @param destination The Multilocation to which we want to send the tokens
* @param weight The weight we want to buy in the destination chain
*/
function transfer_with_fee(address currency_address, uint256 amount, uint256 fee, Multilocation memory destination, uint64 weight) external;
/** Transfer a token through XCM based on its currencyId
*
* @dev The token transfer burns/transfers the corresponding amount before sending
* @param asset The asset we want to transfer, defined by its multilocation. Currently only Concrete Fungible assets
* @param amount The amount of tokens we want to transfer
* @param destination The Multilocation to which we want to send the tokens
* @param weight The weight we want to buy in the destination chain
*/
function transfer_multiasset(Multilocation memory asset, uint256 amount, Multilocation memory destination, uint64 weight) external;
}
// Function selector reference
// {
// "b9f813ff": "transfer(address,uint256,(uint8,bytes[]),uint64)",
// "b38c60fa": "transfer_multiasset((uint8,bytes[]),uint256,(uint8,bytes[]),uint64)"
//}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title Xcm Transactor Interface
*
* The interface through which solidity contracts will interact with xcm transactor pallet
*
*/
interface IXcmTransactor {
// A multilocation is defined by its number of parents and the encoded junctions (interior)
struct Multilocation {
uint8 parents;
bytes [] interior;
}
/** Get index of an account in xcm transactor
*
* @param index The index of which we want to retrieve the account
*/
function index_to_account(uint16 index) external view returns(address);
/** Get transact info of a multilocation
* Selector 71b0edfa
* @param multilocation The location for which we want to retrieve transact info
*/
function transact_info(Multilocation memory multilocation)
external view returns(uint64, uint256, uint64, uint64, uint256);
/** Transact through XCM using fee based on its multilocation
*
* @dev The token transfer burns/transfers the corresponding amount before sending
* @param transactor The transactor to be used
* @param index The index to be used
* @param fee_asset The asset in which we want to pay fees.
* It has to be a reserve of the destination chain
* @param weight The weight we want to buy in the destination chain
* @param inner_call The inner call to be executed in the destination chain
*/
function transact_through_derivative_multilocation(
uint8 transactor,
uint16 index,
Multilocation memory fee_asset,
uint64 weight,
bytes memory inner_call
) external;
/** Transact through XCM using fee based on its currency_id
*
* @dev The token transfer burns/transfers the corresponding amount before sending
* @param transactor The transactor to be used
* @param index The index to be used
* @param currency_id Address of the currencyId of the asset to be used for fees
* It has to be a reserve of the destination chain
* @param weight The weight we want to buy in the destination chain
* @param inner_call The inner call to be executed in the destination chain
*/
function transact_through_derivative(
uint8 transactor,
uint16 index,
address currency_id,
uint64 weight,
bytes memory inner_call
) external;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "Types.sol";
interface ILedger {
function initialize(
bytes32 _stashAccount,
bytes32 controllerAccount,
address vKSM,
address controller,
uint128 minNominatorBalance,
address lido,
uint128 _minimumBalance,
uint256 _maxUnlockingChunks
) external;
function pushData(uint64 eraId, Types.OracleData calldata staking) external;
function nominate(bytes32[] calldata validators) external;
function status() external view returns (Types.LedgerStatus);
function isEmpty() external view returns (bool);
function stashAccount() external view returns (bytes32);
function totalBalance() external view returns (uint128);
function setRelaySpecs(uint128 minNominatorBalance, uint128 minimumBalance, uint256 _maxUnlockingChunks) external;
function cachedTotalBalance() external view returns (uint128);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface Types {
struct Fee{
uint16 total;
uint16 operators;
uint16 developers;
uint16 treasury;
}
struct Stash {
bytes32 stashAccount;
uint64 eraId;
}
enum LedgerStatus {
// bonded but not participate in staking
Idle,
// participate as nominator
Nominator,
// participate as validator
Validator,
// not bonded not participate in staking
None
}
struct UnlockingChunk {
uint128 balance;
uint64 era;
}
struct OracleData {
bytes32 stashAccount;
bytes32 controllerAccount;
LedgerStatus stakeStatus;
// active part of stash balance
uint128 activeBalance;
// locked for stake stash balance.
uint128 totalBalance;
// totalBalance = activeBalance + sum(unlocked.balance)
UnlockingChunk[] unlocking;
uint32[] claimedRewards;
// stash account balance. It includes locked (totalBalance) balance assigned
// to a controller.
uint128 stashBalance;
// slashing spans for ledger
uint32 slashingSpans;
}
struct RelaySpec {
uint16 maxValidatorsPerLedger;
uint128 minNominatorBalance;
uint128 ledgerMinimumActiveBalance;
uint256 maxUnlockingChunks;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IAuthManager {
function has(bytes32 role, address member) external view returns (bool);
function add(bytes32 role, address member) external;
function remove(bytes32 role, address member) external;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "Types.sol";
interface ILido {
function MAX_ALLOWABLE_DIFFERENCE() external view returns(uint128);
function developers() external view returns(address);
function deposit(uint256 amount) external returns (uint256);
function distributeRewards(uint256 totalRewards, uint256 ledgerBalance) external;
function distributeLosses(uint256 totalLosses, uint256 ledgerBalance) external;
function getStashAccounts() external view returns (bytes32[] memory);
function getLedgerAddresses() external view returns (address[] memory);
function ledgerStake(address ledger) external view returns (uint256);
function ledgerShares(address ledger) external view returns (uint256);
function avaliableForStake() external view returns (uint256);
function transferFromLedger(uint256 amount) external;
function transferToLedger(uint256 amount) external;
function flushStakes() external;
function findLedger(bytes32 stash) external view returns (address);
function AUTH_MANAGER() external returns(address);
function ORACLE_MASTER() external view returns (address);
function getPooledKSMByShares(uint256 sharesAmount) external view returns (uint256);
function getSharesByPooledKSM(uint256 amount) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
}