Contracts and scripts to enable inter-blockchain communication of tokens.
The settings
table stores general configuration data:
name current_chain_name;
// stores info about the token that needs to be issued
token_info token_info;
bool enabled;
// whether tokens should be issued or taken from the contract balance
bool do_issue;
uint64_t next_transfer_id = 0;
// duration after which transfers and reports expire can be evicted from RAM
eosio::microseconds expire_after = days(7);
// how many reporters need to report a transfer for it to be confirmed
uint8_t threshold;
It is initialized once using the init
action.
Further updates to the threshold
can be done using the update
function.
The fees
table stores all information related to fees:
asset total;
asset reserve;
time_point_sec last_distribution;
double fees_percentage = 0.002;
The fee percentage can be updated using the update
function.
Currently, fees can be distributed to the reporters every 30 days using a simple point system. Every report and execute of a transfer is one point - the fees for the reporters are distributed on a pro rata basis.
The transfers
table stores every transfer from users to this contract.
uint64_t id; // settings.next_transfer_id
checksum256 transaction_id;
name from_blockchain;
name to_blockchain;
name from_account;
name to_account;
asset quantity;
time_point_sec transaction_time;
time_point_sec expires_at; // secondary index
bool is_refund = false; // refunds are implemented as separate transfers
Note that the id
is not unique among all chains. A cross-chain unique id can be used by combining from_blockchain
with id
.
The reports
table stores reported transfers from another chain.
The transfer data is a plain copy of the original transfer table row on the original chain.
uint64_t id;
transfer transfer; // copy of original transfer
bool confirmed = false;
std::vector<name> confirmed_by;
bool executed = false;
bool failed = false;
std::vector<name> failed_by;
The reporters
table stores the active reporters:
name account;
uint64_t points = 0;
Reporters can be added and removed using the addreporter
and rmreporter
actions.
The reporter is a Nodejs app running on a server that scans all blockchans for events and handles IBC.
- Can be deployed on servers like any other NodeJS app.
- It's stateless and does not require any database.
- Requries Node.js
npm install
npm run build
# for production
npm start
# for testnets
npm run start-dev
The reporter requires environment variables to be set.
See .template.env
- this file can be copied to .env
and configured with the correct accounts and permissions.
# account name on EOS; permission used for reporting; private key for permission
EOS_IBC=maltareports;active;5JzSdC...
# ⚠️ Use your own endpoint here
EOS_ENDPOINT=https://api.eossweden.org:443
# same for WAX
WAX_ENDPOINT=https://chain.wax.io:443
WAX_IBC=maltareports;active;5JzSdC...
More documentation for the reporter script is available here
The contract and the reporters process cross-chain transfers the following way. As an example, consider a transfer from EOS to WAX.
User sends a transfer to the ibc contract.
Fees are subtracted from the quantity and the contract stores the adjusted transfer in its transfers
table with the following data:
// transfer
id; // from settings
transaction_id; // id of this transaction
from_blockchain; // "eos"
to_blockchain; // "wax"
from_account; // "eosaccount"
to_account; // "waxaccount"
quantity; // quantity - fees
transaction_time; // current time of transaction
expires_at; // current time + settings.expire_after
is_refund = false;
The reporters can use any EOSIO node of the EOS chain to read the tables of the contract:
- Fetches head block number and last irreversible block number
- Fetches non-expired transfers using secondary key on
transfers
table - Fetches non-expired reports on the supported opposing chains.
- Crosschecks transfer's target_blockchain and reports to see if transfer has already been reported by themself.
- If not, reports the transfer on the target blockchain using the
report(reporter, transfer)
action.
The contract on WAX stores the report along with the transfer data in the reports
table:
// reports
id;
transfer; // copy of original transfer
confirmed = false;
confirmed_by;
executed = false;
failed = false;
failed_by;
The contract on WAX receives several reports of same transfer by different reporters until the configured threshold is reached. The report (and the transfer) is then marked as confirmed.
// reports
id
confirmed: true
- Reporter fetches the
reports
table of thewaxibc
contract and checks if any report isconfirmed
but notexecuted
yet. - Reporter tries executing the transfer using the
exec(reporter, report_id)
which setsexecute=true
and sends inline transfer action to the target_account. - Assuming the execution succeeded, the report is marked as executed. (For the failure case, see scenario below.)
id
executed: true
There are two actions by the reporter that can fail - the report
and the exec
action.
The report
transaction is fully under the reporter's and ibc contract's control and therefore shouldn't continously fail. It could fail because of CPU issues / blockchain issues, but it will be retried in these cases.
This is the more interesting case as it could fail because the account does not exist on-chain or the account has a contract that rejects the transfer.
- When the reporter's
exec
transaction failed, they will follow up with aexecfailed(reporter, report_id)
transaction. - This adds the reporter to the
failed_by
field.
failed_by: [reporter_name] failed: true // gets locked if failed.executions.length >= threshold ```
- If the number of failed executions has reached the configured threshold, a reverse transfer is added to the
tranfers
table, essentialy requesting a cross-chain refund transfer (ignoring fees).
// new transfer added
id: new_id
from_blockchain: old_transfer.to_blockchain
to_blockchain: old_transfer.from_blockchain
from_account: old_transfer.from_blockchain.ibcContract
to_account: old_transfer.from_account
is_refund: true // to handle logic like no fees
This refund transfer is treated the same as any transfer from WAX -> EOS by the reporters.
The contracts and reporters are currently deployed on EOS and WAX to and implement a decentralized EOSDT (EOS) <> WEOSDT (WAX) bridge.
This software is MIT licensed.