Skip to content

Commit d2b150a

Browse files
nptycanhtrinh
andauthored
[IMP-4] Add GMP Express Example (axelarnetwork#87)
* feat: add call-contract-with-token-express * feat: implement `expressCallWithToken` * chore: update readme * Kiryl changes (axelarnetwork#88) * chore: adding Kiryl changes * chore: delete unused file * chore: update deploy method (axelarnetwork#91) * chore: update deploy method * chore: update gasService address * chore: update abi * chore: update axelar-gmp-sdk-solidity to 3.1.1 * chore: update payload --------- Co-authored-by: npty <[email protected]> * chore: update sdk to 3.2.0 * chore: remove expressCallWithToken * chore: update axelar-local-dev version * chore: refactor deployment step * chore: delete testnet.jsopn * chore: use local testnet if exist * chore: fix merge conflict * chore: update axelar-local-dev and clean hardhat in build command * chore: fix getGasPrice error * chore: fix bug in execute script and remove unrelavant output * chore: prevent listenForGMPEvent function to receive past event * chore: fix bugs in utils.js * chore: pass chains arguments to getChains function * chore: update axelarjs-sdk version * chore: use whitelisted address only for GMPE on testnet * chore: fix import path for IAxelarExecutable * chore: remove log * chore: fix contract check * chore: delete forecallable example because we have gmp express * chore: delete forecall in test * chore: delete non-exist example link in README.md * chore: add gmp express example in the evm readme * chore: update example command for express * chore: fix nft-linker deployment failed * chore: update whitelisted address for testnet * chore: add npm install in readme * chore: add compile smart contract step in readme * chore: print usdc balance * chore: check if testnet.json exists * chore: remove execute function --------- Co-authored-by: Canh Trinh <[email protected]>
1 parent d3e693b commit d2b150a

File tree

22 files changed

+427
-377
lines changed

22 files changed

+427
-377
lines changed

README.md

+13-1
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,24 @@ Install [nodejs](https://nodejs.org/en/download/). Run `node -v` to check your i
1212

1313
Support Node.js version 16.x and 18.x
1414

15-
Clone this repo:
15+
1. Clone this repo:
1616

1717
```bash
1818
git clone https://github.com/axelarnetwork/axelar-examples.git
1919
```
2020

21+
2. Install dependencies:
22+
23+
```bash
24+
npm install
25+
```
26+
27+
3. Compile smart contracts:
28+
29+
```bash
30+
npm run build
31+
```
32+
2133
## Set environment variables
2234

2335
You can get started quickly with a random local key and `.env` file by running

examples-web/contracts/nft-linker/Proxy.sol

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
pragma solidity 0.8.9;
44

5-
import {Proxy} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradable/Proxy.sol";
5+
import {BaseProxy} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradable/BaseProxy.sol";
66

7-
contract ExampleProxy is Proxy {
7+
contract ExampleProxy is BaseProxy {
88
function contractId()
99
internal
1010
pure

examples/aptos/call-contract/contracts/HelloWorld.sol

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
//SPDX-License-Identifier: MIT
22
pragma solidity >=0.8.9 <0.9.0;
33

4-
import { IAxelarExecutable } from '@axelar-network/axelar-cgp-solidity/contracts/interfaces/IAxelarExecutable.sol';
4+
import { AxelarExecutable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol';
55
import { IAxelarGateway } from '@axelar-network/axelar-cgp-solidity/contracts/interfaces/IAxelarGateway.sol';
66
import { IAxelarGasService } from '@axelar-network/axelar-cgp-solidity/contracts/interfaces/IAxelarGasService.sol';
77

8-
contract HelloWorld is IAxelarExecutable {
8+
contract HelloWorld is AxelarExecutable {
99
string public value;
1010
string public sourceChain;
1111
string public sourceAddress;
1212
IAxelarGasService gasService;
1313

1414
constructor(address _gateway, address _gasReceiver)
15-
IAxelarExecutable(_gateway)
15+
AxelarExecutable(_gateway)
1616
{
1717
gasService = IAxelarGasService(_gasReceiver);
1818
}

examples/aptos/token-linker/index.js

+7-11
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,23 @@
11
'use strict';
22

33
const { HexString, CoinClient } = require('aptos');
4-
const {
5-
getDefaultProvider,
6-
Contract,
7-
constants: { AddressZero },
8-
} = require('ethers');
4+
const { getDefaultProvider, Contract } = require('ethers');
95
const {
106
utils: { deployContract },
117
AptosNetwork,
128
} = require('@axelar-network/axelar-local-dev');
139

14-
const TokenLinker = rootRequire('./artifacts/examples/aptos-token-linker/contracts/AptosTokenLinker.sol/AptosTokenLinker.json');
10+
const TokenLinker = rootRequire('./artifacts/examples/aptos/token-linker/contracts/AptosTokenLinker.sol/AptosTokenLinker.json');
1511
const Token = require('@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/test/ERC20MintableBurnable.sol/ERC20MintableBurnable.json');
1612

1713
const aptosTokenLinkerAddress = process.env.APTOS_TOKEN_LINKER_ADDRESS;
1814
const ignoreDigits = 5;
1915

2016
async function preDeploy() {
21-
console.log(`Deploying token_linker for aptos.`);
17+
console.log('Deploying token_linker for aptos.');
2218
const client = new AptosNetwork(process.env.APTOS_URL);
23-
await client.deploy('examples/aptos-token-linker/modules/build/token_linker', ['token_linker.mv'], '0xa1');
24-
console.log(`Deployed token_linker for aptos.`);
19+
await client.deploy('examples/aptos/token-linker/modules/build/token_linker', ['token_linker.mv'], '0xa1');
20+
console.log('Deployed token_linker for aptos.');
2521
}
2622

2723
async function deploy(chain, wallet) {
@@ -54,7 +50,7 @@ async function execute(chains, wallet, options) {
5450
chain.contract = new Contract(chain.aptosTokenLinker, TokenLinker.abi, chain.wallet);
5551
}
5652

57-
const evm = options.getSourceChain(chains);
53+
const evm = options.source;
5854
const amount1 = args[1] || BigInt(1e18);
5955
const amount2 = args[2] || BigInt(Math.floor(5e17 / 256 ** ignoreDigits));
6056

@@ -84,7 +80,7 @@ async function execute(chains, wallet, options) {
8480

8581
// Set the gasLimit to 3e5 (a safe overestimate) and get the gas price.
8682
const gasLimit = 3e5;
87-
const gasPrice = 1
83+
const gasPrice = 1;
8884

8985
console.log(`Minting and Approving ${Number(amount1) / 1e18} ALT`);
9086

examples/evm/Proxy.sol

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
pragma solidity 0.8.9;
44

5-
import {Proxy} from '@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradable/Proxy.sol';
5+
import {InitProxy} from '@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradable/InitProxy.sol';
66

7-
contract ExampleProxy is Proxy {
7+
contract ExampleProxy is InitProxy {
88
function contractId()
99
internal
1010
pure

examples/evm/README.md

+1-5
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,8 @@ npm run build
1818

1919
## Advanced
2020

21-
- [forecall](forecall)
22-
- [headers](headers)
23-
- [deposit-address](deposit-address)
21+
- [call-contract-with-token-express](call-contract-with-token-express)
2422
- [nft-linker](nft-linker)
2523
- [nft-auctionhouse](nft-auctionhouse)
26-
- [nonced-execution](nonced-execution)
2724
- [send-ack](send-ack)
2825
- [cross-chain-token](cross-chain-token)
29-
- [cross-chain-lending](cross-chain-lending)
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,43 @@
11
//SPDX-License-Identifier: MIT
22
pragma solidity 0.8.9;
33

4+
import { AxelarExecutable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol';
5+
import { ExpressExecutable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/express/ExpressExecutable.sol';
46
import { IAxelarGateway } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol';
57
import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol';
68
import { IAxelarGasService } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGasService.sol';
7-
import { ExpressExecutable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/express/ExpressExecutable.sol';
89
import { Upgradable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradable/Upgradable.sol';
9-
import { AddressToString } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/AddressString.sol';
1010

11-
contract DistributionForecallable is ExpressExecutable, Upgradable {
12-
using AddressToString for address;
11+
contract DistributionExpressExecutable is ExpressExecutable {
1312
IAxelarGasService public immutable gasService;
1413

1514
constructor(address gateway_, address gasReceiver_) ExpressExecutable(gateway_) {
1615
gasService = IAxelarGasService(gasReceiver_);
1716
}
1817

19-
function _sendToMany(
20-
string memory destinationChain,
21-
address[] calldata destinationAddresses,
22-
string memory symbol,
23-
uint256 amount,
24-
uint256 feePercent
25-
) internal {
26-
address tokenAddress = gateway.tokenAddresses(symbol);
27-
IERC20(tokenAddress).transferFrom(msg.sender, address(this), amount);
28-
IERC20(tokenAddress).approve(address(gateway), amount);
29-
bytes memory payload = abi.encode(feePercent, destinationAddresses);
30-
gateway.callContractWithToken(destinationChain, address(this).toString(), payload, symbol, amount);
31-
}
32-
3318
function sendToMany(
3419
string memory destinationChain,
20+
string memory destinationAddress,
3521
address[] calldata destinationAddresses,
3622
string memory symbol,
3723
uint256 amount
3824
) external payable {
39-
_sendToMany(destinationChain, destinationAddresses, symbol, amount, 0);
40-
}
41-
42-
function sendToManyForecall(
43-
string memory destinationChain,
44-
address[] calldata destinationAddresses,
45-
string memory symbol,
46-
uint256 amount,
47-
uint64 feeNum,
48-
uint64 feeDenom,
49-
uint128 salt
50-
) external payable {
51-
uint256 feePercent = feeNum + (uint256(feeDenom) << 64) + (uint256(salt) << 128);
52-
_sendToMany(destinationChain, destinationAddresses, symbol, amount, feePercent);
25+
address tokenAddress = gateway.tokenAddresses(symbol);
26+
IERC20(tokenAddress).transferFrom(msg.sender, address(this), amount);
27+
IERC20(tokenAddress).approve(address(gateway), amount);
28+
bytes memory payload = abi.encode(destinationAddresses);
29+
if (msg.value > 0) {
30+
gasService.payNativeGasForExpressCallWithToken{ value: msg.value }(
31+
address(this),
32+
destinationChain,
33+
destinationAddress,
34+
payload,
35+
symbol,
36+
amount,
37+
msg.sender
38+
);
39+
}
40+
gateway.callContractWithToken(destinationChain, destinationAddress, payload, symbol, amount);
5341
}
5442

5543
function _executeWithToken(
@@ -59,7 +47,7 @@ contract DistributionForecallable is ExpressExecutable, Upgradable {
5947
string calldata tokenSymbol,
6048
uint256 amount
6149
) internal override {
62-
(, address[] memory recipients) = abi.decode(payload, (uint256, address[]));
50+
address[] memory recipients = abi.decode(payload, (address[]));
6351
address tokenAddress = gateway.tokenAddresses(tokenSymbol);
6452

6553
uint256 sentAmount = amount / recipients.length;
@@ -68,15 +56,7 @@ contract DistributionForecallable is ExpressExecutable, Upgradable {
6856
}
6957
}
7058

71-
function amountPostFee(uint256 amount, bytes calldata payload) public pure returns (uint256) {
72-
uint256 feePercent = abi.decode(payload, (uint256));
73-
uint64 num = uint64(feePercent);
74-
uint64 denom = uint64(feePercent >> 64);
75-
if (denom == 0) return amount;
76-
return amount - (amount * num) / denom;
77-
}
78-
7959
function contractId() external pure returns (bytes32) {
80-
return keccak256('example');
60+
return keccak256('distribution-proxy');
8161
}
8262
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Call contract with token
2+
3+
This example allows you to send aUSDC from a source chain to a destination chain and distribute it equally among specified accounts.
4+
5+
### Deployment
6+
7+
To deploy the contract, run the following command:
8+
9+
```bash
10+
npm run deploy evm/call-contract-with-token-express [local|testnet]
11+
```
12+
13+
### Execution
14+
15+
To execute the example, use the following command:
16+
17+
```bash
18+
npm run execute evm/call-contract-with-token-express [local|testnet] ${srcChain} ${destChain} ${amount} ${account} ${account2} ...
19+
```
20+
21+
**Note**
22+
The GMP Express feature is already lived on our testnet. However, the following conditions need to be met:
23+
24+
- The contract address must be whitelisted by our executor service.
25+
- We only support `aUSDC` token and the amount must be less than 500 aUSDC.
26+
27+
Currently, our whitelisted contract addresses for this example are:
28+
29+
- Avalanche: `0x4E3b6C3d284361Eb4fA9aDE5831eEfF85578b72c`
30+
- Polygon: `0xAb6dAb12aCCAe665A44E69d44bcfC6219A30Dd32`
31+
32+
### Parameters
33+
34+
- `srcChain`: The blockchain network from which the aUSDC will be transferred. Valid values are Moonbeam, Avalanche, Fantom, Ethereum, and Polygon. Default value is Polygon
35+
- `destChain`: The blockchain network to which the aUSDC will be transferred. Valid values are Moonbeam, Avalanche, Fantom, Ethereum, and Polygon. Default value is Avalanche.
36+
- `amount`: The amount of aUSDC to be transferred and distributed among the specified accounts. Default value is 10.
37+
- `account`: The address of the first account to receive aUSDC.
38+
- `account2`: The address of the second account to receive aUSDC, and so on.
39+
40+
## Example
41+
42+
```bash
43+
npm run deploy evm/call-contract-with-token-express local
44+
npm run execute evm/call-contract-with-token-express local "Polygon" "Avalanche" 100 0xBa86A5719722B02a5D5e388999C25f3333c7A9fb
45+
```
46+
47+
### Output:
48+
49+
```
50+
--- Initially ---
51+
0xBa86A5719722B02a5D5e388999C25f3333c7A9fb has 100 aUSDC
52+
--- After ---
53+
0xBa86A5719722B02a5D5e388999C25f3333c7A9fb has 199 aUSDC
54+
```

0 commit comments

Comments
 (0)