Skip to content
Open
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
19 changes: 10 additions & 9 deletions packages/xc-cfg/src/resolvers/hydration.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { EvmResolver } from '@galacticcouncil/xc-core';
import { getSs58AddressInfo } from '@polkadot-api/substrate-bindings';
import { h160 } from '@galacticcouncil/common';

const ETH_PREFIX = 'ETH\0';
const { H160, isEvmAccount } = h160;

export class HydrationEvmResolver implements EvmResolver {
async toH160(ss58Addr: string): Promise<string> {
const info = getSs58AddressInfo(ss58Addr);
if (!info.isValid) {
throw new Error(`Invalid SS58 address: ${ss58Addr}`);
if (!isEvmAccount(ss58Addr)) {
throw new Error(
`SS58 address is not an EVM-derived account: ${ss58Addr}`
);
}
return H160.fromAccount(ss58Addr);
}

const decodedBytes = info.publicKey;
const prefixBytes = Buffer.from(ETH_PREFIX);
const addressBytes = decodedBytes.slice(prefixBytes.length, -8);
return '0x' + Buffer.from(addressBytes).toString('hex');
async toSS58(h160Addr: string): Promise<string> {
return H160.toAccount(h160Addr);
}
}
17 changes: 15 additions & 2 deletions packages/xc-core/src/chain/EvmParachain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Wormhole, WormholeDef } from '../bridge';
import { EvmClient, EvmResolver } from '../evm';
import { addr } from '../utils';

const { EvmAddr } = addr;
const { EvmAddr, Ss58Addr } = addr;

export interface EvmParachainParams extends ParachainParams {
evmChain: EvmChainDef;
Expand Down Expand Up @@ -52,6 +52,19 @@ export class EvmParachain extends Parachain {
if (this.evmResolver) {
return this.evmResolver.toH160(address, this.client);
}
throw new Error(`No EVM resolver found for ` + this.name);

return address;
}

async getSubstrateAddress(address: string): Promise<string> {
if (Ss58Addr.isValid(address)) {
return address;
}

if (this.evmResolver) {
return this.evmResolver.toSS58(address, this.client);
}

return address;
}
}
1 change: 1 addition & 0 deletions packages/xc-core/src/evm/EvmResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ import { PolkadotClient } from 'polkadot-api';

export interface EvmResolver {
toH160(ss58Addr: string, api?: PolkadotClient): Promise<string>;
toSS58(h160Addr: string, api?: PolkadotClient): Promise<string>;
}
19 changes: 7 additions & 12 deletions packages/xc-sdk/src/Wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,16 @@ import {
SubstrateService,
} from './platforms';
import {
buildBalanceConfig,
calculateMax,
calculateMin,
formatEvmAddress,
DataOriginProcessor,
DataReverseProcessor,
} from './transfer';
import { Transfer } from './types';

import { FeeSwap } from './FeeSwap';

const { EvmAddr } = addr;

