Skip to content

Commit bfc441f

Browse files
FidelVegitbook-bot
authored andcommitted
GITBOOK-231: adding xcall examples
1 parent 33f4e3e commit bfc441f

10 files changed

+290
-42
lines changed

SUMMARY.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@
2929
* [Guides](build-with-xcall/guides/README.md)
3030
* [Sending a message](build-with-xcall/guides/sending-a-message.md)
3131
* [Receiving a message](build-with-xcall/guides/receiving-a-message.md)
32-
* [Error Handling](build-with-xcall/guides/error-handling.md)
33-
* [Explanations](build-with-xcall/explanations/README.md)
34-
* [Message lifecycle](build-with-xcall/explanations/message-lifecycle.md)
35-
* [Fees](build-with-xcall/explanations/fees.md)
32+
* [Error Handling](build-with-xcall/troubleshooting.md)
33+
* [Explanations](build-with-xcall/resources/README.md)
34+
* [Message lifecycle](build-with-xcall/resources/message-lifecycle.md)
35+
* [Fees](build-with-xcall/guides/handling-fees.md)
3636

3737
## Concepts
3838

build-with-xcall/explanations/fees.md

-28
This file was deleted.

build-with-xcall/guides/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ description: Here are a set of guides for the basics.
66

77
* [Sending a message](../quickstart/sending-a-message-with-xcall.md)
88
* [Receiving a message](receiving-a-message.md)
9-
* [Error Handling](error-handling.md)
9+
* [Error Handling](../troubleshooting.md)
+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Fees
2+
3+
When you're making a cross-chain call using xCall, there's a fee that covers the costs of sending the message between different blockchains. `sendCallMessage` is payable, so the fee should be included in the transaction. You can get the fee by calling `getFee`.
4+
5+
`getFee(String _net, boolean _rollback)` returns the total fee (relay + protocol) for sending a message to the specified network. If a rollback data is provided, the `_rollback` param should be set as true because there is an additional backward direction fee (from destination back to source) if rollback is used.
6+
7+
\
8+
This fee is split into two parts:
9+
10+
**Relay Fee**: This fee is for the service that actually sends your message from one blockchain to another. 
11+
12+
**Protocol Fee**: This is the fee for using the cross-chain communication protocol underlying xCall.
13+
14+
### Relay Fee
15+
16+
* If a relay successfully delivers a cross-chain message, it can claim a reward. The first relay to successfully deliver a cross-chain message gets the reward.
17+
* The reward claim can be made using the `claimReward` function, which requires the network address of the reward (`_network`) and the address of the receiver (`_receiver`).
18+
* The accrued reward for each relay can be checked using the `getReward` function.
19+
20+
### Protocol Fee
21+
22+
* The protocol fee is set on the `xCall` contract by an admin wallet.
23+
24+
### Burning Fees and Impact to ICX Tokenomics
25+
26+
Native fees generated by protocol fees and relays managed by the ICON Foundation are swapped to native ICX and burned.
27+
28+
### Example
29+
30+
The process of fetching the cross chain transaction fee is done by making a readonly call to the `getFee(String _net, Boolean _rollback)` method of the xCall contract in the origin chain.
31+
32+
The following code sample showcase how to get the fee of a crosschain message originating on the Berlin testnet on ICON and the destination chain being the Sepolia testnet on Ethereum.
33+
34+
```javascript
35+
const IconService = require("icon-sdk-js");
36+
37+
const { IconBuilder, HttpProvider } = IconService.default;
38+
39+
const { CallBuilder } = IconBuilder;
40+
const ICON_RPC_URL = "https://berlin.net.solidwallet.io/api/v3/icon_dex";
41+
const XCALL_PRIMARY = "cxf4958b242a264fc11d7d8d95f79035e35b21c1bb";
42+
const NETWORK_LABEL_SECONDARY = "0xaa36a7.eth2";
43+
44+
const HTTP_PROVIDER = new HttpProvider(ICON_RPC_URL);
45+
const ICON_SERVICE = new IconService.default(HTTP_PROVIDER);
46+
47+
/*
48+
* getFee - calls the getFee method of the xcall contract
49+
* @param {boolean} useRollback - whether to use rollback
50+
* @returns {String} - the fee as a hex value
51+
* @throws {Error} - if there is an error getting the fee
52+
*/
53+
async function getFee(useRollback = false) {
54+
try {
55+
const params = {
56+
_net: NETWORK_LABEL_SECONDARY,
57+
_rollback: useRollback ? "0x1" : "0x0"
58+
};
59+
60+
const txObj = new CallBuilder()
61+
.to(XCALL_PRIMARY)
62+
.method("getFee")
63+
.params(params)
64+
.build();
65+
66+
return await ICON_SERVICE.call(txObj).execute();
67+
} catch (e) {
68+
console.log("error getting fee", e);
69+
throw new Error("Error getting fee");
70+
}
71+
}
72+
73+
async function main() {
74+
const fee = await getFee();
75+
console.log("fee", fee);
76+
}
77+
78+
main();
79+
```

