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

test: check account balance to ensure transaction result #166

Merged
merged 4 commits into from
Dec 18, 2024
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
13 changes: 13 additions & 0 deletions chopsticks/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ services:
volumes:
- ./pd.yml:/app/config.yml
command: ["chopsticks", "-c", "/app/config.yml", "-p", "8000", "--addr", "0.0.0.0"]
networks:
- kalatori-network

chopsticks-polkadot-2:
build:
Expand All @@ -22,6 +24,8 @@ services:
volumes:
- ./pd-2.yml:/app/config.yml
command: [ "chopsticks", "-c", "/app/config.yml", "-p", "8500", "--addr", "0.0.0.0" ]
networks:
- kalatori-network

chopsticks-statemint:
build:
Expand All @@ -33,6 +37,8 @@ services:
volumes:
- ./pd-ah.yml:/app/config.yml
command: ["chopsticks", "-c", "/app/config.yml", "-p", "9000", "--addr", "0.0.0.0"]
networks:
- kalatori-network

chopsticks-statemint-2:
build:
Expand All @@ -44,3 +50,10 @@ services:
volumes:
- ./pd-ah-2.yml:/app/config.yml
command: [ "chopsticks", "-c", "/app/config.yml", "-p", "9500", "--addr", "0.0.0.0" ]
networks:
- kalatori-network