export interface WalletOptions {
configService: ConfigService;
transferValidations?: TransferValidation[];
Expand Down Expand Up @@ -264,15 +262,12 @@ export class Wallet {
.getUniqueRoutes()
.map(async ({ source }) => {
const { asset, balance } = source;
const assetId = chainRoutes.chain.getBalanceAssetId(asset);
const account = EvmAddr.isValid(assetId.toString())
? await formatEvmAddress(address, chainRoutes.chain)
: address;
const balanceConfig = balance.build({
address: account,
asset: asset,
chain: chainRoutes.chain,
});
const balanceConfig = await buildBalanceConfig(
balance,
address,
asset,
chainRoutes.chain
);
return adapter.subscribeBalance(asset, balanceConfig);
});

Expand Down
90 changes: 45 additions & 45 deletions packages/xc-sdk/src/transfer/DataOriginProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
addr,
Asset,
AssetAmount,
CallType,
FeeAmountConfigBuilder,
FeeAssetConfigBuilder,
Parachain,
Expand All @@ -12,22 +13,20 @@ import {
} from '@galacticcouncil/xc-core';
import { acc, big } from '@galacticcouncil/common';

import { formatAmount, formatEvmAddress } from './utils';
import { buildBalanceConfig, formatAmount, resolveAddress } from './utils';
import { Call, PlatformAdapter, SubstrateService } from '../platforms';

import { DataProcessor } from './DataProcessor';

const { EvmAddr } = addr;

export class DataOriginProcessor extends DataProcessor {
constructor(adapter: PlatformAdapter, config: TransferConfig) {
super(adapter, config);
}

async getCall(ctx: TransferCtx): Promise<Call> {
const { amount, sender, source } = ctx;
const transfer = await this.getTransfer(ctx);
return this.adapter.buildCall(sender, amount, source.feeBalance, transfer);
const { amount, source } = ctx;
const { transfer, account } = await this.getTransfer(ctx);
return this.adapter.buildCall(account, amount, source.feeBalance, transfer);
}

async getDestinationFee(): Promise<{
Expand Down Expand Up @@ -82,35 +81,28 @@ export class DataOriginProcessor extends DataProcessor {
return this.getBalance(address);
}

const feeAssetId = chain.getBalanceAssetId(feeAsset);
const account = EvmAddr.isValid(feeAssetId.toString())
? await formatEvmAddress(address, chain)
: address;
const feeBalanceConfig = source.destinationFee.balance.build({
address: account,
asset: feeAsset,
chain: chain,
});
const feeBalanceConfig = await buildBalanceConfig(
source.destinationFee.balance,
address,
feeAsset,
chain
);
return this.adapter.getBalance(feeAsset, feeBalanceConfig);
}

async getFee(ctx: TransferCtx): Promise<AssetAmount> {
const { chain, route } = this.config;
const { amount, sender, source } = ctx;
const { amount, source } = ctx;

const transfer = await this.getTransfer(ctx);
const address = route.contract
? await formatEvmAddress(sender, chain)
: sender;
const { transfer, account } = await this.getTransfer(ctx);

const networkFee = await this.adapter.estimateFee(
address,
account,
amount,
source.feeBalance,
transfer
);

const { fee } = route.source;
const { fee } = this.config.route.source;
const extraFee = fee ? formatAmount(networkFee.decimals, fee.extra) : 0n;
const totalFee = networkFee.amount + extraFee;
return networkFee.copyWith({ amount: totalFee });
Expand All @@ -124,17 +116,18 @@ export class DataOriginProcessor extends DataProcessor {
return this.getBalance(address);
}

const feeAsset = await this.getFeeAsset(address);
const feeAssetId = chain.getBalanceAssetId(feeAsset);
const account = EvmAddr.isValid(feeAssetId.toString())
? await formatEvmAddress(address, chain)
: address;
const feeBalanceConfig = source.fee.balance.build({
address: account,
asset: feeAsset,
chain: chain,
});

const substrateAddr = await resolveAddress(
address,
chain,
CallType.Substrate
);
const feeAsset = await this.getFeeAsset(substrateAddr);
const feeBalanceConfig = await buildBalanceConfig(
source.fee.balance,
address,
feeAsset,
chain
);
return this.adapter.getBalance(feeAsset, feeBalanceConfig);
}

Expand Down Expand Up @@ -167,23 +160,25 @@ export class DataOriginProcessor extends DataProcessor {
if (extrinsic) {
const { address, amount, asset, sender } = ctx;
const substrate = await SubstrateService.create(chain as Parachain);
const account = await resolveAddress(sender, chain, CallType.Substrate);
const messageId = await substrate.buildMessageId(
sender,
account,
amount,
asset.originSymbol,
address
);
return extrinsic.build({
const transfer = await extrinsic.build({
...ctx,
messageId: messageId,
});
return { transfer, account };
}

const callable = contract || program || move;
if (callable) {
return callable.build({
...ctx,
});
const transfer = await callable.build({ ...ctx });
const account = await resolveAddress(ctx.sender, chain, transfer.type);
return { transfer, account };
}

throw new Error(
Expand Down Expand Up @@ -234,7 +229,11 @@ export class DataOriginProcessor extends DataProcessor {
const submittable = config.getTx(substrate.client);

const fromChain = ctx.source.chain as Parachain;
const fromAddr = ctx.sender;
const fromAddr = await resolveAddress(
ctx.sender,
fromChain,
CallType.Substrate
);

const mda = acc.getMultilocationDerivatedAccount(
fromChain.parachainId,
Expand Down Expand Up @@ -292,11 +291,12 @@ export class DataOriginProcessor extends DataProcessor {
): Promise<AssetAmount> {
const { chain } = this.config;
const { fee } = cfg;
const feeBalanceConfig = fee.balance.build({
address: ctx.sender,
asset: fee.asset,
chain: chain,
});
const feeBalanceConfig = await buildBalanceConfig(
fee.balance,
ctx.sender,
fee.asset,
chain
);
return this.adapter.getBalance(fee.asset, feeBalanceConfig);
}
}
22 changes: 7 additions & 15 deletions packages/xc-sdk/src/transfer/DataProcessor.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import {
addr,
Asset,
AssetAmount,
Parachain,
TransferConfig,
} from '@galacticcouncil/xc-core';
import { big } from '@galacticcouncil/common';

import { formatEvmAddress } from './utils';
import { buildBalanceConfig } from './utils';
import { PlatformAdapter, SubstrateService } from '../platforms';

const { EvmAddr } = addr;

export abstract class DataProcessor {
readonly adapter: PlatformAdapter;
readonly config: TransferConfig;
Expand All @@ -36,17 +33,12 @@ export abstract class DataProcessor {
const { source } = route;

const asset = source.asset;

const assetId = chain.getBalanceAssetId(asset);
const account = EvmAddr.isValid(assetId.toString())
? await formatEvmAddress(address, chain)
: address;
const balanceConfig = route.source.balance.build({
address: account,
asset: asset,
chain: chain,
});

const balanceConfig = await buildBalanceConfig(
route.source.balance,
address,
asset,
chain
);
return this.adapter.getBalance(asset, balanceConfig);
}

Expand Down
43 changes: 37 additions & 6 deletions packages/xc-sdk/src/transfer/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { AnyChain, AssetAmount, EvmParachain } from '@galacticcouncil/xc-core';
import {
AnyChain,
Asset,
AssetAmount,
BalanceConfigBuilder,
CallType,
EvmParachain,
} from '@galacticcouncil/xc-core';
import { big } from '@galacticcouncil/common';

import Big from 'big.js';
Expand Down Expand Up @@ -74,23 +81,47 @@ export function calculateMin(
}

/**
* Return h160 derivated address in case of Evm parachain
* Resolve address to the format required by the given CallType
* on dual-address-space (EvmParachain) chains.
*
*
* @param address - h160 or ss58 address format
* @param chain - transfer chain ctx
* @returns - derivated address if evm resolver defined, fallback to default
* @param callType - target format needed (Evm or Substrate)
* @returns address in the correct format
*/
export async function formatEvmAddress(
export async function resolveAddress(
address: string,
chain: AnyChain
chain: AnyChain,
callType: CallType
): Promise<string> {
if (chain.isEvmParachain()) {
const evmParachain = chain as EvmParachain;
return evmParachain.getDerivatedAddress(address);
return callType === CallType.Evm
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same issue here

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has isEvmParachain check so it only has evm and substrate options

? evmParachain.getDerivatedAddress(address)
: evmParachain.getSubstrateAddress(address);
}
return address;
}

/**
* Build a balance config with the address resolved to the format
* required by the config's CallType.
*/
export async function buildBalanceConfig(
builder: BalanceConfigBuilder,
address: string,
asset: Asset,
chain: AnyChain
) {
const config = builder.build({ address, asset, chain });
const account = await resolveAddress(address, chain, config.type);
if (account === address) {
return config;
}
return builder.build({ address: account, asset, chain });
}

/**
* Format amount if defined
*
Expand Down