0.7.0-dev34 • Published 10 months ago

manta-polkawallet-bridge v0.7.0-dev34

Weekly downloads
-
License
Apache-2.0
Repository
github
Last release
10 months ago

Polkadot bridge SDK

Polkadot bridge SDK for multi-chain cross-chain token transfer.

You can integrate the amazing multi-chain bridge into your DApp with this SDK.

And you're welcome to add your parachain-adapter into the SDK.

Supported parachains

Polkadot:

fromtotokens
polkadotacalaDOT
acalapolkadotDOT
acalamoonbeamGLMR ACA AUSD DOT
acalaparallelPARA ACA AUSD LDOT
acalainterlayINTR IBTC
acalaastarASTR ACA AUSD LDOT
acalahydraDXDAI WETH WBTC
parallelacalaPARA ACA AUSD LDOT
interlayacalaINTR IBTC
astaracalaASTR ACA AUSD LDOT
hydraDXacalaDAI WETH WBTC

Kusama:

fromtotokens
kusamakaruraKSM
kusamastatemineKSM
kusamabasiliskKSM
stateminekaruraRMRK ARIS USDT
karurakusamaKSM
karurastatemineRMRK ARIS USDT
karurabifrostBNC KAR AUSD VSKSM
karurashidenSDN AUSD
karuraaltairAIR AUSD
karurashadowCSM KAR AUSD
karuracrabCRAB
karuraintegriteeTEER
karurakintsugiKINT KBTC
karurakhalaPHA KAR AUSD
karurakicoKICO KAR AUSD
karuracalamariKMA KAR AUSD LKSM
karuramoonriverMOVR KAR AUSD
karuraheikoHKO KAR AUSD LKSM
karurapichiuPCHU KAR AUSD LKSM
karuraturingTUR KAR AUSD LKSM
karuraquartzQTZ
karurabasiliskBSX AUSD DAI USDCet
karuralistenLT KAR AUSD LKSM
bifrostkaruraBNC KAR AUSD KSM VSKSM
shidenkaruraSDN AUSD
altairkaruraAIR AUSD
shadowkaruraCSM KAR AUSD
crabkaruraCRAB
integriteekaruraTEER
kintsugikaruraKINT KBTC
khalakaruraPHA KAR AUSD
kicokaruraKICO KAR AUSD
calamarikaruraKMA KAR AUSD KSM LKSM
moonriverkaruraMOVR KAR AUSD
heikokaruraHKO KAR AUSD LKSM
pichiukaruraPCHU KAR AUSD LKSM
turingkaruraTUR KAR AUSD LKSM
quartzkaruraQTZ
basiliskkusamaKSM
basiliskkaruraBSX AUSD KSM DAI
listenkaruraLT KAR AUSD LKSM

Usage

Example: src/bridge.spec.ts

1. initiate the bridge SDK

/// import any parachain-adapters you want in your bridge.
const availableAdapters: Record<string, BaseCrossChainAdapter> = {
  polkadot: new PolkadotAdapter(),
  // kusama: new KusamaAdapter(),
  acala: new AcalaAdapter(),
  // karura: new KaruraAdapter(),
  // statemine: new StatemineAdapter(),
  // bifrost: new BifrostAdapter(),
  // ...
};

/// create your bridge instance and pass the adapters to it.
const bridge = new Bridge({
  adapters: Object.values(availableAdapters),
});

Then you can get the bridge routers:

const allRouters = bridge.router.getRouters();
/// or the available routers (some may temporarily unavailable)
const availableRouters = bridge.router.getAvailableRouters();

/// and get filtered routers
const destChains = bridge.router.getDestinationChains({ from: "acala" });
const tokens = bridge.router.getAvailableTokens({ from: "acala", to: "polkadot" });

2. network connection

You can use the ApiProvider of the SDK which can connect to all the parachains https://polkadot.js.org/apps supported, or you can use your own apiProvider.

import { ApiProvider } from "./api-provider";

const provider = new ApiProvider();

Connect network and pass the ApiPromise | ApiRx into the adapters.

// list all available from-chains
const chains = Object.keys(availableAdapters) as ChainId[];

// connect all adapters
const connected = await firstValueFrom(provider.connectFromChain(chains, undefined));

// and set `ApiPromise | ApiRx` for each adapter
await Promise.all(chains.map((chain) => availableAdapters[chain].init(provider.getApi(chain))));

For ERC20 token of EVM, acala.js introduces an approach to query token balance from EVM with @acala-network/eth-providers. see: src/adapters/acala.spec.ts

