⏎ LIP_4
Interchain Registrar
Goal of this proposal is to implement a multi-directional peg-contract enabling token and data transfers between uncapped number of decentralized networks.
Pegging is a mechanism of locking
or otherwise temporarily or permanently immobilizing fungible or non fungible tokens on the chain A
in order to issue them on the chain B
or vice versa. Locking
of the asset is usually achieved though a smart-contract or a dedicated state-machine module deployed on the chain A
. Validators of the chain B
collectively have the ability to observe the state and fully control the locking contract/module. Validators of the chain B
have further ability to issue 1:1
assets representing locked tokens to the address designated by the user making a deposit.
Peg-contract/s must have the ability to register its owners/controller accounts
that is accounts that have the ability to collectively unlock tokens deposited by the users. XARC-1
(CrossChain Alliance Request for Comments 1) is an MVP implementation and should be the simplest, most light weight type of the controller registrar thus only consist of the minimum instruction set.
Controllers Registrar can be implemented as a part of a peg-contract or as a separate, standalone smart-contract. It's goal is to only mark/designate accounts capable of controlling peg-contact, for example a as a curated list of accounts:
<address-1>
<address-2>
...
<address-N>
NOTE: A non-transferable token can be used to mark designated accounts if preferred in the implementation
Controllers Registrar should contain information in regards to how many accounts M
out of all accounts N
are required to apply changes to the account list of the Controllers Registrar
contract, so that the curation of its content is possible after the initial setup and can only be executed though a proposal passed by a minimum defined treshold
of accounts. (e.g. via a dedicated proposal)
Due to limitation of the transaction sizes (e.g. to 48kB on ethereum) it must be possible to setup the Controllers Registrar contract with just single account so that accounts can be added to the list is sets and only when the initial setup is completed the contract would be activated.
{
"active": <boolean>, // defines if initial setup was completed
"threshold": <integer>, // the M count from the M/N parameter
"count": <integer>, // the N count, always equal to number of accounts
"accounts": [ // list of accounts taking part in the consensus
"<account-1>",
"<account-2>",
...
"<account-N>"
],
"owner": <address> // initial deployer of the contract
}
setActivate
- Defines if initial setup was completed, defaultfalse
. Once set totrue
it can't be set back tofalse
.
Example: setActivate()
setChange
- Defines threshold and list of accounts to be added and/or removed to/from the list, repeating accounts can be ignored. Threshold defines minimum number of accounts required to manage the accounts list. For the safety reasons threshold value can never be lower thenceiling(count / 2) + 1
. If any of the values is not set then it should remain unmodified. All values should be optional. This function can only be used by the owner when the contract is NOT active.
Example: setAccounts(add: ["0x123...456","0x654..321"], remove: ["0x987...765"], treshold: 154)
proposeChange
- Proposal to add accounts to the account list, remove accounts or change treshold, proposal can be raised by any account in theacounts
list. This function can only be used when the contract is active. Proposal passes and changes are applied only ifapproveProposal
tx was submitted by no less thentreshold
number of accounts. If proposal passes then changes are applied and all proposals older then the one that passed should be cancelled/rejected. If any of the values is not set then it should remain unmodified. All values should be optional.
Example: proposeChange(add: ["0x123...456","0x654..321"], remove: ["0x987...765"], treshold: 156)
approveProposal
- Vote on change proposal can only be used by the accounts in the list ofaccounts
. This function can only be used when the contract is active.
Example: approveProposal(5)
Peg-contract/s must have the ability to register foreign chain-id's to which and from which tokens can be transferred. When users make a cross-chain transfers a destination chain information can then be included in those tx's and identified by the contract. XARC-2
(CrossChain Alliance Request for Comments 2) is an MVP implementation and should be the simplest, most light weight type of the chain registrar thus only consist of the minimum instruction set.
Chains Registrar can be implemented as a part of a peg-contract or as a separate, standalone smart-contract. It's goal is to only mark/designate which sets of accounts present in the Controller Registrar
can collectively control locking and unlocking assets within the Peg-contract and via which Bank Controller
contract those operations can be achieved. Each Controller Registrar
and Bank Registrar
contract address must be associated with the chain-id
. The XARC-2
can be treated as a routing table or an analogy to the DNS registrar where human readable names can be associated with the corresponding IP address.
Only one chain-id
should be associated with one XARC-1
and one XARC-3
contract and only the owner of those contracts can create the initial XARC-2
record.
{
"registrar": [
{
"chain-id": "<string>", // 32 Bytes max (256 bits)
"controller": "<address>", // must be a valid XARC-1 contract address
"bank": "<address>", // must be a valid XARC-3 contract address
}, { ... }, ...
]
}
registerChain
- DefinesXARC-1, XARC-3 contract
andchain-id
to be registered. Tx can only be submitted by theXARC-1 & XARC-3
owner/deployer when theXARC-1
andXARC-3
is NOT active. The chain-id can never be changed after registration is finalized.
Example: registerChain(chain_id: "kira-1", controller: "0xADDRESS...XARC1", bank: "0xADDRESS...XARC3")
proposeChange
- Proposal to changeXARC-1
and/orXARC-3
contracts, proposal can be raised by any account in theXARC-1 accounts
list. This function can only be used when theXARC-1
contract is active. Proposal passes and changes are applied only ifapproveProposal
tx was submitted by no less thenXARC-1 treshold
number of accounts. If proposal passes then changes are applied and all proposals associated with the chain-id older then the one that passed should be cancelled/rejected.
Example: proposeChange(chain_id: "kira-1", controller:"0xNEW...XARC1", bank: "0xNEW...XARC3")
approveProposal
- Vote on change proposal can only be used by the accounts in the list ofaccounts
. This function can only be used when the contract is active.
Example: approveProposal(123)
Peg-contract/s must have the ability to receive, transfer and issue cross-chain assets. When users make a cross-chain transfer to the peg-contract/s (deposit) on the source chain the tokens should be locked within the Banking Registrar. When users make a cross-chain transfer out of the peg-contract (withdraw) on the destination chain the tokens should be unlocked or issued by the collective of accounts controlling the Bank Registrar. XARC-3
(CrossChain Alliance Request for Comments 3) is an MVP implementation and should be the simplest, most light weight type of the bank registrar thus only consist of the minimum instruction set.
Bank Registrar can be implemented as a part of a peg-contract or as a separate, standalone smart-contract. It's goal is to only lock/unlock or issue tokens as commanded by the set of accounts present in the corresponding Controller Registrar
. Each Bank Registrar
contract address must be associated with the chain-id
and the corresponding controller contract.
Only one chain-id and one XARC-1
contract should be associated with one XARC-3
contract and only the owner of the XARC-1
contract can create the initial XARC-3
record.
Bank Registrar contract should consist of the account list that is depositing or withdrawing assets. Deposits and withdraws can be either accepted or rejected though proposal process. Only deposits older then the minimum confirmations
time can be included in the proposal. If proposal passes the proposer receives (proposer_reward*100) %
of all deposit or withdraw fees while all XARC-1
accounts voting on the proposal equally split between each other ((1 - proposer_reward)*100) %
.
Withdraw and deposits can have following status codes:
0
- Pending1
- Accepted2
- Rejected
Token transfers freeze functionality should be implemented to enable transition to the new bank contracts in the future.
Bank registrar XARC-3
requires functionality that would allow it issuance of pegged assets. There exist at least three methods to enable that functionality:
- Embedding functionality to the
XARC-3
that would enable deployment of a modified ERC-20, ERC-721, ... & other smart contracts that can be fully managed by theXARC-1
controller accounts. - Embedding multi-token smartcontract standard such as ERC-1155 then enable
XARC-1
controller accounts management over its functions. - Deployment of a token contract, registration on the
XARC-3
and depositing 100% of its supply to the Bank Registrar from where the assets can be controlled by theXARC-1
controller accounts.
NOTE: It is expected that in Q4 2021 Metamask will fully support ERC-1155 making it a new NFT standard thus option 2 appears to be the cheapest, most lightweight solution.
The simplest implementation by far is to deploy a fixed-supply contract with maximum possible supply and deposit 100% of all tokens into the XARC-3
while giving XARC-1
accounts full control over the assets. To achieve that a new donate
function should be created that will deposit assets directly to the XARC-3
but will not create a deposit
index that XARC-1
controllers would have to vote on to accept as assets would NOT be credited to any account on the destination chain.
{
"registrar": "<address>", // must be a valid XARC-2 contract address
"deposit-fee": <integer>, // minimum fee that must be paid to deposit
"withdraw-fee": <integer>, // minimum fee that must be paid to withdraw
"proposer-reward": <decimal>, // reward for proposing withdraws/deposits
"confirmations": <integer>, // minimum number of confirmations required
"freeze": {
"deposits": <boolean> // enable/disable deposits
"withdraws": <boolean> // enable/disable withdraws
"donations": <boolean> // enable/disable donations
},
"balances": [
{
"address": "<address>", // account address
"deposits": [ { // assets to be accepted for deposit
"token": "<address>", // token deposited
"amount": <integer>, // amount deposited
"index": <integer>, // deposit identifier
"fee": <integer>, // fee paid by the user
"status": <integer> // deposit status
}, { ... }, ... ],
"withdraws": [ { // pending withdraws to claim
"token": "<address>", // token that can be withdrawn
"amount": <integer>, // amount that can be withdrawn
"index": <integer>, // withdraw identifier
"fee": <integer>, // fee paid by the user
"status": <integer> // withdraw status
}, { ... }, ... ] },
{ ... }, ...
],
"owner": <address> // initial deployer of the contract
}
setActivate
- Defines if initial setup was completed, defaultfalse
. Once set totrue
it can't be set back tofalse
.
Example: setActivate()
setChange
- Defines cross-chain registrar address, fees, proposer rewards and token transfers freeze properties. If any of the values is not set then it should remain unmodified. All values should be optional. This function can only be used by the owner when the contract is NOT active.
Example: setAccounts(registrar: "0xXARC2..ADDR", deposit_fee: 0, withdraw_fee: 123456, proposer_reward: 0.1)
proposeChange
- Proposal to change registrar, deposit/withdraw fees, fees, proposer rewards and change token freeze properties. Proposal passes and changes are applied only ifapproveProposal
tx was submitted by no less thenXARC-1 treshold
number of accounts. If proposal passes then changes are applied and all proposals older then the one that passed should be cancelled/rejected.
Example: proposeChange(registrar: "0xXARC2..ADDR", deposit_fee: 999, withdraw_fee: 321, proposer_reward: 0.1, freeze_withdraws: true, freeze_deposits: false, freeze_donations: false)
proposeDeposits
- Proposal to accept and/or reject deposits. Can only be raised for assets deposited atcurrent_block_heigh - confirmations
. If passed records are cleared to save space. This proposal can be raised by any account as perXARC-1
, proposer receivesproposer-reward %
of all deposit fees. Remaining fees are split between all who vote on accepting proposal. Proposal must have at least one record present and all deposit proposals older then the accepted one become automatically rejected.
Example: processDeposits(accept: [1,2,4,5], reject: [3,6])
proposeWithdraws
- Proposal to accept and/or reject withdraws. This proposal can be raised by any account as perXARC-1
, proposer receivesproposer-reward %
of all withdraw fees. Remaining fees are split between all who vote on accepting proposal. Proposal must have at least one record present and all withdraw proposals older then the accepted one become automatically rejected.
Example: processDeposits(accept: [1,2,4,5], reject: [3,6])
approveProposal
- Vote on change proposal can only be used by the accounts in the list ofaccounts
as perXARC-1
. This function can only be used when the contract is active.
Example: approveProposal(123)
deposit
- Deposit transaction can be made by anu user and requires a minimumdeposit-fee
to be included. Deposits should only be possible ifdeposits-freeze
flag is det to false.
Example: deposit(amount: 1000, token: "0xCONTRACT...ADDR", fee: 1234)
withdraw
- Withdraw transaction can be made by any user and requires a minimumwithdraw-fee
to be included. Withdraws should only be possible ifwithdraws-freeze
flag is det to false.
Example: withdraw(amount: 1000, token: "0xCONTRACT...ADDR", fee: 1234)
claim
- Claim transaction can be executed afterwithdraw
status is changed toaccepted
.
Example: claim()
refund
- Refund transaction can be executed afterdeposit
status changes torejected
or if transaction is not present in any of the active deposit proposals. If refund is called funds should be returned to the user.
Example: refund()
donate
- Transfers assets to the contract without need for accepting deposit. No tokens would be issued on the destination chain in such case. This action can NOT be refunded. There should be no deposit fees in case of token donations. Donations should only be possible ifdonations-freeze
flag is det to false.
Example: donate(amount: 1000, token: "0xCONTRACT...ADDR")