diff --git a/README.md b/README.md index bcda1d7..4c6150b 100644 --- a/README.md +++ b/README.md @@ -60,12 +60,12 @@ function bindPort(string calldata portId, address moduleAddress) To comply with IBC protocol regulations, a channel cannot function until it is paired with a business module through a port. -## Send ICS20 Packet (WIP) +## Send ICS20 Packet (using ERC20) -In the previous migration step, a standard ICS20 transfer module has already been bound at port `port-0` by default. Run script `scripts/send_packet.js` to send a standard custom ICS20 packet: +In the previous migration step, a standard ICS20 transfer module has already been bound at port `transfer` by default. Run script `scripts/send_erc20_packet.js` to send a standard custom ICS20 packet: ```bash $ yarn send ``` -This is because an IBC packet cannot be sent by directly calling the method in `OwnableIBCHandler` contract. Instead, it should be sent by calling a method in the business module, and the handler contract will be invoked subsequently. \ No newline at end of file +This is because an IBC packet cannot be sent by directly calling the method in `OwnableIBCHandler` contract. Instead, it should be sent by calling a method in the business module, and the handler contract will be invoked subsequently. diff --git a/package.json b/package.json index d7620e8..dfb6e7d 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,7 @@ "scripts": { "compile": "truffle compile", "migrate": "truffle migrate --network axon", - "send": "truffle exec './scripts/send_packet.js' --network axon", - "query": "truffle exec './scripts/query_packet.js' --network axon" + "send": "truffle exec './scripts/send_erc20_packet_back.js' --network axon" }, "dependencies": { "@openzeppelin/contracts": "^4.9.3", @@ -17,4 +16,4 @@ "ganache": "^7.9.0", "truffle": "^5.11.1" } -} \ No newline at end of file +} diff --git a/scripts/common.js b/scripts/common.js deleted file mode 100644 index 71cbba0..0000000 --- a/scripts/common.js +++ /dev/null @@ -1,28 +0,0 @@ -const ethers = require("ethers"); - -const AXON_CLIENTS = { - "07-axon-0": { - handler: "0xf975A646FCa589Be9fc4E0C28ea426A75645fB1f", - mock_module: "0xAaC7D4A36DAb95955ef3c641c23F1fA46416CF71", - channel: "channel-0", - port: "port-0" - }, - "07-axon-1": { - handler: "0x7E27bCbe2F0eDdA3E0AA12492950a6B8703b00FB", - mock_module: "0x9015957A2210BB8B10e27d8BBEEF8d9498f123eF", - channel: "channel-0", - port: "port-0" - }, -} - -function generate_ibc_handler(address, artifacts) { - const abi = new ethers.utils.Interface(artifacts.require("OwnableIBCHandler").abi); - const provider = new ethers.providers.WebSocketProvider(process.env.AXON_WS_RPC_URL); - const handler = new ethers.Contract(address, abi, provider); - return handler; -} - -module.exports = { - AXON_CLIENTS, - generate_ibc_handler -}; diff --git a/scripts/query_packet.js b/scripts/query_packet.js deleted file mode 100644 index 75c8641..0000000 --- a/scripts/query_packet.js +++ /dev/null @@ -1,19 +0,0 @@ -const { AXON_CLIENTS, generate_ibc_handler } = require("./common"); - -async function query_packet_commitment_sequences(clientId) { - const client = AXON_CLIENTS[clientId]; - const handler = generate_ibc_handler(client.handler, artifacts); - const next_sequence = await handler.getNextSequenceSend(client.port, client.channel); - console.log("max sequence:", next_sequence.toString()); - for (let i = 0; i < parseInt(next_sequence.toString()); i++) { - const result = await handler.getHashedPacketCommitment(client.port, client.channel, i); - console.log("result on", i, result); - } - const sequences = await handler.getHashedPacketCommitmentSequences(client.port, client.channel); - console.log("packet sequences:", sequences); -} - -module.exports = async (callback) => { - await query_packet_commitment_sequences("07-axon-0").catch(e => callback(e.toString())); - callback(); -} diff --git a/scripts/send_erc20_packet_back.js b/scripts/send_erc20_packet_back.js new file mode 100644 index 0000000..d95dbbe --- /dev/null +++ b/scripts/send_erc20_packet_back.js @@ -0,0 +1,59 @@ +// This is for emitting SendPacket event directly from Axon to initial the IBC communication + +async function main() { + // First provider account. + const [sender] = await web3.eth.getAccounts(); + // Receiver should be CKB address, which is first 20 bytes of hash of sender's lock_script + const receiver = process.env.RECEIVER; + console.log("Sender and receiver:", sender, receiver); + + const ICS20TransferERC20 = await artifacts.require("ICS20TransferERC20"); + const IERC20 = await artifacts.require("IERC20"); + + const transfer = await ICS20TransferERC20.at( + process.env.TRANSFER_CONTRACT_ADDRESS + ); + + const port = "transfer"; + const channel = process.env.CHANNEL; + + const denom = `${port}/${channel}/${process.env.DENOM}`; + + // Check token associated with the denom that is created before + let tokenAddr = await transfer.denomTokenContract(denom); + if (tokenAddr == "0x0000000000000000000000000000000000000000") { + // const ERC20PresetMinterPauser = await artifacts.require("ERC20PresetMinterPauser"); + // const token_name = process.env.TOKEN_NAME; + // const token_symbol = process.env.TOKEN_SIMBOL; + // const token = await ERC20PresetMinterPauser.new(token_name, token_symbol); + // await token.grantRole(await token.MINTER_ROLE(), transfer.address); + // await token.mint(sender, 999); + // await transfer.setDenomTokenContract(denom, token.address); + // tokenAddr = token.address; + console.error("Axon cannot be source zone now, so the transferred token should already exist on CKB"); + return; + } + + // Check balance. + const amount = process.env.AMOUNT; + const token = await IERC20.at(tokenAddr); + if ((await token.balanceOf(receiver)) >= amount) { + throw "balance should at least be " + amount; + } + + // Send packet: ERC20 approve and ICS20 sendTransfer. + await token.approve(transfer.address, amount, { + from: sender, + }); + let result = await transfer.sendTransfer(denom, amount, receiver, port, channel, 0, { + from: sender, + }); + console.log(`Successfully send ${amount} token to ${receiver} with denom ${denom}: ${result}`); +} + +module.exports = (callback) => { + main().then(callback).catch(e => { + console.log("Error:", e.message, e); + callback(); + }); +}; diff --git a/scripts/send_packet.js b/scripts/send_packet.js deleted file mode 100644 index f4facf4..0000000 --- a/scripts/send_packet.js +++ /dev/null @@ -1,35 +0,0 @@ -const { AXON_CLIENTS, generate_ibc_handler } = require("./common"); - -async function send_packet(from_clientId, to_clientId) { - console.log("send packet from", from_clientId, "to", to_clientId); - - const source = AXON_CLIENTS[from_clientId]; - const target = AXON_CLIENTS[to_clientId]; - const module = await artifacts.require("MockTransfer").at(source.mock_module); - - // build and send packet - const denom = "AT"; - const amount = 100; - const timeoutHeight = 0; - const result = await module.sendTransfer(denom, amount, target.mock_module, source.port, source.channel, timeoutHeight); - console.log("send packet result:", result); -} - -async function listen_send_packet_event(clientId, callback) { - const source = AXON_CLIENTS[clientId]; - const handler = generate_ibc_handler(source.handler, artifacts); - handler.on("SendPacket", (packet) => { - console.log("receive packet event:", packet); - callback(); - }).on("error", error => { - callback(error); - }) -} - -module.exports = async (callback) => { - const source = "07-axon-0"; - const target = "07-axon-1"; - - await listen_send_packet_event(source, callback).catch(e => callback(e.toString())); - await send_packet(source, target).catch(e => callback(e.toString())); -}