import { EvmRpcProvider } from "@acala-network/eth-providers";
import { Wallet } from "@acala-network/sdk";

const provider = new ApiProvider();
const api = provider.getApiPromise("acala");
const evmProvider = new EvmRpcProvider("wss://acala.polkawallet.io");
const wallet = new Wallet(api, { evmProvider });

// by passing a wallet instance with [EvmRpcProvider],
// the [AcalaAdapter] can access the ERC20 token balance in EVM.
const acala = new AcalaAdapter();
await acala.init(api, wallet);

3. token balance query & token transfer

/// balance query
const balance = await firstValueFrom(adapter.subscribeTokenBalance(token, testAccount));

/// and you may want to use the inputConfig provided by the SDK
/// to limit user's transfer amount input
const inputConfig = await firstValueFrom(adapter.subscribeInputConfigs({ to: toChain, token, address: toAddress, signer }));
console.log(inputConfig.minInput, inputConfig.maxInput, inputConfig.destFee, inputConfig.estimateFee, inputConfig.ss58Prefix);

/// create tx & send
const tx = adapter.createTx({
  amount: FixedPointNumber.fromInner("10000000000", 10),
  to: "polkadot",
  token: "DOT",
  address: toAddress,
  signer: testAccount,
});
tx.signAndSend(keyPair, { tip: "0" }, onStatusChangecCallback);

How to integrate your parachain into the bridge sdk

For Substrate parachains

1. Add parachain config

Add a new item in src/configs/chains/polkadot-chains.ts or src/configs/chains/kusama-chains.ts.

/// karura for example
{
  karura: {
    display: "Karura",
    type: typeSubstrate,
    icon: "https://resources.acala.network/_next/image?url=%2Fnetworks%2Fkarura.png&w=96&q=75",
    paraChainId: 2000,
    ss58Prefix: 8,
  }
  /// ...other parachains
}

2. Create adapter for your parachain

Add a new adapter file in src/adapters/, and create your ParachainAdapter class extends BaseCrossChainAdapter.

Example: src/adapters/bifrost.ts

2.1 define tokens and routers
/// bifrost for example
export const bifrostTokensConfig: Record<string, MultiChainToken> = {
  BNC: { name: "BNC", symbol: "BNC", decimals: 12, ed: "10000000000" },
  VSKSM: { name: "VSKSM", symbol: "VSKSM", decimals: 12, ed: "100000000" },
  /// ...other tokens
};
export const bifrostRoutersConfig: Omit<RouteConfigs, "from">[] = [
  /// router for token `BNC` from `bifrost` to `karura`,
  /// `xcm.fee` defines the XCM-Fee on karura,
  /// `xcm.weightLimit` defines the weightLimit value used creating Extrinsic.
  { to: "karura", token: "BNC", xcm: { fee: { token: "BNC", amount: "932400000" }, weightLimit: "Unlimited" } },
  /// router for token `KUSD` from `bifrost` to `karura`
  { to: "karura", token: "KUSD", xcm: { fee: { token: "KUSD", amount: "3826597686" }, weightLimit: "Unlimited" } },
];
2.2 implement public method subscribeTokenBalance()

Implement the subscribeTokenBalance method so the bridge can query token balances.

/// 1. create `BifrostBalanceAdapter` extends `BalanceAdapter`.
class BifrostBalanceAdapter 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> {
    /// ...balance queries
  }
}
/// 2. we use a `createBalanceStorages` function with acala `Storage` utils
///    for token balance queries here.
function createBalanceStorages(api: AnyApi) => {
  return {
    /// balances for native-token (BNC for bifrost)
    balances: (address: string) =>
      Storage.create<any>({
        api,
        path: 'query.system.account',
        params: [address]
      }),
    /// assets for non-native-token (KUSD for bifrost)
    assets: (address: string, token: unknown) =>
      Storage.create<any>({
        api,
        path: "query.tokens.accounts",
        params: [address, token],
      }),
  };
};
/// 3. implement the `subscribeTokenBalance` method
class BaseBifrostAdapter extends BaseCrossChainAdapter {
  private balanceAdapter?: BifrostBalanceAdapter;

  public subscribeTokenBalance (token: string, address: string): Observable<BalanceData> {
    return this.balanceAdapter.subscribeBalance(token, address);
  }
}
2.3 implement public method subscribeMaxInput()

Implement the subscribeMaxInput method so the bridge can set transferable token amount limit.

