Skip to content

Commit

Permalink
feat: add phala adapter and starter configs
Browse files Browse the repository at this point in the history
  • Loading branch information
bvotteler committed Jul 4, 2024
1 parent 793591b commit c4d3a25
Show file tree
Hide file tree
Showing 6 changed files with 334 additions and 3 deletions.
1 change: 1 addition & 0 deletions .github/workflows/xcm-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ jobs:
-p scripts/configs/acala.yml \
-p scripts/configs/astar.yml \
-p scripts/configs/bifrost-polkadot.yml \
-p scripts/configs/phala.yml \
&> log.txt &
echo "Waiting for log to show chopsticks is ready..."
tail -f log.txt | grep -q "Connected parachains"
Expand Down
26 changes: 26 additions & 0 deletions scripts/configs/phala.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
endpoint:
- wss://api.phala.network/ws
- wss://phala-rpc.dwellir.com
mock-signature-host: true

import-storage:
System:
Account:
-
-
- 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY # Alice
- providers: 1
data:
free: '1000000000000000'
Assets:
Account:
-
-
- 14 # IBTC
- 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY # Alice
- balance: '1000000000000000'
-
-
- 13 # INTR
- 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY # Alice
- balance: '1000000000000000'
6 changes: 3 additions & 3 deletions scripts/interlay-chopsticks-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { InterlayAdapter } from "../src/adapters/interlay";
import { HydraAdapter } from "../src/adapters/hydradx";
import { AcalaAdapter } from "../src/adapters/acala";
import { AstarAdapter } from "../src/adapters/astar";
// import { ParallelAdapter } from "../src/adapters/parallel";
import { BifrostPolkadotAdapter } from "../src/adapters/bifrost";
import { PhalaAdapter } from "../src/adapters/phala";
import { BaseCrossChainAdapter } from "../src/base-chain-adapter";
import { RouterTestCase, runTestCasesAndExit } from "./chopsticks-test";

Expand All @@ -27,9 +27,9 @@ async function main(): Promise<void> {
hydra: { adapter: new HydraAdapter(), endpoints: ['ws://127.0.0.1:8001'] },
acala: { adapter: new AcalaAdapter(), endpoints: ['ws://127.0.0.1:8002'] },
astar: { adapter: new AstarAdapter(), endpoints: ['ws://127.0.0.1:8003'] },
// parallel: { adapter: new ParallelAdapter(), endpoints: ['ws://127.0.0.1:8004'] },
bifrost_polkadot: { adapter: new BifrostPolkadotAdapter(), endpoints: ['ws://127.0.0.1:8004']},
polkadot: { adapter: new PolkadotAdapter(), endpoints: ['ws://127.0.0.1:8005'] },
phala: { adapter: new PhalaAdapter(), endpoints: ['ws://127.0.0.1:8005']},
polkadot: { adapter: new PolkadotAdapter(), endpoints: ['ws://127.0.0.1:8006'] },
};

