Skip to content

Commit

Permalink
feat: axelar local dev multiversx add support for ITS (#106)
Browse files Browse the repository at this point in the history
* Start setup of multiversx package.

* Start developing multiversx package integration.

* Deploy multiversx axelar contracts to localnet.

* Start working on call contract example for evm to multiversx.

* Working temp example with avalanche to ethereum message.

* Add hello world contract for multiversx and deploy it.

* Working cross chain call from Ethereum to MultiversX.

* Cleanup for multiversx package and fully working multiversx relayer with elasticsearch events.

* Add wasm contracts to repo.

* MultiversX transaction watcher fixes and updates for new contracts.

* Fix multiversx contract execute.

* Deploy interchain token service for MultiversX.

* Add its transactions processing for multiversx.

* Create multiversx its class for querying contract.

* Process other multiversx gas paid events.

* Add integration tests for multiversx.

* Add test for multiversx its.

* Fix contracts directory not being included in multiversx package.

* Update multiversx package.

* Update multiversx tests.

---------

Co-authored-by: Rares <[email protected]>
  • Loading branch information
raress96 and raress96 authored Mar 12, 2024
1 parent 2f82f82 commit ae9a8cb
Show file tree
Hide file tree
Showing 12 changed files with 655 additions and 26 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

147 changes: 141 additions & 6 deletions packages/axelar-local-dev-multiversx/__tests__/multiversx.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import path from 'path';
import { ethers } from 'ethers';
import { createNetwork, deployContract, EvmRelayer, Network, relay, setLogger } from '@axelar-network/axelar-local-dev';
import { Contract, ethers, Wallet } from 'ethers';
import { contracts, createNetwork, deployContract, EvmRelayer, Network, relay, setLogger } from '@axelar-network/axelar-local-dev';
import HelloWorld from '../artifacts/__tests__/contracts/HelloWorld.sol/HelloWorld.json';
import { createMultiversXNetwork, MultiversXNetwork, MultiversXRelayer } from '../src';
import { createMultiversXNetwork, MultiversXNetwork, MultiversXRelayer, registerMultiversXRemoteITS } from '../src';
import {
Address,
AddressValue,
Expand All @@ -24,10 +24,15 @@ setLogger(() => undefined);
describe('multiversx', () => {
let client: MultiversXNetwork;
let evmNetwork: Network;
let wallet: Wallet;

beforeEach(async () => {
beforeAll(async () => {
client = await createMultiversXNetwork();
});

beforeEach(async () => {
evmNetwork = await createNetwork();
wallet = evmNetwork.userWallets[0];
});

it('should be able to relay tx from EVM to MultiversX', async () => {
Expand All @@ -40,7 +45,7 @@ describe('multiversx', () => {
]);

// Deploy EVM contract
const helloWorld = await deployContract(evmNetwork.userWallets[0], HelloWorld, [
const helloWorld = await deployContract(wallet, HelloWorld, [
evmNetwork.gateway.address,
evmNetwork.gasService.address
]);
Expand Down Expand Up @@ -80,7 +85,7 @@ describe('multiversx', () => {
]);

// Deploy EVM contract
const helloWorld = await deployContract(evmNetwork.userWallets[0], HelloWorld, [
const helloWorld = await deployContract(wallet, HelloWorld, [
evmNetwork.gateway.address,
evmNetwork.gasService.address
]);
Expand Down Expand Up @@ -185,4 +190,134 @@ describe('multiversx', () => {

expect(message).toEqual(toSend);
});

it('should be able to send token from EVM to MultiversX', async () => {
const evmIts = new Contract(evmNetwork.interchainTokenService.address, contracts.IInterchainTokenService.abi, wallet.connect(evmNetwork.provider));
const evmItsFactory = new Contract(evmNetwork.interchainTokenFactory.address, contracts.IInterchainTokenFactory.abi, wallet.connect(evmNetwork.provider));

await registerMultiversXRemoteITS(client, [evmNetwork]);

const name = 'InterchainToken';
const symbol = 'ITE';
const decimals = 18;
const amount = 1000;
const salt = keccak256(ethers.utils.defaultAbiCoder.encode(['uint256', 'uint256'], [process.pid, process.ppid]));
const fee = 100000000;

const tokenId = await evmItsFactory.interchainTokenId(wallet.address, salt);

await (await evmItsFactory.deployInterchainToken(
salt,
name,
symbol,
decimals,
amount,
wallet.address,
)).wait();

await (await evmItsFactory.deployRemoteInterchainToken(
'',
salt,
wallet.address,
'multiversx',
fee,
{ value: fee },
)).wait();

const multiversXRelayer = new MultiversXRelayer();

// Relay tx from EVM to MultiversX
await relay({
multiversx: multiversXRelayer,
evm: new EvmRelayer({ multiversXRelayer })
});

let tokenIdentifier = await client.its.getValidTokenIdentifier(tokenId);
expect(tokenIdentifier);
tokenIdentifier = tokenIdentifier as string;

let balance = (await client.getFungibleTokenOfAccount(client.owner, tokenIdentifier)).balance?.toString();
expect(!balance);

const tx = await evmIts.interchainTransfer(tokenId, 'multiversx', client.owner.pubkey(), amount, '0x', fee, {
value: fee,
});
await tx.wait();

// Relay tx from EVM to MultiversX
await relay({
multiversx: multiversXRelayer,
evm: new EvmRelayer({ multiversXRelayer })
});

balance = (await client.getFungibleTokenOfAccount(client.owner, tokenIdentifier)).balance?.toString();
expect(balance === '1000');
});

// it('should be able to send token from MultiversX to EVM', async () => {
// const evmIts = new Contract(evmNetwork.interchainTokenService.address, contracts.IInterchainTokenService.abi, wallet.connect(evmNetwork.provider));
//
// await registerMultiversXRemoteITS(client, [evmNetwork]);
//
// const name = 'InterchainToken';
// const symbol = 'ITE';
// const decimals = 18;
// const amount = 1000;
// const salt = keccak256(ethers.utils.defaultAbiCoder.encode(['uint256', 'uint256'], [process.pid, process.ppid]));
// const fee = 100000000;
//
// const tokenId = await client.its.interchainTokenId(client.owner, salt);
//
// await client.its.deployInterchainToken(
// salt,
// name,
// symbol,
// decimals,
// amount,
// client.owner,
// );
//
// let tokenIdentifier = await client.its.getValidTokenIdentifier(tokenId);
// expect(tokenIdentifier);
// tokenIdentifier = tokenIdentifier as string;
//
// const multiversXRelayer = new MultiversXRelayer();
// // Update events first so new Multiversx logs are processed afterwards
// await multiversXRelayer.updateEvents();
//
// await client.its.deployRemoteInterchainToken(
// '',
// salt,
// client.owner,
// evmNetwork.name,
// fee,
// );
//
// // Relay tx from MultiversX to EVM
// await relay({
// multiversx: multiversXRelayer,
// evm: new EvmRelayer({ multiversXRelayer })
// });
//
// // TODO: The evm execute transaction is not actually executed successfully for some reason...
// // const evmTokenAddress = await evmIts.interchainTokenAddress('0x' + tokenId);
// // const code = await evmNetwork.provider.getCode(evmTokenAddress);
// // expect (code !== '0x');
// //
// // const destinationToken = new Contract(evmTokenAddress, IERC20.abi, evmNetwork.provider);
// // let balance = await destinationToken.balanceOf(wallet.address);
// // expect(!balance);
// //
// // const result = await client.its.interchainTransfer(tokenId, evmNetwork.name, wallet.address, tokenIdentifier, amount.toString(), '5');
// // expect(result);
// //
// // // Relay tx from MultiversX to EVM
// // await relay({
// // multiversx: multiversXRelayer,
// // evm: new EvmRelayer({ multiversXRelayer })
// // });
// //
// // balance = await destinationToken.balanceOf(wallet.address);
// // expect(balance === '995');
// });
});
Binary file not shown.
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion packages/axelar-local-dev-multiversx/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@axelar-network/axelar-local-dev-multiversx",
"version": "2.2.1",
"version": "2.2.2",
"main": "dist/index.js",
"files": [
"dist/",
Expand Down
42 changes: 42 additions & 0 deletions packages/axelar-local-dev-multiversx/src/Command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,46 @@ export class Command {
'multiversx'
);
};

static createContractCallCommandIts = (commandId: string, relayData: RelayData, args: CallContractArgs) => {
// Remove 0x added by Ethereum for hex strings
const payloadHex = args.payload.startsWith('0x') ? args.payload.substring(2) : args.payload;
const payloadHash = createKeccakHash('keccak256').update(Buffer.from(payloadHex, 'hex')).digest('hex');

return new Command(
commandId,
'approveContractCall',
[args.from, args.sourceAddress, args.destinationContractAddress, payloadHash, args.transactionHash, args.sourceEventIndex],
[],
async () => {
const result = defaultAbiCoder.decode(['uint256'], Buffer.from(payloadHex, 'hex'));
const messageType = Number(result[0]);

let tx = await multiversXNetwork.executeContract(
commandId,
args.destinationContractAddress,
args.from,
args.sourceAddress,
payloadHex
);

// In case of deploy interchain token, call 2nd time with EGLD value
if (messageType === 1) {
tx = await multiversXNetwork.executeContract(
commandId,
args.destinationContractAddress,
args.from,
args.sourceAddress,
payloadHex,
'5000000000000000000' // 5 EGLD for ESDT issue cost on localnet
);
}

relayData.callContract[commandId].execution = tx.getHash();

return tx;
},
'multiversx'
);
};
}
Loading

0 comments on commit ae9a8cb

Please sign in to comment.