From f6028be22b2c37cba73ac1f88cabdc6c790b9ceb Mon Sep 17 00:00:00 2001 From: Francisco Gamundi <52399794+fgamundi@users.noreply.github.com> Date: Fri, 17 Mar 2023 15:46:21 +0100 Subject: [PATCH] Support withdraw to chains with Ethereum accounts (#65) * pangoro initial configuration * Support withdraw to chains with Ethereum accounts * Updated param name * Updated tests and snapshots * Review --------- Co-authored-by: Mario J Maurello --- .../src/config/moonbase/assets/paring.ts | 37 +++++++++++++++++ .../src/config/moonbase/moonbase.assets.ts | 14 +++++-- .../src/config/moonbase/moonbase.chains.ts | 11 +++++ .../config/src/config/moonbase/moonbase.ts | 2 + packages/config/src/constants/assets.ts | 1 + packages/config/src/constants/chains.ts | 1 + packages/config/src/interfaces.ts | 3 +- .../__snapshots__/withdraw.test.ts.snap | 31 +++++++++++--- .../src/withdraw/withdraw.interfaces.ts | 5 ++- packages/config/src/withdraw/withdraw.test.ts | 40 ++++++++++++++----- packages/config/src/withdraw/withdraw.ts | 13 +++++- .../XTokensContract/XTokensContract.ts | 10 +++-- 12 files changed, 141 insertions(+), 27 deletions(-) create mode 100644 packages/config/src/config/moonbase/assets/paring.ts diff --git a/packages/config/src/config/moonbase/assets/paring.ts b/packages/config/src/config/moonbase/assets/paring.ts new file mode 100644 index 00000000..7c6eee1d --- /dev/null +++ b/packages/config/src/config/moonbase/assets/paring.ts @@ -0,0 +1,37 @@ +import { AssetSymbol, ChainKey } from '../../../constants'; +import { PolkadotXcmExtrinsicSuccessEvent } from '../../../extrinsic'; +import { + assets, + balance, + chains, + extrinsic, + withdraw, +} from '../moonbase.common'; +import { MoonbaseXcmConfig } from '../moonbase.interfaces'; + +const asset = assets[AssetSymbol.PARING]; +const origin = chains[ChainKey.DarwiniaPangoro]; + +export const PARING: MoonbaseXcmConfig = { + asset, + origin, + deposit: { + [origin.key]: { + source: origin, + balance: balance.system(), + extrinsic: extrinsic + .polkadotXcm() + .limitedReserveTransferAssets() + .successEvent(PolkadotXcmExtrinsicSuccessEvent.Attempted) + .V1V2() + .X1(), + }, + }, + withdraw: { + [origin.key]: withdraw.xTokens({ + balance: balance.system(), + destination: origin, + feePerWeight: 1_000_000_000, + }), + }, +}; diff --git a/packages/config/src/config/moonbase/moonbase.assets.ts b/packages/config/src/config/moonbase/moonbase.assets.ts index 954c9826..898b57cc 100644 --- a/packages/config/src/config/moonbase/moonbase.assets.ts +++ b/packages/config/src/config/moonbase/moonbase.assets.ts @@ -8,6 +8,7 @@ export const MOONBASE_ASSETS = [ AssetSymbol.DEV, AssetSymbol.LIT, AssetSymbol.NEER, + AssetSymbol.PARING, AssetSymbol.TT1, AssetSymbol.UNIT, ]; @@ -39,10 +40,10 @@ export const MOONBASE_ASSETS_MAP: AssetsMap = { erc20Id: '0xffffffff2754f0bdf7eb215503c69204ccd61c5d', originSymbol: AssetSymbol.NEER, }, - [AssetSymbol.UNIT]: { - id: '42259045809535163221576417993425387648', - erc20Id: '0xffffffff1fcacbd218edc0eba20fc2308c778080', - originSymbol: AssetSymbol.UNIT, + [AssetSymbol.PARING]: { + id: '173481220575862801646329923366065693029', + erc20Id: '0xffffffff8283448b3cb519ca4732f2dddc6a6165', + originSymbol: AssetSymbol.PARING, }, [AssetSymbol.TT1]: { id: '156305701417244550631956600137082963628', @@ -52,4 +53,9 @@ export const MOONBASE_ASSETS_MAP: AssetsMap = { [ChainKey.StatemineAlphanet]: 2, }, }, + [AssetSymbol.UNIT]: { + id: '42259045809535163221576417993425387648', + erc20Id: '0xffffffff1fcacbd218edc0eba20fc2308c778080', + originSymbol: AssetSymbol.UNIT, + }, }; diff --git a/packages/config/src/config/moonbase/moonbase.chains.ts b/packages/config/src/config/moonbase/moonbase.chains.ts index 89122d82..44946d51 100644 --- a/packages/config/src/config/moonbase/moonbase.chains.ts +++ b/packages/config/src/config/moonbase/moonbase.chains.ts @@ -6,6 +6,7 @@ export const MOONBASE_CHAINS = [ ChainKey.AlphanetRelay, ChainKey.LitentryAlphanet, ChainKey.BitCountryPioneer, + ChainKey.DarwiniaPangoro, ChainKey.MoonbaseBeta, ChainKey.StatemineAlphanet, ChainKey.UniqueAlpha, @@ -33,6 +34,16 @@ export const MOONBASE_CHAINS_MAP: ChainsMap = { genesisHash: '0xb27da7332d3a229f0d5f2a83f711b3f74a70f22b68021e92c37817057de58e74', }, + [ChainKey.DarwiniaPangoro]: { + key: ChainKey.DarwiniaPangoro, + name: 'Pangoro', + ws: 'wss://pangoro-rpc.darwinia.network', + weight: 1_000_000_000, + parachainId: 2105, + usesEthereumAccounts: true, + genesisHash: + '0xaaa8b33b723b30b44e45e4e6c01936cc92e7559b4184fb0cee2853d55610fcbf', + }, [ChainKey.LitentryAlphanet]: { key: ChainKey.LitentryAlphanet, name: 'Litentry Alphanet', diff --git a/packages/config/src/config/moonbase/moonbase.ts b/packages/config/src/config/moonbase/moonbase.ts index 2ab6ec1e..aba43b73 100644 --- a/packages/config/src/config/moonbase/moonbase.ts +++ b/packages/config/src/config/moonbase/moonbase.ts @@ -6,6 +6,7 @@ import { BIT } from './assets/bit'; import { DEV } from './assets/dev'; import { LIT } from './assets/lit'; import { NEER } from './assets/neer'; +import { PARING } from './assets/paring'; import { TT1 } from './assets/tt1'; import { UNIT } from './assets/unit'; @@ -15,6 +16,7 @@ export const MOONBASE_CONFIGS: MoonbaseXcmConfigs = { [AssetSymbol.DEV]: DEV, [AssetSymbol.LIT]: LIT, [AssetSymbol.NEER]: NEER, + [AssetSymbol.PARING]: PARING, [AssetSymbol.TT1]: TT1, [AssetSymbol.UNIT]: UNIT, }; diff --git a/packages/config/src/constants/assets.ts b/packages/config/src/constants/assets.ts index 41cd88a4..bea34dff 100644 --- a/packages/config/src/constants/assets.ts +++ b/packages/config/src/constants/assets.ts @@ -23,6 +23,7 @@ export enum AssetSymbol { MOVR = 'MOVR', NEER = 'NEER', PARA = 'PARA', + PARING = 'PARING', PHA = 'PHA', RING = 'RING', RMRK = 'RMRK', diff --git a/packages/config/src/constants/chains.ts b/packages/config/src/constants/chains.ts index af191e32..47b6918a 100644 --- a/packages/config/src/constants/chains.ts +++ b/packages/config/src/constants/chains.ts @@ -52,6 +52,7 @@ export enum ChainKey { Crab = 'Crab', CrustShadow = 'CrustShadow', Darwinia = 'Darwinia', + DarwiniaPangoro = 'DarwiniaPangoro', Integritee = 'Integritee', Interlay = 'Interlay', Karura = 'Karura', diff --git a/packages/config/src/interfaces.ts b/packages/config/src/interfaces.ts index 85493556..f010ec5e 100644 --- a/packages/config/src/interfaces.ts +++ b/packages/config/src/interfaces.ts @@ -49,7 +49,8 @@ export interface Chain * unitsPerSecond = weightPerSecond * baseExtrinsicCost / baseExtrinsicWeight */ unitsPerSecond?: bigint; - ss58Format: number; + ss58Format?: number; + usesEthereumAccounts?: boolean; genesisHash: string; } diff --git a/packages/config/src/withdraw/__snapshots__/withdraw.test.ts.snap b/packages/config/src/withdraw/__snapshots__/withdraw.test.ts.snap index 70e46c81..4ee40884 100644 --- a/packages/config/src/withdraw/__snapshots__/withdraw.test.ts.snap +++ b/packages/config/src/withdraw/__snapshots__/withdraw.test.ts.snap @@ -1,10 +1,29 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`withdraw xTokens eth account should get params with parachain id 1`] = ` +[ + 1, + [ + "0x000000064", + "0x03ef46c7649270c912704fb09b75097f6e32208b8500", + ], +] +`; + +exports[`withdraw xTokens eth account should get params without parachain id 1`] = ` +[ + 1, + [ + "0x03ef46c7649270c912704fb09b75097f6e32208b8500", + ], +] +`; + exports[`withdraw xTokens should be correct withdraw config 1`] = ` { "balance": "", "destination": { - "parachainId": 1000, + "parachainId": 100, }, "feePerWeight": 8, "getParams": [Function], @@ -14,21 +33,21 @@ exports[`withdraw xTokens should be correct withdraw config 1`] = ` } `; -exports[`withdraw xTokens should get params with parachain id 1`] = ` +exports[`withdraw xTokens substrate account should get params with parachain id 1`] = ` [ 1, [ - "0x00000003e8", - "0x01ef46c7649270c912704fb09b75097f6e32208b8500", + "0x000000064", + "0x01c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300", ], ] `; -exports[`withdraw xTokens should get params without parachain id 1`] = ` +exports[`withdraw xTokens substrate account should get params without parachain id 1`] = ` [ 1, [ - "0x01ef46c7649270c912704fb09b75097f6e32208b8500", + "0x01c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300", ], ] `; diff --git a/packages/config/src/withdraw/withdraw.interfaces.ts b/packages/config/src/withdraw/withdraw.interfaces.ts index 6b3919b7..0cbd6bf9 100644 --- a/packages/config/src/withdraw/withdraw.interfaces.ts +++ b/packages/config/src/withdraw/withdraw.interfaces.ts @@ -15,7 +15,10 @@ export interface WithdrawXTokensConfig< sourceMinBalance?: MinBalanceConfig; xcmFeeAsset?: WithdrawXcmFeeAsset; weight: number; - getParams: (account: string) => WithdrawXTokensParams; + getParams: ( + account: string, + usesEthereumAccounts: boolean | undefined, + ) => WithdrawXTokensParams; } export type WithdrawXTokensParams = [ diff --git a/packages/config/src/withdraw/withdraw.test.ts b/packages/config/src/withdraw/withdraw.test.ts index 469852d3..c4241c80 100644 --- a/packages/config/src/withdraw/withdraw.test.ts +++ b/packages/config/src/withdraw/withdraw.test.ts @@ -1,32 +1,52 @@ import { createWithdrawBuilder } from './withdraw'; describe('withdraw', () => { - const account = '0xeF46c7649270C912704fB09B75097f6E32208b85'; const withdraw = createWithdrawBuilder(); describe('xTokens', () => { const cfg = withdraw.xTokens({ balance: '' as any, - destination: { parachainId: 1000 } as any, + destination: { parachainId: 100 } as any, feePerWeight: 8, }); it('should be correct withdraw config', () => { expect(cfg).toMatchSnapshot(); }); + describe('substrate account', () => { + const account = '5GWpSdqkkKGZmdKQ9nkSF7TmHp6JWt28BMGQNuG4MXtSvq3e'; - it('should get params with parachain id', () => { - expect(cfg.getParams(account)).toMatchSnapshot(); + it('should get params with parachain id', () => { + expect(cfg.getParams(account, false)).toMatchSnapshot(); + }); + + it('should get params without parachain id', () => { + const cfg2 = withdraw.xTokens({ + balance: '' as any, + destination: {} as any, + feePerWeight: 8, + }); + + expect(cfg2.getParams(account, false)).toMatchSnapshot(); + }); }); - it('should get params without parachain id', () => { - const cfg2 = withdraw.xTokens({ - balance: '' as any, - destination: {} as any, - feePerWeight: 8, + describe('eth account', () => { + const account = '0xeF46c7649270C912704fB09B75097f6E32208b85'; + + it('should get params with parachain id', () => { + expect(cfg.getParams(account, true)).toMatchSnapshot(); }); - expect(cfg2.getParams(account)).toMatchSnapshot(); + it('should get params without parachain id', () => { + const cfg2 = withdraw.xTokens({ + balance: '' as any, + destination: {} as any, + feePerWeight: 8, + }); + + expect(cfg2.getParams(account, true)).toMatchSnapshot(); + }); }); }); }); diff --git a/packages/config/src/withdraw/withdraw.ts b/packages/config/src/withdraw/withdraw.ts index dea19109..b52257a9 100644 --- a/packages/config/src/withdraw/withdraw.ts +++ b/packages/config/src/withdraw/withdraw.ts @@ -31,9 +31,18 @@ function xTokens({ sourceMinBalance, xcmFeeAsset, weight, - getParams: (account: string) => { + getParams: (account: string, usesEthereumAccounts = false) => { const { parachainId } = destination; - const acc = `0x01${u8aToHex(decodeAddress(account), -1, false)}00`; + // 01: AccountId32 + // 03: AccountKey20 + // https://docs.moonbeam.network/builders/interoperability/xcm/xc20/xtokens/#building-the-precompile-multilocation + const accountType = usesEthereumAccounts ? '03' : '01'; + + const acc = `0x${accountType}${u8aToHex( + decodeAddress(account), + -1, + false, + )}00`; return [ 1, diff --git a/packages/sdk/src/contracts/XTokensContract/XTokensContract.ts b/packages/sdk/src/contracts/XTokensContract/XTokensContract.ts index 124be3d9..68a79781 100644 --- a/packages/sdk/src/contracts/XTokensContract/XTokensContract.ts +++ b/packages/sdk/src/contracts/XTokensContract/XTokensContract.ts @@ -27,6 +27,9 @@ export class XTokensContract { config: WithdrawXTokensConfig, minAmount: bigint, ): Promise { + const { usesEthereumAccounts } = config.destination; + const params = config.getParams(account, usesEthereumAccounts); + if (config.xcmFeeAsset) { return this.#contract.transferMultiCurrencies( [ @@ -34,14 +37,15 @@ export class XTokensContract { [asset.erc20Id, amount], ], 0, - config.getParams(account), + params, config.weight, ); } + return this.#contract.transfer( asset.erc20Id, amount, - config.getParams(account), + params, config.weight, ); } @@ -56,7 +60,7 @@ export class XTokensContract { await this.#contract.estimateGas.transfer( asset.erc20Id, amount, - config.getParams(account), + config.getParams(account, config.destination.usesEthereumAccounts), config.weight, ) ).toBigInt();