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

Feat: add Heiko kbtc #50

Merged
merged 10 commits into from
Mar 1, 2023
177 changes: 100 additions & 77 deletions src/adapters/interlay.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,80 @@ import { ApiProvider } from "../api-provider";
import { chains, ChainName } from "../configs";
import { Bridge } from "..";
import { PolkadotAdapter } from "./polkadot";
import { InterlayAdapter } from "./interlay";
import { InterlayAdapter, KintsugiAdapter } from "./interlay";
import { StatemintAdapter } from "./statemint";
import { HeikoAdapter } from "./parallel";

// helper method for getting balances, configs, fees, and constructing xcm extrinsics
async function runMyTestSuite(testAccount: string, bridge: Bridge, from: ChainName, to: ChainName, token: string) {
const adapter = bridge.findAdapter(from);
if (adapter) {
const balance = await firstValueFrom(
adapter.subscribeTokenBalance(token, testAccount)
);

console.log(
`balance ${token}: free-${balance.free.toNumber()} locked-${balance.locked.toNumber()} available-${balance.available.toNumber()}`
);
expect(balance.available.toNumber()).toBeGreaterThanOrEqual(0);
expect(balance.free.toNumber()).toBeGreaterThanOrEqual(
balance.available.toNumber()
);
expect(balance.free.toNumber()).toEqual(
balance.locked.add(balance.available).toNumber()
);

const toAdapter = bridge.findAdapter(to);
const toBalance = await firstValueFrom(
toAdapter.subscribeTokenBalance(token, testAccount)
);
console.log(
`balance at destination ${token}: free-${toBalance.free.toNumber()} locked-${toBalance.locked.toNumber()} available-${toBalance.available.toNumber()}`
);

const inputConfig = await firstValueFrom(
adapter.subscribeInputConfigs({
to,
token,
address: testAccount,
signer: testAccount,
})
);

console.log(
`inputConfig: min-${inputConfig.minInput.toNumber()} max-${inputConfig.maxInput.toNumber()} ss58-${
inputConfig.ss58Prefix
} estimateFee-${inputConfig.estimateFee}`
);
expect(inputConfig.minInput.toNumber()).toBeGreaterThan(0);
expect(inputConfig.maxInput.toNumber()).toBeLessThanOrEqual(
balance.available.toNumber()
);

const destFee = adapter.getCrossChainFee(token, to);

console.log(
`destFee: fee-${destFee.balance.toNumber()} ${destFee.token}`
);
if (to === "polkadot") {
expect(destFee.balance.toNumber()).toEqual(0.1);
} else {
expect(destFee.balance.toNumber()).toBeGreaterThan(0);
}

const tx = adapter.createTx({
amount: FixedPointNumber.fromInner("10000000000", 10),
to,
token,
address: testAccount,
signer: testAccount,
});

expect(tx.method.section).toEqual("xTokens");
expect(tx.args.length).toEqual(4);
expect(tx.method.method).toEqual("transfer");
}
};