build-with-xcall/guides/receiving-a-message.md

+199-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ When the EOA calls `executeCall` method, the `xCall` contract invokes the follow
5454
void handleCallMessage(String _from, byte[] _data);
5555
```
5656

57-
**I**f execution fails on the destination chain, `handleCallMessage` may also need to be defined in the source chain Smart Contract A in order to handle the [executeRollback](https://github.com/icon-project/IIPs/blob/master/IIPS/iip-52.md#executerollback) invocation properly. For more information, see [Troubleshooting](error-handling.md).
57+
**I**f execution fails on the destination chain, `handleCallMessage` may also need to be defined in the source chain Smart Contract A in order to handle the [executeRollback](https://github.com/icon-project/IIPs/blob/master/IIPS/iip-52.md#executerollback) invocation properly. For more information, see [Troubleshooting](../troubleshooting.md).
5858

5959
#### CallExecuted Event
6060

@@ -75,3 +75,201 @@ void CallExecuted(BigInteger _reqId, int _code, String _msg);
7575

7676
### Example
7777

78+
Waiting for the xCall related events is the same process as waiting for any other event in a JVM (ICON) chain or EVM chain.
79+
80+
The following is an example of waiting for the `CallMessageSent` event on a cross-chain message originating on ICON:
81+
82+
```javascript
83+
const IconService = require("icon-sdk-js");
84+
85+
const { HttpProvider } = IconService.default;
86+
87+
// RPC node for the ICON network
88+
const ICON_RPC_URL = "https://berlin.net.solidwallet.io/api/v3/icon_dex";
89+
const HTTP_PROVIDER = new HttpProvider(ICON_RPC_URL);
90+
const ICON_SERVICE = new IconService.default(HTTP_PROVIDER);
91+
92+
/*
93+
* filterEvent - filters the event logs
94+
* @param {object} eventlogs - the event logs
95+
* @param {string} sig - the signature of the event
96+
* @param {string} address - the address of the contract
97+
* @returns {object} - the filtered event logs
98+
* @throws {Error} - if there is an error filtering the event logs
99+
*/
100+
function filterEvent(eventlogs, sig, address) {
101+
return eventlogs.filter(event => {
102+
return (
103+
event.indexed &&
104+
event.indexed[0] === sig &&
105+
(!address || address === event.scoreAddress)
106+
);
107+
});
108+
}
109+
110+
/*
111+
* parseCallMessageSentEvent - parses the CallMessageSent event logs
112+
* @param {object} event - the event logs
113+
* @returns {object} - the parsed event logs
114+
* @throws {Error} - if there is an error parsing the event logs
115+
*/
116+
function parseCallMessageSentEvent(event) {
117+
const indexed = event[0].indexed || [];
118+
const data = event[0].data || [];
119+
return {
120+
_from: indexed[1],
121+
_to: indexed[2],
122+
_sn: indexed[3],
123+
_nsn: data[0]
124+
};
125+
}
126+
127+
async function main() {
128+
// hash of the cross chain transaction
129+
const txHash = "0x123..";
130+
// signature for the event
131+
const callMessageSentSignature = "CallMessageSent(Address,str,int,int)";
132+
// address of the xcall contract
133+
const xCallContractAddress = "cx123..";
134+
135+
// get the transaction result
136+
const txResult = await ICON_SERVICE.getTransactionResult(txHash).execute();
137+
138+
// filter the CallMessageSent event logs
139+
const filteredEvent = filterEvent(
140+
txResult.eventLogs,
141+
callMessageSentSignature,
142+
xCallContractAddress
143+
);
144+
145+
// parsing the CallMessageSent event logs
146+
const parsedEvent = parseCallMessageSentEvent(filteredEvent);
147+
console.log("parsedEvent", parsedEvent);
148+
}
149+
150+
main();
151+
```
152+
153+
The following code sample showcase how to wait and fetch the `CallMessage` event of the destination chain in a cross chain message scenario where the destination chain is an EVM chain.
154+
155+
```javascript
156+
const fs = require("fs");
157+
const { ethers } = require("ethers");
158+
159+
// RPC of the node in the destination chain
160+
const EVM_RPC_URL =
161+
"https://sepolia.infura.io/v3/ffbf8ebe228f4758ae82e175640275e0";
162+
// Private key of the wallet in the destination chain
163+
const WALLET_PK = "0x0123...";
164+
// btp network label of the origin chain, in this example Berlin Testnet from ICON
165+
const NETWORK_LABEL_ORIGIN = "0x7.icon";
166+
// Address of the dApp contract in the destination chain
167+
const EVM_DAPP_ADDRESS = "0x0123...";
168+
// Address of the dApp contract in the origin chain
169+
const ICON_DAPP_ADDRESS = "cx123...";
170+
// path to the xcall contract abi
171+
const XCALL_ABI_PATH = "./xcallAbi.json";
172+
// address of the xcall contract in the destination chain
173+
const XCALL_ADDRESS_DESTINATION = "0x0123...";
174+
175+
/*
176+
* sleep - sleeps for the specified amount of time
177+
* @param {number} ms - the amount of time to sleep in milliseconds
178+
* @returns {Promise} - the promise to sleep
179+
*/
180+
async function sleep(ms) {
181+
return new Promise(resolve => setTimeout(resolve, ms));
182+
}
183+
184+
/*
185+
* filterCallMessageEventEvm - filters the CallMessage event logs
186+
* @param {string} iconDappAddress - the address of the ICON dapp
187+
* @param {string} evmDappAddress - the address of the EVM dapp
188+
* @param {string} sn - the serial number cross chain transaction
189+
* @returns {object} - the filtered event logs
190+
* @throws {Error} - if there is an error filtering the event logs
191+
*/
192+
function filterCallMessageEventEvm(iconDappAddress, evmDappAddress, sn) {
193+
const btpAddressSource = `btp://${NETWORK_LABEL_ORIGIN}/${iconDappAddress}`;
194+
const xcallContract = getXcallContractObject();
195+
const callMessageFilters = xcallContract.filters.CallMessage(
196+
btpAddressSource,
197+
evmDappAddress,
198+
sn
199+
);
200+
return callMessageFilters;
201+
}
202+
203+
/*
204+
* waitEventEVM - waits for the event to be emitted
205+
* @param {object} filterCM - the filter for the event
206+
* @returns {object} - the event logs
207+
* @throws {Error} - if there is an error waiting for the event
208+
*/
209+
async function waitEventEVM(filterCM) {
210+
const contract = getXcallContractObject();
211+
let height = await contract.provider.getBlockNumber();
212+
let next = height + 1;
213+
console.log("block height", height);
214+
while (true) {
215+
if (height == next) {
216+
await sleep(1000);
217+
next = (await contract.provider.getBlockNumber()) + 1;
218+
continue;
219+
}
220+
for (; height < next; height++) {
221+
console.log(`waitEventEvmChain: ${height} -> ${next}`);
222+
const events = await contract.queryFilter(filterCM, height);
223+
if (events.length > 0) {
224+
return events;
225+
}
226+
}
227+
}
228+
}
229+
230+
/*
231+
* getXcallContractObject - gets the xcall contract object
232+
* @returns {object} - the xcall contract object
233+
* @throws {Error} - if there is an error getting the xcall contract object
234+
*/
235+
function getXcallContractObject() {
236+
try {
237+
const contract = JSON.parse(fs.readFileSync(XCALL_ABI_PATH));
238+
const abi = contract.abi;
239+
const provider = new ethers.providers.JsonRpcProvider(EVM_RPC_URL);
240+
const signer = new ethers.Wallet(WALLET_PK, provider);
241+
const contractObject = new ethers.Contract(
242+
XCALL_ADDRESS_DESTINATION,
243+
abi,
244+
signer
245+
);
246+
return contractObject;
247+
} catch (e) {
248+
console.log(e);
249+
throw new Error("Error getting Xcall contract");
250+
}
251+
}
252+
253+
async function main() {
254+
// Serial number of the crosschain message
255+
const crossChainMessageSN = "0x1";
256+
257+
// filter call message event evm
258+
const callMessageEventEvmFilters = filterCallMessageEventEvm(
259+
ICON_DAPP_ADDRESS,
260+
EVM_DAPP_ADDRESS,
261+
crossChainMessageSN
262+
);
263+
console.log(
264+
"\n# call message event evm filters:",
265+
callMessageEventEvmFilters
266+
);
267+
268+
// wait for call message event evm
269+
const eventsEvm = await waitEventEVM(callMessageEventEvmFilters);
270+
console.log("\n# events params:");
271+
console.log(JSON.stringify(eventsEvm[0].args));
272+
}
273+
274+
main();
275+
```

build-with-xcall/guides/sending-a-message.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Sending a call message requires your Smart Contract to call the **pre-deployed** xCall Smart Contract's `sendCallMessage` method.
44

5-
More detailed explanation can be found [here](https://github.com/icon-project/IIPs/blob/master/IIPS/iip-52.md#sendcallmessage). Rollback is covered in the [Troubleshooting ](error-handling.md)section.
5+
More detailed explanation can be found [here](https://github.com/icon-project/IIPs/blob/master/IIPS/iip-52.md#sendcallmessage). Rollback is covered in the [Troubleshooting ](../troubleshooting.md)section.
66

77
#### JVM
88

build-with-xcall/explanations/README.md build-with-xcall/resources/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ description: Here are articles to help you learn more about xCall.
77
#### Articles
88

99
* [Message Lifecycle](message-lifecycle.md)
10-
* [Fees](fees.md)
10+
* [Fees](../guides/handling-fees.md)

build-with-xcall/explanations/message-lifecycle.md build-with-xcall/resources/message-lifecycle.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ The simplified lifecycle of an xCall message, only including what is relevant to
99
3. EOA then respond to this event by invoking the `executeCall` method in the xCall Smart Contract on the destination chain.
1010
4. The execution of this method triggers the target dApp's smart contract method.
1111
5. If the call executes successfully, a `CallExecutedEvent` is emitted.
12-
6. If an error occurs during execution, and rollback data was included in the original call, an error handling process is initiated, sending a `ResponseMessage` Event back to the source chain for state rollback operations. For more information, see [Troubleshooting](../guides/error-handling.md).
12+
6. If an error occurs during execution, and rollback data was included in the original call, an error handling process is initiated, sending a `ResponseMessage` Event back to the source chain for state rollback operations. For more information, see [Troubleshooting](../troubleshooting.md).
1313

14-
In this process, the dApp developer handles [initiating the cross-chain call](../quickstart/sending-a-message-with-xcall.md), [responding to events](../guides/receiving-a-message.md), and [errors](../guides/error-handling.md).
14+
In this process, the dApp developer handles [initiating the cross-chain call](../quickstart/sending-a-message-with-xcall.md), [responding to events](../guides/receiving-a-message.md), and [errors](../troubleshooting.md).
1515

16-
`sendCallMessage` is a `Payable` method and requires a fee. For more information, see [Handling Fees](fees.md).
16+
`sendCallMessage` is a `Payable` method and requires a fee. For more information, see [Handling Fees](../guides/handling-fees.md).
1717

1818
### Full message lifecycle
1919

Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Error handling
1+
# Error Handling
22

33
If an error occurs during the execution of the call request on the destination chain, and a rollback parameter was provided in the initial `sendCallMessage` method, the xCall contract on the source chain emits a `RollbackMessage` event. This event is triggered when an error occurs on the destination chain and a rollback operation is needed. The `RollbackMessage` event includes the serial number of the original request that needs to be rolled back.
44

@@ -8,4 +8,3 @@ The destination chain does not pass back rollback instructions. These are define
88

99
After the rollback operation is executed, the `RollbackExecuted` event is emitted by the xCall contract. This event notifies that the rollback has been executed and includes the serial number for the rollback, the execution result code, and a result message if any.
1010

11-
### Example

xcall/getting-started.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ If you run into issues, join the [ICON Discord](https://discord.gg/8ZG7hCsWND) t
2020

2121
### Learn More
2222

23-
For general information and concepts, proceed to [Explanations](../build-with-xcall/explanations/).
23+
For general information and concepts, proceed to [Explanations](../build-with-xcall/resources/).

0 commit comments

Comments
 (0)