Skip to content

Commit

Permalink
Add E2E Tests for Asset Teleportation Between LAOS and Asset Hub with…
Browse files Browse the repository at this point in the history
… Configuration Updates (#829)

* mercury sovereign account

* fix compilation

* adding test for zombienet sovereign address

* zombienet uses assehub for default

* downloading polkadot-parachain

* set variable for asset hub

* fix bin

* using a couple of collators

* wip

* add limited teleport asset call

* add limited teleport asset call

* test hrmp channels are open

* restore unnecesary changes

* restore xcm-native file

* WIP test teleport asset from laos to asset hub

* test force the creation of hrmp channels

* edit xcm config and zombienet config file

* add some logs

* add setup file to e2e tests

* merge main

* restore unnecesary changes

* restore unnecesary changes

* wip

* Adding withdrawasset + buyexecution to e2e create asset test

* Prettier

* read event with hardcoded call

* build correct call

* finish create foreign asset test

* add exit so mocha exists when tests end

* no need of setup file anymore

* test send create pool xcm msg

* create pool call is encoded properly

* refactor

* check balances after creating foreign asset

* check balances after creating foreign asset

* Using WS connection to Zombienet in order to receibe tx status/events

* Reveting to http provider for simplicity

* Waiting together for all blockchains producing blocks

* Solving conflicts with test-create-pool

* add mint step so ferdie owns laos in AH

* Refactoring

* prettier

* uncomment teleport

* add TODO comment

* some comments

* Correct deposit in e2e teleport test

* Solving typo

* Solving typo

* test teleport back

* delete old line

* refactor: resuse laosAssetId and remove chai-bn dep

* refactor: add waitForEvent fn

* add some logs to tests

* go back to 1seg of delay and set 15 waiting blocks for events

* use checking account to disregard wrong event

* format issues

* use HttpProvider to prevent poltergeist

* increate timeout

* go back to 600000 ms

* go back to 600000 ms

* remove comments

* apply suggestions

* fix BN compare

* Update readme

* fix: read events from canonical chain

* Adding helpful structures

* Adding data structures for networks

* downgrade to 14.0.1

* update and remove unused deps

* refactor test names

* npm fmt

* open polkadot connections only when needed

* Using this to pass global context to tests

* fmt

* Solving typo

* Deleting repeated stuff

* Rename types

* Moving mocha types to external file

* Use this.ethereumPairs instead of the plain address along tests

* fmt

* increasing invalid tx wait

* Managing all tx statuses

* Managing future, retracted and finalityTimeout tx statuses

---------

Co-authored-by: Alessandro Siniscalchi <[email protected]>
Co-authored-by: luispdm <[email protected]>
Co-authored-by: Tomás Senovilla Polo <[email protected]>
  • Loading branch information
4 people authored Nov 13, 2024
1 parent 41da0fe commit 4076f10
Show file tree
Hide file tree
Showing 21 changed files with 3,679 additions and 1,858 deletions.
1 change: 1 addition & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ jobs:
run: |
export ZOMBIENET_RELAYCHAIN_COMMAND=./tmp/polkadot
export ZOMBIENET_LAOS_COMMAND=./target/release/laos
export ZOMBIENET_ASSETHUB_COMMAND=./tmp/polkadot-parachain
./zombienet-linux-x64 spawn ./zombienet/native.toml &
echo "Zombienet started"
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ node_modules/
frontier-test-tmp
build/

tmp/
tmp/
3,888 changes: 2,401 additions & 1,487 deletions e2e-tests/package-lock.json

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions e2e-tests/package.json
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
{
"name": "ts-tests",
"name": "e2e-tests",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"fmt-check": "prettier ./tests --check",
"fmt": "prettier ./tests --write",
"build": "./compile_contracts.sh",
"test": "mocha -r ts-node/register -t 600000 'tests/**/*.ts'",
"test": "mocha -r ts-node/register -t 900000 'tests/**/*.ts'",
"test-sql": "FRONTIER_BACKEND_TYPE='sql' mocha -r ts-node/register 'tests/**/*.ts'"
},
"author": "",
"license": "ISC",
"dependencies": {
"@polkadot/api": "^14.2.3",
"@polkadot/api-augment": "^14.2.3",
"@polkadot/types": "^14.2.2",
"@polkadot/util": "^13.2.2",
"@types/chai": "^4.3.5",
"@types/mocha": "^10.0.1",
"chai": "^4.3.7",
"chai-as-promised": "^7.1.1",
"ethers": "^6.3.0",
"mocha": "^10.2.0",
"mocha-steps": "^1.3.0",
"rimraf": "^5.0.0",
"solc": "^0.8.3",
"truffle": "^5.11.5",
"ts-node": "^10.9.1",
Expand Down
9 changes: 6 additions & 3 deletions e2e-tests/tests/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@ import EvolutionCollection from "../build/contracts/EvolutionCollection.json";
import EvolutionCollectionFactory from "../build/contracts/EvolutionCollectionFactory.json";
import Vesting from "../build/contracts/Vesting.json";
import ParachainStaking from "../build/contracts/ParachainStaking.json";

// Node config
export const RUNTIME_SPEC_NAME = "laos";
export const RUNTIME_SPEC_VERSION = 2390;
export const RUNTIME_IMPL_VERSION = 0;
export const LOCAL_NODE_IP = "127.0.0.1:9999";
export const LAOS_NODE_IP = "127.0.0.1:9999";
export const ASSET_HUB_NODE_IP = "127.0.0.1:9950";
export const RELAYCHAIN_NODE_IP = "127.0.0.1:9944";

// Chain config
export const CHAIN_ID = 667;
export const GAS_PRICE = "0x3B9ACA00";
export const ASSET_HUB_PARA_ID = 1000;
export const LAOS_PARA_ID = 2900;

// Accounts
export const CHECKING_ACCOUNT = "0x6d6F646c70792F78636D63680000000000000000";
export const FAITH = "0xC0F0f4ab324C46e55D02D0033343B4Be8A55532d";
export const FAITH_PRIVATE_KEY = "0xb9d2ea9a615f3165812e8d44de0d24da9bbd164b65c4f0573e1ce2c8dbd9c8df";
export const ALITH = "0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac";
Expand Down
37 changes: 19 additions & 18 deletions e2e-tests/tests/test-create-collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,72 +5,73 @@ import {
EVOLUTION_COLLECTION_FACTORY_CONTRACT_ADDRESS,
EVOLUTION_COLLECTION_FACTORY_ABI,
GAS_PRICE,
FAITH,
FAITH_PRIVATE_KEY,
REVERT_BYTECODE,
SELECTOR_LOG_NEW_COLLECTION,
} from "./config";
import { createCollection, describeWithExistingNode } from "./util";

describeWithExistingNode("Frontier RPC (Create Collection)", (context) => {
describeWithExistingNode("Frontier RPC (Create Collection)", function () {
let contract: Contract;
// This is the contract that is created in the test
let testCollectionContract: Contract;
// This is the address of another contract that is created in the test
let testCollectionAddress: string;

before(async function () {
contract = new context.web3.eth.Contract(
contract = new this.context.web3.eth.Contract(
EVOLUTION_COLLECTION_FACTORY_ABI,
EVOLUTION_COLLECTION_FACTORY_CONTRACT_ADDRESS,
{
from: FAITH,
from: this.ethereumPairs.faith.address,
gasPrice: GAS_PRICE,
}
);
context.web3.eth.accounts.wallet.add(FAITH_PRIVATE_KEY);
});

step("when collection is created, it should return owner", async function () {
const collectionContract = await createCollection(context);
const collectionContract = await createCollection(this.context);
testCollectionContract = collectionContract;

const owner = await collectionContract.methods.owner().call();
expect(owner).to.be.eq(FAITH);
expect(owner).to.be.eq(this.ethereumPairs.faith.address);
});

step("when collection is created event is emitted", async function () {
const estimatedGas = await contract.methods.createCollection(FAITH).estimateGas();
const result = await contract.methods.createCollection(FAITH).send({
from: FAITH,
const estimatedGas = await contract.methods.createCollection(this.ethereumPairs.faith.address).estimateGas();
const result = await contract.methods.createCollection(this.ethereumPairs.faith.address).send({
from: this.ethereumPairs.faith.address,
gas: estimatedGas,
gasPrice: GAS_PRICE,
});
expect(result.status).to.be.eq(true);

expect(Object.keys(result.events).length).to.be.eq(1);
expect(context.web3.utils.isAddress(result.events.NewCollection.returnValues._collectionAddress)).to.be.eq(
expect(this.context.web3.utils.isAddress(result.events.NewCollection.returnValues._collectionAddress)).to.be.eq(
true
);
testCollectionAddress = result.events.NewCollection.returnValues._collectionAddress;
expect(result.events.NewCollection.returnValues._owner).to.be.eq(FAITH);
expect(result.events.NewCollection.returnValues._owner).to.be.eq(this.ethereumPairs.faith.address);

// event topics
expect(result.events.NewCollection.raw.topics.length).to.be.eq(2);
expect(result.events.NewCollection.raw.topics[0]).to.be.eq(SELECTOR_LOG_NEW_COLLECTION);
expect(result.events.NewCollection.raw.topics[1]).to.be.eq(context.web3.utils.padLeft(FAITH.toLowerCase(), 64));
expect(result.events.NewCollection.raw.topics[1]).to.be.eq(
this.context.web3.utils.padLeft(this.ethereumPairs.faith.address.toLowerCase(), 64)
);

// event data
expect(result.events.NewCollection.raw.data.toLowerCase()).to.be.eq(
context.web3.utils.padLeft(result.events.NewCollection.returnValues._collectionAddress, 64).toLowerCase()
this.context.web3.utils
.padLeft(result.events.NewCollection.returnValues._collectionAddress, 64)
.toLowerCase()
);
});

step("when collection is created, bytecode is inserted in the storage", async function () {
expect(await context.web3.eth.getCode(testCollectionContract.options.address)).to.be.eq(REVERT_BYTECODE);
expect(await context.web3.eth.getCode(testCollectionAddress)).to.be.eq(REVERT_BYTECODE);
expect(await this.context.web3.eth.getCode(testCollectionContract.options.address)).to.be.eq(REVERT_BYTECODE);
expect(await this.context.web3.eth.getCode(testCollectionAddress)).to.be.eq(REVERT_BYTECODE);

// non-contract address doesn't have any code
expect(await context.web3.eth.getCode(FAITH)).to.be.eq("0x");
expect(await this.context.web3.eth.getCode(this.ethereumPairs.faith.address)).to.be.eq("0x");
});
});
62 changes: 35 additions & 27 deletions e2e-tests/tests/test-evolution.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { createCollection, describeWithExistingNode, slotAndOwnerToTokenId } from "./util";
import {
FAITH,
SELECTOR_LOG_EVOLVED_WITH_EXTERNAL_TOKEN_URI,
SELECTOR_LOG_MINTED_WITH_EXTERNAL_TOKEN_URI,
SELECTOR_LOG_OWNERSHIP_TRANSFERRED,
Expand All @@ -10,11 +9,11 @@ import Contract from "web3-eth-contract";
import BN from "bn.js";
import { step } from "mocha-steps";

describeWithExistingNode("Frontier RPC (Mint and Evolve Assets)", (context) => {
describeWithExistingNode("Frontier RPC (Mint and Evolve Assets)", function () {
let collectionContract: Contract;

beforeEach(async function () {
collectionContract = await createCollection(context);
collectionContract = await createCollection(this.context);
});

step("when collection does not exist token uri should fail", async function () {
Expand All @@ -32,14 +31,14 @@ describeWithExistingNode("Frontier RPC (Mint and Evolve Assets)", (context) => {

step("when asset is minted it should return token uri", async function () {
const slot = "0";
const to = FAITH;
const to = this.ethereumPairs.faith.address;
const tokenURI = "https://example.com";

let nonce = await context.web3.eth.getTransactionCount(FAITH);
let nonce = await this.context.web3.eth.getTransactionCount(this.ethereumPairs.faith.address);
const estimatedGas = await collectionContract.methods.mintWithExternalURI(to, slot, tokenURI).estimateGas();
const result = await collectionContract.methods
.mintWithExternalURI(to, slot, tokenURI)
.send({ from: FAITH, gas: estimatedGas, nonce: nonce++ });
.send({ from: this.ethereumPairs.faith.address, gas: estimatedGas, nonce: nonce++ });
expect(result.status).to.be.eq(true);

const tokenId = result.events.MintedWithExternalURI.returnValues._tokenId;
Expand All @@ -49,7 +48,7 @@ describeWithExistingNode("Frontier RPC (Mint and Evolve Assets)", (context) => {

step("given slot and owner it should return token id", async function () {
const slot = "1";
const to = FAITH;
const to = this.ethereumPairs.faith.address;

const tokenId = slotAndOwnerToTokenId(slot, to);
expect(tokenId).to.be.eq("000000000000000000000001c0f0f4ab324c46e55d02d0033343b4be8a55532d");
Expand All @@ -59,13 +58,13 @@ describeWithExistingNode("Frontier RPC (Mint and Evolve Assets)", (context) => {

step("when asset is minted it should emit an event", async function () {
const slot = "22";
const to = FAITH;
const to = this.ethereumPairs.faith.address;
const tokenURI = "https://example.com";

const estimatedGas = await collectionContract.methods.mintWithExternalURI(to, slot, tokenURI).estimateGas();
const result = await collectionContract.methods
.mintWithExternalURI(to, slot, tokenURI)
.send({ from: FAITH, gas: estimatedGas });
.send({ from: this.ethereumPairs.faith.address, gas: estimatedGas });
expect(result.status).to.be.eq(true);

expect(Object.keys(result.events).length).to.be.eq(1);
Expand All @@ -82,18 +81,21 @@ describeWithExistingNode("Frontier RPC (Mint and Evolve Assets)", (context) => {
expect(result.events.MintedWithExternalURI.raw.topics.length).to.be.eq(2);
expect(result.events.MintedWithExternalURI.raw.topics[0]).to.be.eq(SELECTOR_LOG_MINTED_WITH_EXTERNAL_TOKEN_URI);
expect(result.events.MintedWithExternalURI.raw.topics[1]).to.be.eq(
context.web3.utils.padLeft(FAITH.toLowerCase(), 64)
this.context.web3.utils.padLeft(this.ethereumPairs.faith.address.toLowerCase(), 64)
);

// event data
expect(result.events.MintedWithExternalURI.raw.data).to.be.eq(
context.web3.eth.abi.encodeParameters(["uint96", "uint256", "string"], [slot, tokenIdDecimal, tokenURI])
this.context.web3.eth.abi.encodeParameters(
["uint96", "uint256", "string"],
[slot, tokenIdDecimal, tokenURI]
)
);
});

step("when asset is evolved it should change token uri", async function () {
const slot = "22";
const to = FAITH;
const to = this.ethereumPairs.faith.address;
const tokenURI = "https://example.com";
const newTokenURI = "https://new_example.com";
const tokenId = slotAndOwnerToTokenId(slot, to);
Expand All @@ -102,15 +104,15 @@ describeWithExistingNode("Frontier RPC (Mint and Evolve Assets)", (context) => {
var estimatedGas = await collectionContract.methods.mintWithExternalURI(to, slot, tokenURI).estimateGas();
const mintingResult = await collectionContract.methods
.mintWithExternalURI(to, slot, tokenURI)
.send({ from: FAITH, gas: estimatedGas });
.send({ from: this.ethereumPairs.faith.address, gas: estimatedGas });
expect(mintingResult.status).to.be.eq(true);

estimatedGas = await collectionContract.methods
.evolveWithExternalURI(tokenIdDecimal, newTokenURI)
.estimateGas();
const evolvingResult = await collectionContract.methods
.evolveWithExternalURI(tokenIdDecimal, newTokenURI)
.send({ from: FAITH, gas: estimatedGas });
.send({ from: this.ethereumPairs.faith.address, gas: estimatedGas });
expect(evolvingResult.status).to.be.eq(true);

const got = await collectionContract.methods.tokenURI(tokenIdDecimal).call();
Expand All @@ -119,7 +121,7 @@ describeWithExistingNode("Frontier RPC (Mint and Evolve Assets)", (context) => {

step("when asset is evolved it should emit an event", async function () {
const slot = "22";
const to = FAITH;
const to = this.ethereumPairs.faith.address;
const tokenURI = "https://example.com";
const newTokenURI = "https://new_example.com";
const tokenId = slotAndOwnerToTokenId(slot, to);
Expand All @@ -128,15 +130,15 @@ describeWithExistingNode("Frontier RPC (Mint and Evolve Assets)", (context) => {
var estimatedGas = await collectionContract.methods.mintWithExternalURI(to, slot, tokenURI).estimateGas();
const mintingResult = await collectionContract.methods
.mintWithExternalURI(to, slot, tokenURI)
.send({ from: FAITH, gas: estimatedGas });
.send({ from: this.ethereumPairs.faith.address, gas: estimatedGas });
expect(mintingResult.status).to.be.eq(true);

estimatedGas = await collectionContract.methods
.evolveWithExternalURI(tokenIdDecimal, newTokenURI)
.estimateGas();
const evolvingResult = await collectionContract.methods
.evolveWithExternalURI(tokenIdDecimal, newTokenURI)
.send({ from: FAITH, gas: estimatedGas });
.send({ from: this.ethereumPairs.faith.address, gas: estimatedGas });
expect(evolvingResult.status).to.be.eq(true);

expect(Object.keys(evolvingResult.events).length).to.be.eq(1);
Expand All @@ -154,33 +156,35 @@ describeWithExistingNode("Frontier RPC (Mint and Evolve Assets)", (context) => {

// event data
expect(evolvingResult.events.EvolvedWithExternalURI.raw.data).to.be.eq(
context.web3.eth.abi.encodeParameters(["string"], [newTokenURI])
this.context.web3.eth.abi.encodeParameters(["string"], [newTokenURI])
);
});
});

describeWithExistingNode("Frontier RPC (Transfer Ownership)", (context) => {
describeWithExistingNode("Frontier RPC (Transfer Ownership)", function () {
let collectionContract: Contract;

before(async function () {
collectionContract = await createCollection(context);
collectionContract = await createCollection(this.context);
});

step("when is transferred owner should change and emit an event", async function () {
const newOwner = "0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac";

expect(await collectionContract.methods.owner().call()).to.be.eq(FAITH);
expect(await collectionContract.methods.owner().call()).to.be.eq(this.ethereumPairs.faith.address);
const estimatedGas = await collectionContract.methods.transferOwnership(newOwner).estimateGas();
const tranferringResult = await collectionContract.methods
.transferOwnership(newOwner)
.send({ from: FAITH, gas: estimatedGas });
.send({ from: this.ethereumPairs.faith.address, gas: estimatedGas });
expect(tranferringResult.status).to.be.eq(true);
expect(await collectionContract.methods.owner().call()).to.be.eq(newOwner);

expect(Object.keys(tranferringResult.events).length).to.be.eq(1);

// data returned within the event
expect(tranferringResult.events.OwnershipTransferred.returnValues._previousOwner).to.be.eq(FAITH);
expect(tranferringResult.events.OwnershipTransferred.returnValues._previousOwner).to.be.eq(
this.ethereumPairs.faith.address
);
expect(tranferringResult.events.OwnershipTransferred.returnValues._newOwner).to.be.eq(newOwner);

// event topics
Expand All @@ -189,17 +193,21 @@ describeWithExistingNode("Frontier RPC (Transfer Ownership)", (context) => {
SELECTOR_LOG_OWNERSHIP_TRANSFERRED
);
expect(tranferringResult.events.OwnershipTransferred.raw.topics[1]).to.be.eq(
context.web3.utils.padLeft(FAITH.toLowerCase(), 64)
this.context.web3.utils.padLeft(this.ethereumPairs.faith.address.toLowerCase(), 64)
);
expect(tranferringResult.events.OwnershipTransferred.raw.topics[2]).to.be.eq(
context.web3.utils.padLeft(newOwner.toLowerCase(), 64)
this.context.web3.utils.padLeft(newOwner.toLowerCase(), 64)
);
// event data
expect(tranferringResult.events.OwnershipTransferred.raw.data).to.be.eq("0x");

try {
const estimatedGas = await collectionContract.methods.transferOwnership(FAITH).estimateGas();
await collectionContract.methods.transferOwnership(FAITH).send({ from: FAITH, gas: estimatedGas });
const estimatedGas = await collectionContract.methods
.transferOwnership(this.ethereumPairs.faith.address)
.estimateGas();
await collectionContract.methods
.transferOwnership(this.ethereumPairs.faith.address)
.send({ from: this.ethereumPairs.faith.address, gas: estimatedGas });
expect.fail("Expected error was not thrown"); // Ensure an error is thrown
} catch (error) {
expect(error.message).to.eq(
Expand Down
Loading

0 comments on commit 4076f10

Please sign in to comment.