Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transaction router: Same chain #31

Merged
merged 29 commits into from
Jul 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- run: yarn install
- run: 'CI=false yarn build'
- run: yarn lint
test:
asset-registry-test:
runs-on: ubuntu-latest
strategy:
matrix:
Expand All @@ -34,7 +34,21 @@ jobs:
node-version: ${{ matrix.node-version }}
- run: yarn install
- run: 'CI=false yarn build'
- run: yarn test
- run: yarn test -- __tests__/assetRegistry.test.ts
identity-key-test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x, 18.x]
steps:
- uses: actions/[email protected]
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: yarn install
- run: 'CI=false yarn build'
- run: yarn test -- __tests__/identityKey.test.ts

all:
needs: [build]
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,6 @@ package-lock.json

# typescript
*.tsbuildinfo

# zombienet
bin/
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,22 @@ For details regarding the contract deployment go to this [page](https://github.c
2. `yarn install`
3. `yarn dev`
4. Go to `http://localhost:3000` to interact with the webapp
5. To run the unit tests: `yarn test`

### Running tests

Some tests require a zombienet network to be run in the background. The steps to take before running the tests are the following:

1. Run a local [swanky](https://github.com/AstarNetwork/swanky-node) test node. This is where the contracts will be deployed to locally. The command to run: `./swanky-node --dev --tmp`
2. Run the local zombienet network: `zombienet-macos -p native spawn local_network.toml`

After the swanky node and the zombienet is running you can run all the tests:

```
yarn test
```

The tests can take quite some time to run so, in case you want to run a specific test file, run the following command instead:

```
yarn test -- ./__tests__/test_file.test.ts
```
245 changes: 245 additions & 0 deletions __tests__/transactionRouter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
import { ApiPromise, Keyring, WsProvider } from "@polkadot/api";
import { KeyringPair } from "@polkadot/keyring/types";

import TransactionRouter from "../src/utils/transactionRouter";
import IdentityContractFactory from "../types/constructors/identity";
import IdentityContract from "../types/contracts/identity";
import { AccountType, NetworkInfo } from "../types/types-arguments/identity";

const wsProvider = new WsProvider("ws://127.0.0.1:9944");
const keyring = new Keyring({ type: "sr25519" });

describe("TransactionRouter", () => {
let swankyApi: ApiPromise;
let alice: KeyringPair;
let bob: KeyringPair;
let identityContract: any;

beforeEach(async function (): Promise<void> {
swankyApi = await ApiPromise.create({
provider: wsProvider,
noInitWarn: true,
});
alice = keyring.addFromUri("//Alice");
bob = keyring.addFromUri("//Bob");

const factory = new IdentityContractFactory(swankyApi, alice);
identityContract = new IdentityContract(
(await factory.new()).address,
alice,
swankyApi
);
});

it("Can't send tokens to yourself", async () => {
const sender = alice;
const receiver = alice;

// First lets add a network and create an identity.

await addNetwork(identityContract, alice, {
rpcUrl: "ws://127.0.0.1:4242",
accountType: AccountType.accountId32,
});

await expect(
TransactionRouter.sendTokens(
identityContract,
sender,
0, // origin network
receiver.addressRaw,
AccountType.accountId32,
0, // destination network
{}, // multi asset
1000
)
).rejects.toThrow("Cannot send tokens to yourself");
});

it("Sending native asset on the same network works", async () => {
const sender = alice;
const receiver = bob;

const westendProvider = new WsProvider("ws://127.0.0.1:4242");
const westendApi = await ApiPromise.create({ provider: westendProvider });

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const { data: balance } = await westendApi.query.system.account(
receiver.address
);
const receiverBalance = parseInt(balance.free.toHuman().replace(/,/g, ""));

// First lets add a network.
await addNetwork(identityContract, alice, {
rpcUrl: "ws://127.0.0.1:4242",
accountType: AccountType.accountId32,
});

const amount = Math.pow(10, 12);

await TransactionRouter.sendTokens(
identityContract,
sender,
0, // origin network
receiver.addressRaw,
AccountType.accountId32,
0, // destination network
// MultiAsset:
{
interior: "Here",
parents: 0,
},
amount
);

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const { data: balance } = await westendApi.query.system.account(
receiver.address
);
const newReceiverBalance = parseInt(
balance.free.toHuman().replace(/,/g, "")
);

expect(newReceiverBalance).toBe(receiverBalance + amount);
}, 30000);

it("Sending non-native asset on the same network works", async () => {
const sender = alice;
const receiver = bob;

const assetHubProvider = new WsProvider("ws://127.0.0.1:4243");
const assetHubApi = await ApiPromise.create({
provider: assetHubProvider,
});

// First create an asset.
if (!(await getAsset(assetHubApi, 0))) {
await createAsset(assetHubApi, sender, 0);
}

// Mint some assets to the creator.
await mintAsset(assetHubApi, sender, 0, 500);

const amount = 200;

const senderAccountBefore: any = (await assetHubApi.query.assets.account(
0,
sender.address
)).toHuman();

const senderBalanceBefore = parseInt(senderAccountBefore.balance.replace(/,/g, ""));

const receiverAccountBefore: any = (await assetHubApi.query.assets.account(
0,
receiver.address
)).toHuman();

const receiverBalanceBefore = receiverAccountBefore ? parseInt(receiverAccountBefore.balance.replace(/,/g, "")) : 0;

// First lets add a network.
await addNetwork(identityContract, alice, {
rpcUrl: "ws://127.0.0.1:4243",
accountType: AccountType.accountId32,
});

await TransactionRouter.sendTokens(
identityContract,
sender,
0, // origin network
receiver.addressRaw,
AccountType.accountId32,
0, // destination network
// MultiAsset:
{
interior: {
X2: [
{ PalletInstance: 50 }, // assets pallet
{ GeneralIndex: 0 },
],
},
parents: 0,
},
amount
);

const senderAccountAfter: any = (await assetHubApi.query.assets.account(
0,
sender.address
)).toHuman();

const senderBalanceAfter = parseInt(senderAccountAfter.balance.replace(/,/g, ""));

const receiverAccountAfter: any = (await assetHubApi.query.assets.account(
0,
receiver.address
)).toHuman();

const receiverBalanceAfter = parseInt(receiverAccountAfter.balance.replace(/,/g, ""));

expect(senderBalanceAfter).toBe(senderBalanceBefore - amount);
expect(receiverBalanceAfter).toBe(receiverBalanceBefore + amount);

}, 120000);
});

const addNetwork = async (
contract: IdentityContract,
signer: KeyringPair,
network: NetworkInfo
): Promise<void> => {
await contract
.withSigner(signer)
.tx.addNetwork(network);
};

const createAsset = async (
api: ApiPromise,
signer: KeyringPair,
id: number
): Promise<void> => {
const callTx = async (resolve: () => void) => {
const unsub = await api.tx.assets
.create(
id,
// Admin:
signer.address,
10 // min balance
)
.signAndSend(signer, (result: any) => {
if (result.status.isInBlock) {
unsub();
resolve();
}
});
};
return new Promise(callTx);
};

const mintAsset = async (
api: ApiPromise,
signer: KeyringPair,
id: number,
amount: number
): Promise<void> => {
const callTx = async (resolve: () => void) => {
const unsub = await api.tx.assets
.mint(
id,
signer.address, // beneficiary
amount
)
.signAndSend(signer, (result: any) => {
if (result.status.isInBlock) {
unsub();
resolve();
}
});
};
return new Promise(callTx);
};

const getAsset = async (api: ApiPromise, id: number): Promise<any> => {
return (await api.query.assets.asset(id)).toHuman();
};
1 change: 1 addition & 0 deletions artifacts/address_book.contract

Large diffs are not rendered by default.

Loading