networks:
kalatori-network:
external: true
2 changes: 1 addition & 1 deletion src/chain/payout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub async fn payout(
let block = block_hash(&client, None).await?; // TODO should retry instead
let block_number = current_block_number(&client, &chain.metadata, &block).await?;
let balance = order.balance(&client, &chain, &block).await?; // TODO same
let loss_tolerance = 10000; // TODO: replace with multiple of existential
let loss_tolerance = 20000; // TODO: replace with multiple of existential
// TODO: add upper limit for transactions that would require manual intervention
// just because it was found to be needed with non-crypto trade, who knows why?
let currency = chain
Expand Down
44 changes: 36 additions & 8 deletions tests/kalatori-api-test-suite/src/polkadot.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';
import { cryptoWaitReady, decodeAddress, encodeAddress } from '@polkadot/util-crypto';

export async function updateAccountBalance(api: ApiPromise, accountAddress: string, amount: bigint): Promise<void> {
const keyring = new Keyring({ type: 'sr25519' });
const alice = keyring.addFromUri('//Alice');

const transfer = api.tx.balances.transfer(accountAddress, amount);
await transfer.signAndSend(alice);
}
import { u32 } from '@polkadot/types';
import type { AccountInfo } from '@polkadot/types/interfaces/system';
import type { AssetBalance } from '@polkadot/types/interfaces/assets';
import { BN } from '@polkadot/util';

export async function connectPolkadot(rpcUrl: string): Promise<ApiPromise> {
const provider = new WsProvider(rpcUrl);
Expand All @@ -16,6 +12,38 @@ export async function connectPolkadot(rpcUrl: string): Promise<ApiPromise> {
return api;
}

export const reverseDecimals = (amount: number, decimals: number): number => {
return amount / Math.pow(10, decimals);
};

export async function getDotBalance(rpcUrl: string, paymentAccount: string): Promise<number> {
const provider = new WsProvider(rpcUrl);
const api = await ApiPromise.create({ provider });

const accountInfo = await api.query.system.account(paymentAccount);

// @ts-ignore
const freeBalance = accountInfo.data.free.toBigInt();

return Number(freeBalance);
}

export async function getAssetBalance(rpcUrl: string, paymentAccount: string, assetId: number): Promise<number> {
const provider = new WsProvider(rpcUrl);
const api = await ApiPromise.create({ provider });
const decodedAccount = decodeAddress(paymentAccount);

// Query the balance for the specified asset and account
const assetIdU32 = new u32(api.registry, assetId);
const accountInfo = (await api.query.assets.account(assetIdU32, decodedAccount)).toJSON() as { balance: number};

if (accountInfo) {
return accountInfo.balance;
} else {
return 0;
}
}

export async function transferFunds(rpcUrl: string, paymentAccount: string, amount: number, assetId?: number) {
const provider = new WsProvider(rpcUrl);
const api = await ApiPromise.create({ provider });
Expand Down
50 changes: 46 additions & 4 deletions tests/kalatori-api-test-suite/tests/order.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import request from 'supertest';
import { connectPolkadot, transferFunds } from '../src/polkadot';
import { ApiPromise } from '@polkadot/api';
import {getAssetBalance, getDotBalance, reverseDecimals, transferFunds} from '../src/polkadot';

describe('Order Endpoint Blackbox Tests', () => {
const baseUrl = process.env.DAEMON_HOST;
Expand All @@ -14,7 +13,7 @@ describe('Order Endpoint Blackbox Tests', () => {
};

const usdcOrderData = {
amount: 1,
amount: 10,
currency: 'USDC',
callback: 'https://example.com/callback'
};
Expand Down Expand Up @@ -254,6 +253,9 @@ describe('Order Endpoint Blackbox Tests', () => {

expect(repaidOrderDetails.payment_status).toBe('paid');
expect(repaidOrderDetails.withdrawal_status).toBe('completed');

const paymentAccountDotBalance = await getDotBalance(orderDetails.currency.rpc_url, paymentAccount);
expect(reverseDecimals(paymentAccountDotBalance,10)).toBe(0);
}, 100000);

it('should create, repay, and automatically withdraw an order in USDC', async () => {
Expand Down Expand Up @@ -283,6 +285,9 @@ describe('Order Endpoint Blackbox Tests', () => {

expect(repaidOrderDetails.payment_status).toBe('paid');
expect(repaidOrderDetails.withdrawal_status).toBe('completed');

const paymentAccountUsdcBalance = await getAssetBalance(orderDetails.currency.rpc_url, paymentAccount, orderDetails.currency.asset_id);
expect(reverseDecimals(paymentAccountUsdcBalance, 6)).toBe(0);
}, 50000);

it('should not automatically withdraw DOT order until fully repaid', async () => {
Expand All @@ -305,6 +310,9 @@ describe('Order Endpoint Blackbox Tests', () => {
// lets wait for the changes to get propagated on chain and app to catch them
await new Promise(resolve => setTimeout(resolve, 15000));

const halfAmountBalance = await getDotBalance(orderDetails.currency.rpc_url, paymentAccount);
expect(reverseDecimals(halfAmountBalance, 10)).toBe(orderDetails.amount/2);

let repaidOrderDetails = await getOrderDetails(orderId);
expect(repaidOrderDetails.payment_status).toBe('pending');
expect(repaidOrderDetails.withdrawal_status).toBe('waiting');
Expand All @@ -323,6 +331,9 @@ describe('Order Endpoint Blackbox Tests', () => {
repaidOrderDetails = await getOrderDetails(orderId);
expect(repaidOrderDetails.payment_status).toBe('paid');
expect(repaidOrderDetails.withdrawal_status).toBe('completed');

const paymentAccountDotBalance = await getDotBalance(orderDetails.currency.rpc_url, paymentAccount);
expect(reverseDecimals(paymentAccountDotBalance, 10)).toBe(0);
}, 100000);

it('should not automatically withdraw USDC order until fully repaid', async () => {
Expand All @@ -345,6 +356,9 @@ describe('Order Endpoint Blackbox Tests', () => {
// lets wait for the changes to get propagated on chain and app to catch them
await new Promise(resolve => setTimeout(resolve, 15000));

const halfAmountBalance = await getAssetBalance(orderDetails.currency.rpc_url, paymentAccount, orderDetails.currency.asset_id);
expect(reverseDecimals(halfAmountBalance, 6)).toBe(halfAmount);

let repaidOrderDetails = await getOrderDetails(orderId);
expect(repaidOrderDetails.payment_status).toBe('pending');
expect(repaidOrderDetails.withdrawal_status).toBe('waiting');
Expand All @@ -363,6 +377,9 @@ describe('Order Endpoint Blackbox Tests', () => {
repaidOrderDetails = await getOrderDetails(orderId);
expect(repaidOrderDetails.payment_status).toBe('paid');
expect(repaidOrderDetails.withdrawal_status).toBe('completed');

const paymentAccountUsdcBalance = await getAssetBalance(orderDetails.currency.rpc_url, paymentAccount, orderDetails.currency.asset_id);
expect(reverseDecimals(paymentAccountUsdcBalance, 6)).toBe(0);
}, 100000);

it('should not update order if received payment in wrong currency', async () => {
Expand Down Expand Up @@ -400,6 +417,9 @@ describe('Order Endpoint Blackbox Tests', () => {
// lets wait for the changes to get propagated on chain and app to catch them
await new Promise(resolve => setTimeout(resolve, 15000));

const halfAmountBalance = await getDotBalance(orderDetails.currency.rpc_url, paymentAccount);
expect(reverseDecimals(halfAmountBalance, 10)).toBe(orderDetails.amount/2);

const partiallyRepaidOrderDetails = await getOrderDetails(orderId);
expect(partiallyRepaidOrderDetails.payment_status).toBe('pending');
expect(partiallyRepaidOrderDetails.withdrawal_status).toBe('waiting');
Expand All @@ -411,6 +431,11 @@ describe('Order Endpoint Blackbox Tests', () => {
let forcedOrderDetails = await getOrderDetails(orderId);
expect(forcedOrderDetails.payment_status).toBe('pending');
expect(forcedOrderDetails.withdrawal_status).toBe('forced');

await new Promise(resolve => setTimeout(resolve, 5000));

const paymentAccountDotBalance = await getDotBalance(orderDetails.currency.rpc_url, paymentAccount);
expect(reverseDecimals(paymentAccountDotBalance, 10)).toBe(0);
}, 100000);

it('should be able to force withdraw partially repayed USDC order', async () => {
Expand All @@ -420,11 +445,22 @@ describe('Order Endpoint Blackbox Tests', () => {
const paymentAccount = orderDetails.payment_account;
expect(paymentAccount).toBeDefined();

await transferFunds(orderDetails.currency.rpc_url, paymentAccount, usdcOrderData.amount/2);
const halfAmount = orderDetails.amount/2;

// Partial repayment
await transferFunds(
orderDetails.currency.rpc_url,
paymentAccount,
halfAmount,
orderDetails.currency.asset_id
);

// lets wait for the changes to get propagated on chain and app to catch them
await new Promise(resolve => setTimeout(resolve, 15000));

const halfAmountBalance = await getAssetBalance(orderDetails.currency.rpc_url, paymentAccount, orderDetails.currency.asset_id);
expect(reverseDecimals(halfAmountBalance, 6)).toBe(halfAmount);

const partiallyRepaidOrderDetails = await getOrderDetails(orderId);
expect(partiallyRepaidOrderDetails.payment_status).toBe('pending');
expect(partiallyRepaidOrderDetails.withdrawal_status).toBe('waiting');
Expand All @@ -433,9 +469,15 @@ describe('Order Endpoint Blackbox Tests', () => {
.post(`/v2/order/${orderId}/forceWithdrawal`);
expect(response.status).toBe(201);

// lets wait for the changes to get propagated on chain and app to catch them
await new Promise(resolve => setTimeout(resolve, 15000));

let forcedOrderDetails = await getOrderDetails(orderId);
expect(forcedOrderDetails.payment_status).toBe('pending');
expect(forcedOrderDetails.withdrawal_status).toBe('forced');

const paymentAccountUsdcBalance = await getAssetBalance(orderDetails.currency.rpc_url, paymentAccount, orderDetails.currency.asset_id);
expect(reverseDecimals(paymentAccountUsdcBalance, 6)).toBe(0);
}, 100000);

it('should return 404 for non-existing order on force withdrawal', async () => {
Expand Down
Loading