/// maxInput = availableBalance - estimatedFee - existentialDeposit
class BaseBifrostAdapter extends BaseCrossChainAdapter {
  public subscribeMaxInput(token: string, address: string, to: ChainId): Observable<FN> {
    return combineLatest({
      txFee: token === this.balanceAdapter?.nativeToken ? this.estimateTxFee() : "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));

        return balance.minus(fee).minus(FN.fromInner(tokenMeta?.ed || "0", tokenMeta?.decimals));
      })
    );
  }
}
2.4 implement public method createTx()

Implement the createTx method so the bridge can create the cross-chain transfer Extrinsic.

class BaseBifrostAdapter extends BaseCrossChainAdapter {
  public createTx(
    params: TransferParams
  ): SubmittableExtrinsic<"promise", ISubmittableResult> | SubmittableExtrinsic<"rxjs", ISubmittableResult> {
    const { address, amount, to, token } = params;
    const toChain = chains[to];

    const accountId = this.api?.createType("AccountId32", address).toHex();

    const tokenId = SUPPORTED_TOKENS[token];
    if (!tokenId) {
      throw new TokenNotFound(token);
    }

    return this.api.tx.xTokens.transfer(
      tokenId,
      amount.toChainData(),
      {
        V1: {
          parents: 1,
          interior: { X2: [{ Parachain: toChain.paraChainId }, { AccountId32: { id: accountId, network: "Any" } }] },
        },
      },
      this.getDestWeight(token, to)?.toString()
    );
  }
}
2.5 pass your routers config to your adapter
/// `chains.bifrost` is the config you added in step 1.
/// `bifrostRoutersConfig` & `bifrostTokensConfig` is the config you defined in step 2.1.
export class BifrostAdapter extends BaseBifrostAdapter {
  constructor() {
    super(chains.bifrost, bifrostRoutersConfig, bifrostTokensConfig);
  }
}

And you are all set now!

Additional steps

You can import your ParachainAdapter into src/bridge.spec.ts to test your adapter.

run testing with yarn test.

And remember to run yarn lint before commit your code.

For EVM parachains

TODO

0.6.0-dev8

11 months ago

0.6.0-dev9

11 months ago

0.6.0-dev6

11 months ago

0.6.0-dev7

11 months ago

0.6.0-dev4

11 months ago

0.6.0-dev5

11 months ago

0.6.0-dev2

11 months ago

0.6.0-dev3

11 months ago

0.6.0-dev0

11 months ago

0.6.0-dev1

11 months ago

0.5.2-dev3

12 months ago

1.0.0-dev1

10 months ago

1.0.0-dev2

10 months ago

0.5.3-dev1

11 months ago

0.5.3-dev0

11 months ago

1.0.0-dev0

11 months ago

0.7.0-dev16

10 months ago

0.7.0-dev17

10 months ago

0.7.0-dev18

10 months ago

0.7.0-dev19

10 months ago

0.7.0-dev12

10 months ago

0.5.2-dev1

12 months ago

0.7.0-dev13

10 months ago

0.5.2-dev2

12 months ago

0.7.0-dev14

10 months ago

0.7.0-dev15

10 months ago

0.7.0-dev10

10 months ago

0.5.2

12 months ago

0.7.0-dev11

10 months ago

0.5.1

12 months ago

0.6.0-dev10

11 months ago

0.6.0-dev11

11 months ago

0.6.0-dev12

11 months ago

0.7.0-dev8

10 months ago

0.7.0-dev7

10 months ago

0.7.0-dev9

10 months ago

0.7.0-dev4

10 months ago

0.7.0-dev3

10 months ago

0.7.0-dev6

10 months ago

0.7.0-dev5

10 months ago

0.7.0-dev0

10 months ago

0.7.0-dev2

10 months ago

0.7.0-dev1

10 months ago

0.7.0-dev27

10 months ago

0.7.0-dev28

10 months ago

0.7.0-dev29

10 months ago

0.7.0-dev23

10 months ago

0.7.0-dev24

10 months ago

0.7.0-dev25

10 months ago

0.7.0-dev26

10 months ago

0.7.0-dev20

10 months ago

0.7.0-dev22

10 months ago

0.7.0-dev34

10 months ago

0.7.0-dev30

10 months ago

0.7.0-dev31

10 months ago

0.7.0-dev32

10 months ago

0.7.0-dev33

10 months ago

0.6.0

11 months ago

0.5.1-dev0

1 year ago

0.4.0

1 year ago

0.5.0-dev0

1 year ago

0.2.0-dev1

1 year ago

0.1.0

1 year ago

0.1.0-dev1

1 year ago

0.4.0-dev0

1 year ago

0.3.0

1 year ago

0.2.0-dev

1 year ago

0.0.0

1 year ago