describe.skip("interlay-adapter should work", () => {
jest.setTimeout(30000);
Expand All @@ -19,6 +91,31 @@ describe.skip("interlay-adapter should work", () => {
return firstValueFrom(provider.connectFromChain(chains, undefined));
}

test("connect kintsugi to do xcm", async () => {
const fromChains = ["kintsugi", "heiko"] as ChainName[];

await connect(fromChains);

const kintsugi = new KintsugiAdapter();
const heiko = new HeikoAdapter();

await kintsugi.setApi(provider.getApi(fromChains[0]));
await heiko.setApi(provider.getApi(fromChains[1]));

const bridge = new Bridge({
adapters: [kintsugi, heiko],
});

expect(
bridge.router.getDestinationChains({
from: chains.kintsugi,
token: "KBTC",
}).length
).toEqual(1);

await runMyTestSuite(testAccount, bridge, "kintsugi", "heiko", "KBTC");
});

test("connect interlay to do xcm", async () => {
const fromChains = ["interlay", "polkadot", "statemint"] as ChainName[];

Expand Down Expand Up @@ -50,81 +147,7 @@ describe.skip("interlay-adapter should work", () => {
}).length
).toEqual(1);

const adapter = bridge.findAdapter(fromChains[0]);

async function runMyTestSuit(to: ChainName, token: string) {
if (adapter) {
const balance = await firstValueFrom(
adapter.subscribeTokenBalance(token, testAccount)
);

console.log(
`balance ${token}: free-${balance.free.toNumber()} locked-${balance.locked.toNumber()} available-${balance.available.toNumber()}`
);
expect(balance.available.toNumber()).toBeGreaterThanOrEqual(0);
expect(balance.free.toNumber()).toBeGreaterThanOrEqual(
balance.available.toNumber()
);
expect(balance.free.toNumber()).toEqual(
balance.locked.add(balance.available).toNumber()
);

const toAdapter = bridge.findAdapter(to);
const toBalance = await firstValueFrom(
toAdapter.subscribeTokenBalance(token, testAccount)
);
console.log(
`balance at destination ${token}: free-${toBalance.free.toNumber()} locked-${toBalance.locked.toNumber()} available-${toBalance.available.toNumber()}`
);

const inputConfig = await firstValueFrom(
adapter.subscribeInputConfigs({
to,
token,
address: testAccount,
signer: testAccount,
})
);

console.log(
`inputConfig: min-${inputConfig.minInput.toNumber()} max-${inputConfig.maxInput.toNumber()} ss58-${
inputConfig.ss58Prefix
} estimateFee-${inputConfig.estimateFee}`
);
expect(inputConfig.minInput.toNumber()).toBeGreaterThan(0);
expect(inputConfig.maxInput.toNumber()).toBeLessThanOrEqual(
balance.available.toNumber()
);

const destFee = adapter.getCrossChainFee(token, to);

console.log(
`destFee: fee-${destFee.balance.toNumber()} ${destFee.token}`
);
if (to != "polkadot") {
expect(destFee.balance.toNumber()).toBeGreaterThan(0);
} else {
expect(destFee.balance.toNumber()).toEqual(0.1);
}

const tx = adapter.createTx({
amount: FixedPointNumber.fromInner("10000000000", 10),
to,
token,
address: testAccount,
signer: testAccount,
});

expect(tx.method.section).toEqual("xTokens");
expect(tx.args.length).toEqual(4);
expect(tx.method.method).toEqual("transfer");

expect(tx.args.length).toEqual(4);
expect(tx.method.method).toEqual("transfer");
}
}

await runMyTestSuit("polkadot", "DOT");
await runMyTestSuit("statemint", "USDT");
await runMyTestSuite(testAccount, bridge, "interlay", "polkadot", "DOT");
await runMyTestSuite(testAccount, bridge, "interlay", "statemint", "USDT");
});
});
16 changes: 16 additions & 0 deletions src/adapters/interlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@ export const kintsugiRoutersConfig: Omit<CrossChainRouterConfigs, "from">[] = [
weightLimit: DEST_WEIGHT,
},
},
{
to: "heiko",
token: "KBTC",
xcm: {
// estimated fee calculated from:
// ksm_per_sec = ~233_100_000_000
// kint_per_sec = (ksm_per_second * 4) / 3 = 310_800_000_000
// xcm_secs = ~(247_189_333 / kint_per_sec) ... calculated using a recent kint transaction
// kbtc_per_sec = ksm_per_sec / 1_500_000 ... see https://github.com/interlay/interbtc/blob/18efc1e9194a8591713b9885799a6deb6c0392f2/parachain/runtime/kintsugi/src/xcm_config.rs#L104
// estimated kbtc fee = kbtc_per_sec * xcm_secs = ~123.6
fee: { token: "KBTC", amount: "200" },
weightLimit: DEST_WEIGHT,
},
},
];

export const interlayTokensConfig: Record<
Expand All @@ -68,11 +82,13 @@ export const interlayTokensConfig: Record<
kintsugi: {
KSM: { name: "KSM", symbol: "KSM", decimals: 12, ed: "0" },
USDT: { name: "USDT", symbol: "USDT", decimals: 6, ed: "0" },
KBTC: { name: "KBTC", symbol: "KBTC", decimals: 8, ed: "0" },
},
};

const KINTSUGI_SUPPORTED_TOKENS: Record<string, unknown> = {
KSM: { Token: "KSM" },
KBTC: { Token: "KBTC" },
USDT: { ForeignAsset: 3 },
};

Expand Down
Loading