Skip to content

Commit

Permalink
solution: new ui for convert tx (#1352)
Browse files Browse the repository at this point in the history
  • Loading branch information
BOOMER74 authored Dec 13, 2023
1 parent 1cc9e79 commit 2064105
Show file tree
Hide file tree
Showing 45 changed files with 1,058 additions and 1,083 deletions.
42 changes: 34 additions & 8 deletions packages/core/src/blockchains/tokens/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,16 +119,16 @@ export class Token implements TokenData {
return isWrappedToken(this);
}

getAmount(amount: BigNumber | string | number): TokenAmount {
return new TokenAmount(amount, this.getUnits(), this);
}

getUnits(): Units {
const { decimals, name, symbol } = this;

return new Units([new Unit(decimals, name, symbol)]);
}

getAmount(amount: BigNumber | string | number): TokenAmount {
return new TokenAmount(amount, this.getUnits(), this);
}

toPlain(): TokenData {
return { ...this };
}
Expand Down Expand Up @@ -210,35 +210,61 @@ export class TokenRegistry {
return (instances?.size ?? 0) > 0;
}

getStablecoins(blockchain: BlockchainCode): Token[] {
hasWrappedToken(blockchain: BlockchainCode): boolean {
return WRAPPED_TOKENS[blockchain] != null;
}

getPinned(blockchain: BlockchainCode): Token[] {
const instances = this.instances.get(blockchain);

if (instances == null) {
return [];
}

return [...instances.values()].reduce<Token[]>((carry, token) => {
if (token.stablecoin) {
if (token.pinned) {
return [...carry, token];
}

return carry;
}, []);
}

getPinned(blockchain: BlockchainCode): Token[] {
getStablecoins(blockchain: BlockchainCode): Token[] {
const instances = this.instances.get(blockchain);

if (instances == null) {
return [];
}

return [...instances.values()].reduce<Token[]>((carry, token) => {
if (token.pinned) {
if (token.stablecoin) {
return [...carry, token];
}

return carry;
}, []);
}

getWrapped(blockchain: BlockchainCode): Token {
const address = WRAPPED_TOKENS[blockchain];

if (address == null) {
throw new Error(`Wrapped token not found for ${blockchain} blockchain`);
}

const instances = this.instances.get(blockchain);

if (instances == null) {
throw new Error(`Can't find wrapped token by blockchain ${blockchain}`);
}

const instance = instances.get(address.toLowerCase());

if (instance == null) {
throw new Error(`Can't find wrapped token by address ${address} in ${blockchain} blockchain`);
}

return instance;
}
}
177 changes: 108 additions & 69 deletions packages/core/src/transaction/workflow/TxBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
isEthereum,
} from '../../blockchains';
import { EthereumTransactionType } from '../ethereum';
import { CreateBitcoinTx, CreateErc20ApproveTx, CreateErc20Tx, CreateEtherTx } from './create-tx';
import { CreateBitcoinTx, CreateErc20ApproveTx, CreateErc20ConvertTx, CreateErc20Tx, CreateEtherTx } from './create-tx';
import {
AnyCreateTx,
AnyErc20CreateTx,
Expand All @@ -28,6 +28,7 @@ import {
fromEthereumPlainTx,
isAnyErc20CreateTx,
isErc20ApproveCreateTx,
isErc20ConvertCreateTx,
isErc20CreateTx,
isEtherCreateTx,
} from './create-tx/types';
Expand Down Expand Up @@ -111,10 +112,9 @@ export class TxBuilder implements BuilderOrigin {
createTx.priorityGasPrice = feeRange.stdPriorityGasPrice;
}

createTx.type =
Blockchains[blockchain].params.eip1559 ?? false
? EthereumTransactionType.EIP1559
: EthereumTransactionType.LEGACY;
const { eip1559: supportEip1559 = false } = Blockchains[blockchain].params;

createTx.type = supportEip1559 ? EthereumTransactionType.EIP1559 : EthereumTransactionType.LEGACY;
}
} else {
if (isBitcoinPlainTx(transaction)) {
Expand All @@ -130,20 +130,26 @@ export class TxBuilder implements BuilderOrigin {

createTx = fromEthereumPlainTx(transaction, tokenRegistry);

const isChanged = asset !== createTx.getAsset() || blockchain !== createTx.blockchain;

if (isEtherCreateTx(createTx) || isErc20CreateTx(createTx)) {
if (asset !== createTx.getAsset() || blockchain !== createTx.blockchain) {
if (isChanged) {
return this.convertEthereumTx(createTx);
}

this.mergeEthereumFee(createTx);
this.mergeEthereumTx(transaction, createTx);
}

if (isErc20ApproveCreateTx(createTx)) {
if (asset !== createTx.getAsset()) {
if (isChanged) {
if (isErc20ApproveCreateTx(createTx)) {
createTx = this.transformErc20ApproveTx(createTx);
}

if (isErc20ConvertCreateTx(createTx)) {
createTx = this.transformErc20ConvertTx(createTx);
}

this.mergeEthereumFee(createTx);
}
}
Expand All @@ -152,70 +158,20 @@ export class TxBuilder implements BuilderOrigin {
return createTx;
}

private initBitcoinTx(entry: BitcoinEntry): CreateBitcoinTx {
const {
changeAddress,
feeRange,
dataProvider: { getUtxo },
} = this;

const createTx = new CreateBitcoinTx(
{
changeAddress,
blockchain: blockchainIdToCode(entry.blockchain),
entryId: entry.id,
},
getUtxo(entry),
);

if (isBitcoinFeeRange(feeRange)) {
createTx.feePrice = feeRange.std;
}

return createTx;
}

private initEthereumTx(entry: EthereumEntry): CreateEtherTx {
const { asset } = this;
const { getBalance } = this.dataProvider;

const createTx = new CreateEtherTx(null, blockchainIdToCode(entry.blockchain));

createTx.totalBalance = getBalance(entry, asset) as WeiAny;

return createTx;
}

private initErc20Tx(entry: EthereumEntry): CreateErc20Tx {
const { asset, ownerAddress, tokenRegistry } = this;
const { getBalance } = this.dataProvider;

const blockchain = blockchainIdToCode(entry.blockchain);

const { coinTicker } = Blockchains[blockchain].params;

const createTx = new CreateErc20Tx(tokenRegistry, asset, blockchain);

createTx.totalBalance = getBalance(entry, coinTicker) as WeiAny;
createTx.totalTokenBalance = getBalance(entry, asset, ownerAddress);
createTx.transferFrom = ownerAddress;

return createTx;
}

private convertEthereumTx(oldCreateTx: EthereumBasicCreateTx): EthereumBasicCreateTx {
const { asset, entry, feeRange, ownerAddress, tokenRegistry } = this;
const { getBalance } = this.dataProvider;

const blockchain = blockchainIdToCode(entry.blockchain);

const { coinTicker, eip1559: supportEip1559 = false } = Blockchains[blockchain].params;

const type = supportEip1559 ? oldCreateTx.type : EthereumTransactionType.LEGACY;

let newCreateTx: EthereumBasicCreateTx;

if (tokenRegistry.hasAddress(blockchain, asset)) {
newCreateTx = new CreateErc20Tx(tokenRegistry, asset, blockchain, type);
newCreateTx = new CreateErc20Tx(asset, tokenRegistry, blockchain, type);
newCreateTx.totalBalance = getBalance(entry, coinTicker) as WeiAny;
newCreateTx.totalTokenBalance = getBalance(entry, asset, newCreateTx.transferFrom);

Expand Down Expand Up @@ -259,20 +215,53 @@ export class TxBuilder implements BuilderOrigin {
return newCreateTx;
}

private transformErc20ApproveTx(createTx: CreateErc20ApproveTx): CreateErc20ApproveTx {
const { asset, entry, tokenRegistry } = this;
private initBitcoinTx(entry: BitcoinEntry): CreateBitcoinTx {
const {
changeAddress,
feeRange,
dataProvider: { getUtxo },
} = this;

const createTx = new CreateBitcoinTx(
{
changeAddress,
blockchain: blockchainIdToCode(entry.blockchain),
entryId: entry.id,
},
getUtxo(entry),
);

if (isBitcoinFeeRange(feeRange)) {
createTx.feePrice = feeRange.std;
}

return createTx;
}

private initEthereumTx(entry: EthereumEntry): CreateEtherTx {
const { asset } = this;
const { getBalance } = this.dataProvider;

const createTx = new CreateEtherTx(null, blockchainIdToCode(entry.blockchain));

createTx.totalBalance = getBalance(entry, asset) as WeiAny;

return createTx;
}

private initErc20Tx(entry: EthereumEntry): CreateErc20Tx {
const { asset, ownerAddress, tokenRegistry } = this;
const { getBalance } = this.dataProvider;

const blockchain = blockchainIdToCode(entry.blockchain);

const { coinTicker, eip1559: supportEip1559 = false } = Blockchains[blockchain].params;
const { coinTicker } = Blockchains[blockchain].params;

createTx.setToken(
tokenRegistry.byAddress(blockchain, asset),
getBalance(entry, coinTicker) as WeiAny,
getBalance(entry, asset) as TokenAmount,
supportEip1559,
);
const createTx = new CreateErc20Tx(asset, tokenRegistry, blockchain);

createTx.totalBalance = getBalance(entry, coinTicker) as WeiAny;
createTx.totalTokenBalance = getBalance(entry, asset, ownerAddress);
createTx.transferFrom = ownerAddress;

return createTx;
}
Expand Down Expand Up @@ -321,4 +310,54 @@ export class TxBuilder implements BuilderOrigin {
}
}
}

private transformErc20ApproveTx(createTx: CreateErc20ApproveTx): CreateErc20ApproveTx {
const { asset, entry, tokenRegistry } = this;
const { getBalance } = this.dataProvider;

const blockchain = blockchainIdToCode(entry.blockchain);

let tokenAddress = asset;

if (!tokenRegistry.hasAddress(blockchain, tokenAddress)) {
[{ address: tokenAddress }] = tokenRegistry.byBlockchain(blockchain);
}

const { coinTicker, eip1559: supportEip1559 = false } = Blockchains[blockchain].params;

createTx.setToken(
tokenRegistry.byAddress(blockchain, tokenAddress),
getBalance(entry, coinTicker) as WeiAny,
getBalance(entry, tokenAddress) as TokenAmount,
supportEip1559,
);

return createTx;
}

private transformErc20ConvertTx(createTx: CreateErc20ConvertTx): CreateErc20ConvertTx {
const { asset, entry, tokenRegistry } = this;
const { getBalance } = this.dataProvider;

const blockchain = blockchainIdToCode(entry.blockchain);

createTx.asset = asset;

let tokenAddress = asset;

if (!tokenRegistry.hasAddress(blockchain, tokenAddress)) {
tokenAddress = tokenRegistry.getWrapped(blockchain).address;
}

const { coinTicker, eip1559: supportEip1559 = false } = Blockchains[blockchain].params;

createTx.setToken(
tokenRegistry.byAddress(blockchain, tokenAddress),
getBalance(entry, coinTicker) as WeiAny,
getBalance(entry, tokenAddress) as TokenAmount,
supportEip1559,
);

return createTx;
}
}
12 changes: 10 additions & 2 deletions packages/core/src/transaction/workflow/TxSigner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { BlockchainCode, Blockchains } from '../../blockchains';
import { EthereumTx } from '../../blockchains/ethereum';
import { EthereumAddress } from '../../blockchains/ethereum/EthereumAddress';
import { EthereumTransaction, EthereumTransactionType } from '../ethereum';
import { AnyCreateTx, isAnyBitcoinCreateTx, isErc20ApproveCreateTx } from './create-tx/types';
import { AnyCreateTx, isAnyBitcoinCreateTx, isErc20ApproveCreateTx, isErc20ConvertCreateTx } from './create-tx/types';

interface SignerOrigin {
createTx: AnyCreateTx;
Expand Down Expand Up @@ -143,7 +143,15 @@ export class TxSigner implements SignerOrigin {
}

if (transaction.verifySignature()) {
const sender = isErc20ApproveCreateTx(createTx) ? createTx.approveBy : createTx.from;
let sender: string | undefined;

if (isErc20ApproveCreateTx(createTx)) {
sender = createTx.approveBy;
} else if (isErc20ConvertCreateTx(createTx)) {
sender = createTx.address;
} else {
sender = createTx.from;
}

if (sender != null && !transaction.getSenderAddress().equals(new EthereumAddress(sender))) {
throw new Error('Emerald Vault returned signature from wrong Sender');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,15 @@ export class CreateBitcoinTx implements BitcoinTx {
this.setAmount(value);
}

/**
* @deprecated
* Added to make one logic for Bitcoin and Ethereum flow.
* Create getter after refactoring Ethereum create transaction class.
*/
getAsset(): string {
return this.amount.units.top.code;
}

/**
* @deprecated
* Added to make one logic for Bitcoin and Ethereum flow.
Expand Down
Loading

0 comments on commit 2064105

Please sign in to comment.