Skip to content
This repository has been archived by the owner on Oct 22, 2024. It is now read-only.

Commit

Permalink
Clean up e2e tests (paritytech#365)
Browse files Browse the repository at this point in the history
* update

* fix tests

* fast test

* ethapp tests working

* eth erc20 working

* fix eth erc20

* done

* no p

* np P
  • Loading branch information
musnit authored Apr 22, 2021
1 parent 9f39477 commit 728f0eb
Show file tree
Hide file tree
Showing 9 changed files with 375 additions and 209 deletions.
2 changes: 1 addition & 1 deletion test/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ cd ./node_modules/@snowfork/snowbridge-types && yarn install
Install `polkadot-launch`:

```bash
git clone -n https://github.com/snowfork/polkadot-launch.git /tmp/polkadot-launch
git clone -n https://github.com/paritytech/polkadot-launch.git /tmp/polkadot-launch
cd /tmp/polkadot-launch
yarn install
yarn build
Expand Down
2 changes: 1 addition & 1 deletion test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"main": "index.js",
"license": "MIT",
"scripts": {
"test": "mocha --timeout 120000 --exit"
"test": "mocha --timeout 110000 --exit"
},
"dependencies": {
"@polkadot/api": "^4.4.1",
Expand Down
22 changes: 20 additions & 2 deletions test/src/ethclient/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ const ERC20 = require('../../../ethereum/build/contracts/ERC20.json');
const TestToken = require('../../../ethereum/build/contracts/TestToken.json');
const DOTApp = require('../../../ethereum/build/contracts/DOTApp.json');
const WrappedToken = require('../../../ethereum/build/contracts/WrappedToken.json');


const BasicOutboundChannel = require('../../../ethereum/build/contracts/BasicOutboundChannel.json');
const IncentivizedOutboundChannel = require('../../../ethereum/build/contracts/IncentivizedOutboundChannel.json');

/**
* The Ethereum client for Bridge interaction
Expand All @@ -33,6 +33,14 @@ class EthClient {

const appDOT = new this.web3.eth.Contract(DOTApp.abi, DOTApp.networks[networkID].address);
this.appDOT = appDOT;

const appBasicOutChan = new this.web3.eth.Contract(BasicOutboundChannel.abi,
BasicOutboundChannel.networks[networkID].address);
this.appBasicOutChan = appBasicOutChan;

const appIncOutChan = new this.web3.eth.Contract(IncentivizedOutboundChannel.abi,
IncentivizedOutboundChannel.networks[networkID].address);
this.appIncOutChan = appIncOutChan;
};

loadERC20Contract() {
Expand Down Expand Up @@ -114,6 +122,16 @@ class EthClient {
value: 0
});
}

async waitForNextEventData({ appName, eventName, eventData }) {
let foundEvent = new Promise(async (resolve, reject) => {
this[appName].once(eventName, (error, event) => {
resolve(event.returnValues[eventData]);
})
});
return foundEvent;
}

}


Expand Down
31 changes: 31 additions & 0 deletions test/src/fixtures/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const TestToken = require('../../../ethereum/build/contracts/TestToken.json');
const EthClient = require('../../src/ethclient').EthClient;
const SubClient = require('../../src/subclient').SubClient;

const polkadotRecipient = "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d";
const polkadotRecipientSS58 = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY";
const polkadotSenderSS58 = polkadotRecipientSS58;
const treasuryAddressSS58 = "5EYCAe5jHEaRUtbinpdbTLuTyGiVt2TJGQPi9fdvVpNLNfSS";
const ethEndpoint = 'ws://localhost:8545';
const parachainEndpoint = 'ws://localhost:11144';
const testNetworkID = '344';

const TestTokenAddress = TestToken.networks[testNetworkID].address;

const ETH_TO_PARA_WAIT_TIME = 60000;
const PARA_TO_ETH_WAIT_TIME = 100000;

async function bootstrap() {
const ethClient = new EthClient(ethEndpoint, testNetworkID);
const subClient = new SubClient(parachainEndpoint);
await subClient.connect();
await ethClient.initialize();
return { ethClient, subClient };
}

module.exports = {
bootstrap, polkadotRecipient,
polkadotRecipientSS58, polkadotSenderSS58, treasuryAddressSS58,
TestTokenAddress,
ETH_TO_PARA_WAIT_TIME, PARA_TO_ETH_WAIT_TIME
};
99 changes: 96 additions & 3 deletions test/src/subclient/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,31 @@ class SubClient {
return BigNumber(balance.toBigInt())
}

async subscribeAssetBalances(accountId, assetId, length) {
// Create an array of promises and resolvers for the balances
const balancePromiseItems = new Array(length).fill().map(i => {
let resolver;
const promise = new Promise(async (resolve, reject) => {
resolver = resolve;
});
return { promise, resolver };
});
const balancePromises = balancePromiseItems.map(i => i.promise);
const resolveBalance = balancePromiseItems.map(i => i.resolver);

// Setup our balance subscription and resolve each promise one by one
let count = 0;
const unsubscribe = await this.api.query.assets.balances(assetId, accountId, newBalance => {
resolveBalance[count](BigNumber(newBalance.toBigInt()));
count++;
if (count === length) {
unsubscribe();
}
});

return balancePromises;
}

async queryAccountBalance(accountId) {
let {
data: {
Expand All @@ -35,16 +60,84 @@ class SubClient {
return BigNumber(balance.toBigInt())
}

async subscribeAccountBalances(accountId, length) {
// Create an array of promises and resolvers for the balances
const balancePromiseItems = new Array(length).fill().map(i => {
let resolver;
const promise = new Promise(async (resolve, reject) => {
resolver = resolve;
});
return { promise, resolver };
});
const balancePromises = balancePromiseItems.map(i => i.promise);
const resolveBalance = balancePromiseItems.map(i => i.resolver);

// Setup our balance subscription and resolve each promise one by one
let count = 0;
const unsubscribe = await this.api.query.system.account(accountId, account => {
let {
data: {
free: balance
}
} = account;
resolveBalance[count](BigNumber(balance.toBigInt()));
count++;
if (count === length) {
unsubscribe();
}
});

return balancePromises;
}

async waitForNextEvent({ eventSection, eventMethod, eventDataType }) {
let foundData = new Promise(async (resolve, reject) => {
const unsubscribe = await this.api.query.system.events((events) => {
events.forEach((record) => {
const { event, phase } = record;
const types = event.typeDef;
if (event.section === eventSection && event.method === eventMethod) {
if (eventDataType === undefined) {
resolve(event.data);
} else {
event.data.forEach((data, index) => {
if (types[index].type === eventDataType) {
unsubscribe();
resolve(data);
}
});
}
}
});
});
});
return foundData;
}

async burnETH(account, recipient, amount, channel) {
const txHash = await this.api.tx.eth.burn(channel, recipient, amount).signAndSend(account);
return await this.api.tx.eth.burn(channel, recipient, amount).signAndSend(account);
}

async burnERC20(account, assetId, recipient, amount, channel) {
const txHash = await this.api.tx.erc20.burn(channel, assetId, recipient, amount).signAndSend(account);
return await this.api.tx.erc20.burn(channel, assetId, recipient, amount).signAndSend(account);
}

async lockDOT(account, recipient, amount, channel) {
const txHash = await this.api.tx.dot.lock(channel, recipient, amount).signAndSend(account);
return await this.api.tx.dot.lock(channel, recipient, amount).signAndSend(account);
}

async waitForNextBlock() {
const wait = new Promise(async (resolve, reject) => {
let count = 0;
const unsubscribe = await this.api.rpc.chain.subscribeNewHeads((header) => {
count++
if (count === 2) {
unsubscribe();
resolve();
}
});
});
return wait;
}

}
Expand Down
92 changes: 92 additions & 0 deletions test/test/dotapp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
const Web3 = require('web3');

const BigNumber = require('bignumber.js');

const { expect } = require("chai")
.use(require("chai-as-promised"))
.use(require("chai-bignumber")(BigNumber))

const { treasuryAddressSS58, polkadotSenderSS58,
polkadotRecipientSS58, polkadotRecipient, bootstrap } = require('../src/fixtures');

describe('Bridge', function () {

let ethClient, subClient;
before(async function () {
const clients = await bootstrap();
ethClient = clients.ethClient;
subClient = clients.subClient;
});

describe('DOT App', function () {

it('should transfer DOT from Substrate to Ethereum', async function () {
const amount = BigNumber('100000000000000'); // 100 DOT (12 decimal places in this environment)
const amountWrapped = BigNumber(Web3.utils.toWei('100', "ether")); // 100 SnowDOT (18 decimal places)
const ethAccount = ethClient.accounts[1];

const beforeEthBalance = await ethClient.getDotBalance(ethAccount);
const beforeSubBalance = await subClient.queryAccountBalance(polkadotSenderSS58);

// lock DOT using basic channel
await subClient.lockDOT(subClient.alice, ethAccount, amount.toFixed(), 0)
await ethClient.waitForNextEventData({ appName: 'snowDOT', eventName: 'Minted' });

const afterEthBalance = await ethClient.getDotBalance(ethAccount);
const afterSubBalance = await subClient.queryAccountBalance(polkadotSenderSS58);

expect(afterEthBalance.minus(beforeEthBalance)).to.be.bignumber.equal(amountWrapped);
expect(beforeSubBalance.minus(afterSubBalance)).to.be.bignumber.greaterThan(amount);
})

it('should transfer DOT from Ethereum to Substrate (basic channel)', async function () {
const amount = BigNumber('1000000000000'); // 1 DOT (12 decimal places in this environment)
const amountWrapped = BigNumber(Web3.utils.toWei('1', "ether")); // 1 SnowDOT (18 decimal places)
const ethAccount = ethClient.accounts[1];
const subBalances = await subClient.subscribeAccountBalances(
polkadotRecipientSS58, 2
);

const beforeEthBalance = await ethClient.getDotBalance(ethAccount);
const beforeSubBalance = await subBalances[0];

await ethClient.burnDOT(ethAccount, amountWrapped, polkadotRecipient, 0);

const afterEthBalance = await ethClient.getDotBalance(ethAccount);
const afterSubBalance = await subBalances[1];

expect(beforeEthBalance.minus(afterEthBalance)).to.be.bignumber.equal(amountWrapped);
expect(afterSubBalance.minus(beforeSubBalance)).to.be.bignumber.equal(amount);
})

it('should transfer DOT from Ethereum to Substrate (incentivized channel)', async function () {
const amount = BigNumber('1000000000000'); // 1 DOT (12 decimal places in this environment)
const amountWrapped = BigNumber(Web3.utils.toWei('1', "ether")); // 1 SnowDOT (18 decimal places)
const ethAccount = ethClient.accounts[1];
const fee = BigNumber(Web3.utils.toWei('1', "ether")) // 1 SnowDOT
const treasuryReward = BigNumber("200000000000") // 0.2 DOT
const subBalances = await subClient.subscribeAccountBalances(
polkadotRecipientSS58, 2
);
const treasuryBalances = await subClient.subscribeAccountBalances(
treasuryAddressSS58, 2
);

const beforeEthBalance = await ethClient.getDotBalance(ethAccount);
const beforeSubBalance = await subBalances[0];
const beforeTreasuryBalance = await treasuryBalances[0];

await ethClient.burnDOT(ethAccount, amountWrapped, polkadotRecipient, 1);

const afterEthBalance = await ethClient.getDotBalance(ethAccount);
const afterSubBalance = await subBalances[1];
const afterTreasuryBalance = await treasuryBalances[1];

expect(beforeEthBalance.minus(afterEthBalance)).to.be.bignumber.equal(amountWrapped.plus(fee));
expect(afterSubBalance.minus(beforeSubBalance)).to.be.bignumber.equal(amount);
expect(afterTreasuryBalance.minus(beforeTreasuryBalance)).to.be.bignumber.equal(treasuryReward);
})

})

});
68 changes: 68 additions & 0 deletions test/test/erc20app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
const BigNumber = require('bignumber.js');

const { expect } = require("chai")
.use(require("chai-as-promised"))
.use(require("chai-bignumber")(BigNumber))

const { TestTokenAddress, polkadotRecipientSS58, polkadotRecipient, bootstrap } = require('../src/fixtures');

describe('Bridge', function () {

let ethClient, subClient;
before(async function () {
const clients = await bootstrap();
ethClient = clients.ethClient;
subClient = clients.subClient;
this.erc20AssetId = subClient.api.createType('AssetId',
{ Token: TestTokenAddress }
);
});

describe('ERC20 App', function () {
it('should transfer ERC20 tokens from Ethereum to Substrate', async function () {
const amount = BigNumber('1000');
const ethAccount = ethClient.accounts[1];
const subBalances = await subClient.subscribeAssetBalances(
polkadotRecipientSS58, this.erc20AssetId, 2
);

const beforeEthBalance = await ethClient.getErc20Balance(ethAccount);
const beforeSubBalance = await subBalances[0];

await ethClient.approveERC20(ethAccount, amount);
await ethClient.lockERC20(ethAccount, amount, polkadotRecipient);

const afterEthBalance = await ethClient.getErc20Balance(ethAccount);
const afterSubBalance = await subBalances[1];

expect(afterEthBalance).to.be.bignumber.equal(beforeEthBalance.minus(amount));
expect(afterSubBalance).to.be.bignumber.equal(beforeSubBalance.plus(amount));

// conservation of value
expect(beforeEthBalance.plus(beforeSubBalance)).to.be.bignumber.equal(afterEthBalance.plus(afterSubBalance));
});

it('should transfer ERC20 from Substrate to Ethereum', async function () {
// Wait for new substrate block before tests, as queries may go to old block
await subClient.waitForNextBlock();

const amount = BigNumber('1000');
const ethAccount = ethClient.accounts[1];

const beforeEthBalance = await ethClient.getErc20Balance(ethAccount);
const beforeSubBalance = await subClient.queryAssetBalance(polkadotRecipientSS58, this.erc20AssetId);

await subClient.burnERC20(subClient.alice, TestTokenAddress, ethAccount, amount.toFixed(), 1)
await ethClient.waitForNextEventData({ appName: 'appERC20', eventName: 'Unlocked' });

const afterEthBalance = await ethClient.getErc20Balance(ethAccount);
const afterSubBalance = await subClient.queryAssetBalance(polkadotRecipientSS58, this.erc20AssetId);

expect(afterEthBalance.minus(beforeEthBalance)).to.be.bignumber.equal(amount);
expect(beforeSubBalance.minus(afterSubBalance)).to.be.bignumber.equal(amount);
// conservation of value
expect(beforeEthBalance.plus(beforeSubBalance)).to.be.bignumber.equal(afterEthBalance.plus(afterSubBalance));
})
})

});
Loading

0 comments on commit 728f0eb

Please sign in to comment.