const skipCases: Partial<RouterTestCase>[] = [
Expand Down
15 changes: 15 additions & 0 deletions src/adapters/interlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,21 @@ export const interlayRoutersConfig: Omit<CrossChainRouterConfigs, "from">[] = [
// during chopsticks test: fee = 103 Add 10x margin
xcm: { fee: { token: "IBTC", amount: "1030" }, weightLimit: DEST_WEIGHT },
},
{
to: "phala",
token: "INTR",
xcm: {
// TODO: get chopsticks test data: fee = 6_535_947_712 Add 10x margin
fee: { token: "INTR", amount: "65359477120" },
weightLimit: DEST_WEIGHT,
},
},
{
to: "phala",
token: "IBTC",
// TODO: get chopsticks test: fee = 103 Add 10x margin
xcm: { fee: { token: "IBTC", amount: "1030" }, weightLimit: DEST_WEIGHT },
},
{
to: "polkadot",
token: "DOT",
Expand Down
281 changes: 281 additions & 0 deletions src/adapters/phala.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
import { Storage } from "@acala-network/sdk/utils/storage";
import { AnyApi, FixedPointNumber as FN } from "@acala-network/sdk-core";
import { combineLatest, map, Observable } from "rxjs";

import { SubmittableExtrinsic } from "@polkadot/api/types";
import { DeriveBalancesAll } from "@polkadot/api-derive/balances/types";
import { ISubmittableResult } from "@polkadot/types/types";

import { BalanceAdapter, BalanceAdapterConfigs } from "../balance-adapter";
import { BaseCrossChainAdapter } from "../base-chain-adapter";
import { ChainName, chains } from "../configs";
import { ApiNotFound, CurrencyNotFound } from "../errors";
import {
BalanceData,
CrossChainRouterConfigs,
CrossChainTransferParams,
ExtendedToken,
} from "../types";

const DEST_WEIGHT = "Unlimited";
type TokenData = ExtendedToken & { toQuery: () => string };

export const phalaRoutersConfig: Omit<CrossChainRouterConfigs, "from">[] = [
{
to: "interlay",
token: "IBTC",
xcm: {
// during chopsticks test: fee = 71 Add 10x margin
fee: { token: "IBTC", amount: "710" },
weightLimit: DEST_WEIGHT,
},
},
{
to: "interlay",
token: "INTR",
xcm: {
// during chopsticks test: fee = 21_660_472 Add 10x margin
fee: { token: "INTR", amount: "216604720" },
weightLimit: DEST_WEIGHT,
},
},
];

export const phalaTokensConfig: Record<

Check failure on line 44 in src/adapters/phala.ts

View workflow job for this annotation

GitHub Actions / lint

Replace `⏎··string,⏎··Record<string,·TokenData>⏎` with `string,·Record<string,·TokenData>`
string,
Record<string, TokenData>
> = {
phala: {
PHA: {
name: "PHA",
symbol: "PHA",
decimals: 12,
ed: "10000000000",
} as TokenData,
// ed confirmed via assets.asset(<id>)
IBTC: {
name: "IBTC",
symbol: "IBTC",
decimals: 8,
ed: "1,000,000",
toRaw: () =>
"0x0001000000000000000000000000000000000000000000000000000000000000",
toQuery: () => "14",
},
INTR: {
name: "INTR",
symbol: "INTR",
decimals: 10,
ed: "100,000,000",
toRaw: () =>
"0x0002000000000000000000000000000000000000000000000000000000000000",
toQuery: () => "13",
},
},
};

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
const createBalanceStorages = (api: AnyApi) => {
return {
balances: (address: string) =>
Storage.create<DeriveBalancesAll>({
api,
path: "derive.balances.all",
params: [address],
}),
assets: (tokenId: string, address: string) =>
Storage.create<any>({
api,
path: "query.assets.account",
params: [tokenId, address],
}),
};
};

class PhalaBalanceAdapter extends BalanceAdapter {
private storages: ReturnType<typeof createBalanceStorages>;

constructor({ api, chain, tokens }: BalanceAdapterConfigs) {
super({ api, chain, tokens });
this.storages = createBalanceStorages(api);
}

public subscribeBalance(
token: string,
address: string
): Observable<BalanceData> {
const storage = this.storages.balances(address);

if (token === this.nativeToken) {
return storage.observable.pipe(
map((data) => ({
free: FN.fromInner(data.freeBalance.toString(), this.decimals),
locked: FN.fromInner(data.lockedBalance.toString(), this.decimals),
reserved: FN.fromInner(
data.reservedBalance.toString(),
this.decimals
),
available: FN.fromInner(
data.availableBalance.toString(),
this.decimals
),
}))
);
}

const tokenData: TokenData = this.getToken(token);

if (!tokenData) {
throw new CurrencyNotFound(token);
}

return this.storages.assets(tokenData.toQuery(), address).observable.pipe(
map((balance) => {
const amount = FN.fromInner(
balance.unwrapOrDefault()?.balance?.toString() || "0",
this.getToken(token).decimals
);

return {
free: amount,
locked: new FN(0),
reserved: new FN(0),
available: amount,
};
})
);
}
}

class BasePhalaAdapter extends BaseCrossChainAdapter {
private balanceAdapter?: PhalaBalanceAdapter;

public override async setApi(api: AnyApi) {
this.api = api;

await api.isReady;

const chain = this.chain.id as ChainName;

this.balanceAdapter = new PhalaBalanceAdapter({
chain,
api,
tokens: phalaTokensConfig[chain],
});
}

public subscribeTokenBalance(
token: string,
address: string
): Observable<BalanceData> {
if (!this.balanceAdapter) {
throw new ApiNotFound(this.chain.id);
}

return this.balanceAdapter.subscribeBalance(token, address);
}

public subscribeMaxInput(
token: string,
address: string,
to: ChainName
): Observable<FN> {
if (!this.balanceAdapter) {
throw new ApiNotFound(this.chain.id);
}

return combineLatest({
txFee:
token === this.balanceAdapter?.nativeToken
? this.estimateTxFee({
amount: FN.ZERO,
to,
token,
address,
signer: address,
})
: "0",
balance: this.balanceAdapter
.subscribeBalance(token, address)
.pipe(map((i) => i.available)),
}).pipe(
map(({ balance, txFee }) => {
const tokenMeta = this.balanceAdapter?.getToken(token);
const feeFactor = 1.2;
const fee = FN.fromInner(txFee, tokenMeta?.decimals).mul(
new FN(feeFactor)
);

// always minus ed
return balance
.minus(fee)
.minus(FN.fromInner(tokenMeta?.ed || "0", tokenMeta?.decimals));
})
);
}

public createTx(
params: CrossChainTransferParams
):
| SubmittableExtrinsic<"promise", ISubmittableResult>
| SubmittableExtrinsic<"rxjs", ISubmittableResult> {
if (!this.api) {
throw new ApiNotFound(this.chain.id);
}

const { address, amount, to, token } = params;

const accountId = this.api?.createType("AccountId32", address).toHex();
const toChain = chains[to];

const dst = {
parents: 1,
interior: {
X2: [
{ Parachain: toChain.paraChainId },
{ AccountId32: { id: accountId } },
],
},
};

let asset: any = {
id: { Concrete: { parents: 0, interior: "Here" } },
fun: { Fungible: amount.toChainData() },
};

const tokenData: TokenData = this.getToken(token);

if (!tokenData) {
throw new CurrencyNotFound(token);
}

if (token !== this.balanceAdapter?.nativeToken) {
asset = {
id: {
Concrete: {
parents: 1,
interior: {
X2: [
{ Parachain: toChain.paraChainId },
{ GeneralKey: { length: 2, data: tokenData.toRaw() } },
],
},
},
},
fun: { Fungible: amount.toChainData() },
};
}

return this.api.tx.xTransfer.transfer(asset, dst, undefined);
}
}

export class PhalaAdapter extends BasePhalaAdapter {
constructor() {
super(

Check failure on line 275 in src/adapters/phala.ts

View workflow job for this annotation

GitHub Actions / lint

Replace `⏎······chains.phala,⏎······phalaRoutersConfig,⏎······phalaTokensConfig.parallel⏎····` with `chains.phala,·phalaRoutersConfig,·phalaTokensConfig.parallel`
chains.phala,
phalaRoutersConfig,
phalaTokensConfig.parallel
);
}
}
8 changes: 8 additions & 0 deletions src/configs/chains/polkadot-chains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,12 @@ export const polkadotChains = {
paraChainId: 2034,
ss58Prefix: 63,
},
phala: {
id: "phala",
display: "Phala",
type: typeSubstrate,
icon: "",
paraChainId: 2035,
ss58Prefix: 30,
},
};

0 comments on commit c4d3a25

Please sign in to comment.