diff --git a/modules/abstract-eth/package.json b/modules/abstract-eth/package.json index 4edc096157..017e955e52 100644 --- a/modules/abstract-eth/package.json +++ b/modules/abstract-eth/package.json @@ -37,10 +37,16 @@ ] }, "dependencies": { - "@bitgo/sdk-coin-eth": "^4.10.0", "@bitgo/sdk-core": "^8.26.0", "@bitgo/statics": "^29.0.0", "@bitgo/utxo-lib": "^9.16.0", - "bignumber.js": "^8.0.1" + "bignumber.js": "^9.1.1", + "ethers": "^5.1.3", + "ethereumjs-util": "7.1.5", + "@ethereumjs/common": "^2.6.5", + "@ethereumjs/tx": "^3.3.0", + "ethereumjs-abi": "^0.6.5", + "bn.js": "^5.2.1", + "debug": "^3.1.0" } } diff --git a/modules/abstract-eth/src/abstractEthLikeCoin.ts b/modules/abstract-eth/src/abstractEthLikeCoin.ts index 48da58afdf..b000c915fa 100644 --- a/modules/abstract-eth/src/abstractEthLikeCoin.ts +++ b/modules/abstract-eth/src/abstractEthLikeCoin.ts @@ -1,11 +1,9 @@ /** * @prettier */ -import { isValidEthAddress, KeyPair as EthKeyPair, TransactionBuilder } from '@bitgo/sdk-coin-eth'; import { CoinFamily, BaseCoin as StaticsBaseCoin } from '@bitgo/statics'; import { bip32 } from '@bitgo/utxo-lib'; import { randomBytes } from 'crypto'; - import { BaseCoin, BitGoBase, @@ -22,9 +20,10 @@ import { TransactionRecipient as Recipient, VerifyTransactionOptions, } from '@bitgo/sdk-core'; - import BigNumber from 'bignumber.js'; +import { isValidEthAddress, KeyPair as EthKeyPair, TransactionBuilder } from './lib'; + export interface EthSignTransactionOptions extends SignTransactionOptions { txPrebuild: TransactionPrebuild; prv: string; @@ -36,7 +35,7 @@ export interface TxInfo { txid: string; } -export interface TransactionPrebuild extends BaseTransactionPrebuild { +interface TransactionPrebuild extends BaseTransactionPrebuild { txHex: string; txInfo: TxInfo; feeInfo: EthTransactionFee; diff --git a/modules/abstract-eth/src/abstractEthLikeMPCCoin.ts b/modules/abstract-eth/src/abstractEthLikeMPCCoin.ts deleted file mode 100644 index 709627d204..0000000000 --- a/modules/abstract-eth/src/abstractEthLikeMPCCoin.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @prettier - */ -import { MPCAlgorithm } from '@bitgo/sdk-core'; -import { AbstractEthLikeCoin } from './abstractEthLikeCoin'; - -export abstract class AbstractEthLikeMPCCoin extends AbstractEthLikeCoin { - /** @inheritDoc */ - supportsTss(): boolean { - return true; - } - - /** @inheritDoc */ - getMPCAlgorithm(): MPCAlgorithm { - return 'ecdsa'; - } -} diff --git a/modules/abstract-eth/src/abstractEthLikeNewCoins.ts b/modules/abstract-eth/src/abstractEthLikeNewCoins.ts new file mode 100644 index 0000000000..81dbd30431 --- /dev/null +++ b/modules/abstract-eth/src/abstractEthLikeNewCoins.ts @@ -0,0 +1,203 @@ +/** + * @prettier + */ +import debugLib from 'debug'; +import { bip32 } from '@bitgo/utxo-lib'; +import { + BitGoBase, + EthereumLibraryUnavailableError, + Recipient, + TransactionRecipient, + TransactionPrebuild as BaseTransactionPrebuild, +} from '@bitgo/sdk-core'; +import { BaseCoin as StaticsBaseCoin, CoinFamily, EthereumNetwork as EthLikeNetwork } from '@bitgo/statics'; +import type * as EthLikeTxLib from '@ethereumjs/tx'; +import type * as EthLikeCommon from '@ethereumjs/common'; + +import { AbstractEthLikeCoin } from './abstractEthLikeCoin'; + +/** + * The prebuilt hop transaction returned from the HSM + */ +interface HopPrebuild { + tx: string; + id: string; + signature: string; + paymentId: string; + gasPrice: number; + gasLimit: number; + amount: number; + recipient: string; + nonce: number; + userReqSig: string; + gasPriceMax: number; +} + +export interface TransactionPrebuild extends BaseTransactionPrebuild { + hopTransaction?: HopPrebuild; + buildParams: { + recipients: Recipient[]; + }; + recipients: TransactionRecipient[]; + nextContractSequenceId: string; + gasPrice: number; + gasLimit: number; + isBatch: boolean; + coin: string; + token?: string; +} + +const debug = debugLib('bitgo:v2:ethlike'); + +export const optionalDeps = { + get ethAbi() { + try { + return require('ethereumjs-abi'); + } catch (e) { + debug('unable to load ethereumjs-abi:'); + debug(e.stack); + throw new EthereumLibraryUnavailableError(`ethereumjs-abi`); + } + }, + + get ethUtil() { + try { + return require('ethereumjs-util'); + } catch (e) { + debug('unable to load ethereumjs-util:'); + debug(e.stack); + throw new EthereumLibraryUnavailableError(`ethereumjs-util`); + } + }, + + get EthTx(): typeof EthLikeTxLib { + try { + return require('@ethereumjs/tx'); + } catch (e) { + debug('unable to load @ethereumjs/tx'); + debug(e.stack); + throw new EthereumLibraryUnavailableError(`@ethereumjs/tx`); + } + }, + + get EthCommon(): typeof EthLikeCommon { + try { + return require('@ethereumjs/common'); + } catch (e) { + debug('unable to load @ethereumjs/common:'); + debug(e.stack); + throw new EthereumLibraryUnavailableError(`@ethereumjs/common`); + } + }, +}; + +export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin { + protected readonly sendMethodName: 'sendMultiSig' | 'sendMultiSigToken'; + + protected readonly _staticsCoin: Readonly; + private static _ethLikeCoin: Readonly; + + protected constructor(bitgo: BitGoBase, staticsCoin?: Readonly) { + super(bitgo, staticsCoin); + + if (!staticsCoin) { + throw new Error('missing required constructor parameter staticsCoin'); + } + + this._staticsCoin = staticsCoin; + AbstractEthLikeNewCoins._ethLikeCoin = staticsCoin; + this.sendMethodName = 'sendMultiSig'; + } + + readonly staticsCoin?: Readonly; + + getChain() { + return this._staticsCoin.name; + } + + /** + * Get the base chain that the coin exists on. + */ + getBaseChain() { + return this.getChain(); + } + + getFamily(): CoinFamily { + return this._staticsCoin.family; + } + + getNetwork(): EthLikeNetwork | undefined { + return this._staticsCoin?.network as EthLikeNetwork; + } + + getFullName() { + return this._staticsCoin.fullName; + } + + getBaseFactor() { + return Math.pow(10, this._staticsCoin.decimalPlaces); + } + + /** @inheritDoc */ + isEVM(): boolean { + return true; + } + + valuelessTransferAllowed(): boolean { + return true; + } + + /** + * Evaluates whether an address string is valid for this coin + * @param address + */ + isValidAddress(address: string): boolean { + return optionalDeps.ethUtil.isValidAddress(optionalDeps.ethUtil.addHexPrefix(address)); + } + + /** + * Return boolean indicating whether input is valid public key for the coin. + * + * @param {String} pub the pub to be checked + * @returns {Boolean} is it valid? + */ + isValidPub(pub: string): boolean { + try { + return bip32.fromBase58(pub).isNeutered(); + } catch (e) { + return false; + } + } + + /** + * Flag for sending data along with transactions + * @returns {boolean} True if okay to send tx data (ETH), false otherwise + */ + transactionDataAllowed() { + return true; + } + + /** + * Default gas price from platform + * @returns {BigNumber} + */ + getRecoveryGasPrice(): any { + return new optionalDeps.ethUtil.BN('20000000000'); + } + + /** + * Default gas limit from platform + * @returns {BigNumber} + */ + getRecoveryGasLimit(): any { + return new optionalDeps.ethUtil.BN('500000'); + } + + /** + * Default expire time for a contract call (1 week) + * @returns {number} Time in seconds + */ + getDefaultExpireTime(): number { + return Math.floor(new Date().getTime() / 1000) + 60 * 60 * 24 * 7; + } +} diff --git a/modules/abstract-eth/src/ethLikeMPCToken.ts b/modules/abstract-eth/src/ethLikeMPCToken.ts deleted file mode 100644 index 47b5caab87..0000000000 --- a/modules/abstract-eth/src/ethLikeMPCToken.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @prettier - */ -import { MPCAlgorithm } from '@bitgo/sdk-core'; -import { EthLikeToken } from './ethLikeToken'; - -export abstract class EthLikeMPCToken extends EthLikeToken { - /** @inheritDoc */ - supportsTss(): boolean { - return true; - } - - /** @inheritDoc */ - getMPCAlgorithm(): MPCAlgorithm { - return 'ecdsa'; - } -} diff --git a/modules/abstract-eth/src/ethLikeToken.ts b/modules/abstract-eth/src/ethLikeToken.ts index 87b7bd8fed..6fa75cc102 100644 --- a/modules/abstract-eth/src/ethLikeToken.ts +++ b/modules/abstract-eth/src/ethLikeToken.ts @@ -5,7 +5,8 @@ import { coins, EthLikeTokenConfig, tokens } from '@bitgo/statics'; import { BitGoBase, CoinConstructor, NamedCoinConstructor } from '@bitgo/sdk-core'; import { AbstractEthLikeCoin } from './abstractEthLikeCoin'; -import { TransactionBuilder as EthTransactionBuilder, TransactionPrebuild } from '@bitgo/sdk-coin-eth'; +import { TransactionBuilder as EthLikeTransactionBuilder } from './lib'; +import { TransactionPrebuild } from './abstractEthLikeNewCoins'; export type CoinNames = { [network: string]: string; @@ -35,10 +36,6 @@ export class EthLikeToken extends AbstractEthLikeCoin { return tokensCtors; } - protected getTransactionBuilder(): EthTransactionBuilder { - return new EthTransactionBuilder(coins.get(this.getBaseChain())); - } - get type(): string { return this.tokenConfig.type; } @@ -102,4 +99,12 @@ export class EthLikeToken extends AbstractEthLikeCoin { verifyCoin(txPrebuild: TransactionPrebuild): boolean { return txPrebuild.coin === this.tokenConfig.coin && txPrebuild.token === this.tokenConfig.type; } + + /** + * Create a new transaction builder for the current chain + * @return a new transaction builder + */ + protected getTransactionBuilder(): EthLikeTransactionBuilder { + throw new Error('Method not implemented'); + } } diff --git a/modules/abstract-eth/src/index.ts b/modules/abstract-eth/src/index.ts index 7f0b554b57..4ec88e2ed1 100644 --- a/modules/abstract-eth/src/index.ts +++ b/modules/abstract-eth/src/index.ts @@ -1,4 +1,4 @@ export * from './abstractEthLikeCoin'; export * from './ethLikeToken'; -export * from './abstractEthLikeMPCCoin'; -export * from './ethLikeMPCToken'; +export * from './lib'; +export * from './abstractEthLikeNewCoins'; diff --git a/modules/sdk-coin-eth/src/lib/contractCall.ts b/modules/abstract-eth/src/lib/contractCall.ts similarity index 100% rename from modules/sdk-coin-eth/src/lib/contractCall.ts rename to modules/abstract-eth/src/lib/contractCall.ts diff --git a/modules/sdk-coin-eth/src/lib/iface.ts b/modules/abstract-eth/src/lib/iface.ts similarity index 100% rename from modules/sdk-coin-eth/src/lib/iface.ts rename to modules/abstract-eth/src/lib/iface.ts diff --git a/modules/abstract-eth/src/lib/index.ts b/modules/abstract-eth/src/lib/index.ts new file mode 100644 index 0000000000..ae53d5a67b --- /dev/null +++ b/modules/abstract-eth/src/lib/index.ts @@ -0,0 +1,17 @@ +export * from './contractCall'; +export * from './iface'; +export * from './keyPair'; +export * from './transaction'; +export * from './transactionBuilder'; +export * from './transferBuilder'; +export * from './transferBuilders'; +export * from './transferBuilder'; +export * from './types'; +export * from './utils'; +export * from './walletUtil'; + +// for Backwards Compatibility +import * as Interface from './iface'; +import * as Utils from './utils'; + +export { Interface, Utils }; diff --git a/modules/sdk-coin-eth/src/lib/keyPair.ts b/modules/abstract-eth/src/lib/keyPair.ts similarity index 100% rename from modules/sdk-coin-eth/src/lib/keyPair.ts rename to modules/abstract-eth/src/lib/keyPair.ts diff --git a/modules/sdk-coin-eth/src/lib/transaction.ts b/modules/abstract-eth/src/lib/transaction.ts similarity index 100% rename from modules/sdk-coin-eth/src/lib/transaction.ts rename to modules/abstract-eth/src/lib/transaction.ts diff --git a/modules/abstract-eth/src/lib/transactionBuilder.ts b/modules/abstract-eth/src/lib/transactionBuilder.ts new file mode 100644 index 0000000000..254d0264a1 --- /dev/null +++ b/modules/abstract-eth/src/lib/transactionBuilder.ts @@ -0,0 +1,797 @@ +import { BaseCoin as CoinConfig, EthereumNetwork } from '@bitgo/statics'; +import EthereumCommon from '@ethereumjs/common'; +import EthereumAbi from 'ethereumjs-abi'; +import BigNumber from 'bignumber.js'; +import * as ethUtil from 'ethereumjs-util'; +import { FeeMarketEIP1559Transaction } from '@ethereumjs/tx'; + +import { + BaseAddress, + BaseKey, + BaseTransaction, + BaseTransactionBuilder, + BuildTransactionError, + InvalidTransactionError, + isValidPrv, + isValidXprv, + ParseTransactionError, + SigningError, + TransactionType, +} from '@bitgo/sdk-core'; + +import { KeyPair } from './keyPair'; +import { ETHTransactionType, Fee, SignatureParts, TxData } from './iface'; +import { + calculateForwarderAddress, + calculateForwarderV1Address, + classifyTransaction, + decodeForwarderCreationData, + decodeFlushTokensData, + decodeWalletCreationData, + flushCoinsData, + flushTokensData, + getAddressInitializationData, + getV1AddressInitializationData, + getCommon, + getProxyInitcode, + hasSignature, + isValidEthAddress, + getV1WalletInitializationData, +} from './utils'; +import { defaultWalletVersion, defaultForwarderVersion } from './walletUtil'; +import { ERC1155TransferBuilder } from './transferBuilders/transferBuilderERC1155'; +import { ERC721TransferBuilder } from './transferBuilders/transferBuilderERC721'; +import { Transaction } from './transaction'; +import { TransferBuilder } from './transferBuilder'; + +const DEFAULT_M = 3; + +/** + * EthereumLike transaction builder. + */ +export abstract class TransactionBuilder extends BaseTransactionBuilder { + protected _type: TransactionType; + // Specifies common chain and hardfork parameters. + protected _common: EthereumCommon; + protected _sourceKeyPair: KeyPair; + private _transaction: Transaction; + private _counter: number; + private _fee: Fee; + protected _value: string; + + // the signature on the external ETH transaction + private _txSignature: SignatureParts; + + // Wallet initialization transaction parameters + private _walletOwnerAddresses: string[]; + private _walletVersion: number; + + // flush tokens parameters + private _forwarderAddress: string; + private _tokenAddress: string; + + // Send and AddressInitialization transaction specific parameters + protected _transfer: TransferBuilder | ERC721TransferBuilder | ERC1155TransferBuilder; + private _contractAddress: string; + private _contractCounter: number; + private _forwarderVersion: number; + private _initCode: string; + private _baseAddress: string; + + // generic contract call builder + // encoded contract call hex + private _data: string; + + // Common parameter for wallet initialization and address initialization transaction + private _salt: string; + + /** + * Public constructor. + * + * @param _coinConfig + */ + constructor(_coinConfig: Readonly) { + super(_coinConfig); + this._common = getCommon(this._coinConfig.network as EthereumNetwork); + this._type = TransactionType.Send; + this._counter = 0; + this._value = '0'; + this._walletOwnerAddresses = []; + this._forwarderVersion = 0; + this._walletVersion = 0; + this.transaction = new Transaction(this._coinConfig, this._common); + } + + /** @inheritdoc */ + protected async buildImplementation(): Promise { + const transactionData = this.getTransactionData(); + + if (this._txSignature) { + Object.assign(transactionData, this._txSignature); + } + + this.transaction.setTransactionType(this._type); + transactionData.from = this._sourceKeyPair ? this._sourceKeyPair.getAddress() : undefined; + this.transaction.setTransactionData(transactionData); + + // Build and sign a new transaction based on the latest changes + if (this._sourceKeyPair && this._sourceKeyPair.getKeys().prv) { + await this.transaction.sign(this._sourceKeyPair); + } + return this.transaction; + } + + protected getTransactionData(): TxData { + switch (this._type) { + case TransactionType.WalletInitialization: + return this.buildWalletInitializationTransaction(this._walletVersion); + case TransactionType.RecoveryWalletDeployment: + return this.buildBase(this._data); + case TransactionType.Send: + case TransactionType.SendERC721: + case TransactionType.SendERC1155: + return this.buildSendTransaction(); + case TransactionType.AddressInitialization: + return this.buildAddressInitializationTransaction(); + case TransactionType.FlushTokens: + return this.buildFlushTokensTransaction(); + case TransactionType.FlushCoins: + return this.buildFlushCoinsTransaction(); + case TransactionType.SingleSigSend: + return this.buildBase('0x'); + case TransactionType.ContractCall: + return this.buildGenericContractCallTransaction(); + default: + throw new BuildTransactionError('Unsupported transaction type'); + } + } + + /** @inheritdoc */ + protected fromImplementation(rawTransaction: string): Transaction { + let tx: Transaction; + if (/^0x?[0-9a-f]{1,}$/.test(rawTransaction.toLowerCase())) { + tx = Transaction.fromSerialized(this._coinConfig, this._common, rawTransaction); + this.loadBuilderInput(tx.toJson()); + } else { + const txData = JSON.parse(rawTransaction); + tx = new Transaction(this._coinConfig, txData); + } + return tx; + } + + /** + * Load the builder data using the deserialized transaction + * + * @param {TxData} transactionJson the deserialized transaction json + */ + protected loadBuilderInput(transactionJson: TxData): void { + const decodedType = classifyTransaction(transactionJson.data); + this.type(decodedType); + this.counter(transactionJson.nonce); + this.value(transactionJson.value); + + if (transactionJson._type === ETHTransactionType.LEGACY) { + this.fee({ + fee: transactionJson.gasPrice, + gasPrice: transactionJson.gasPrice, + gasLimit: transactionJson.gasLimit, + }); + } else { + this.fee({ + gasLimit: transactionJson.gasLimit, + fee: transactionJson.maxFeePerGas, + eip1559: { + maxFeePerGas: transactionJson.maxFeePerGas, + maxPriorityFeePerGas: transactionJson.maxPriorityFeePerGas, + }, + }); + } + + if (hasSignature(transactionJson)) { + this._txSignature = { v: transactionJson.v!, r: transactionJson.r!, s: transactionJson.s! }; + } + this.setTransactionTypeFields(decodedType, transactionJson); + } + + protected setTransactionTypeFields(decodedType: TransactionType, transactionJson: TxData): void { + switch (decodedType) { + case TransactionType.WalletInitialization: + const { owners, salt } = decodeWalletCreationData(transactionJson.data); + owners.forEach((element) => { + this.owner(element); + }); + if (salt) { + this.salt(salt as string); + this.walletVersion(1); + this.setContract(transactionJson.to); + } + break; + case TransactionType.RecoveryWalletDeployment: + this.data(transactionJson.data); + break; + case TransactionType.FlushTokens: + this.setContract(transactionJson.to); + const { forwarderAddress, tokenAddress } = decodeFlushTokensData(transactionJson.data); + this.forwarderAddress(forwarderAddress); + this.tokenAddress(tokenAddress); + break; + case TransactionType.FlushCoins: + this.setContract(transactionJson.to); + break; + case TransactionType.Send: + case TransactionType.SendERC1155: + case TransactionType.SendERC721: + this.setContract(transactionJson.to); + this._transfer = this.transfer(transactionJson.data); + break; + case TransactionType.AddressInitialization: + this.setContract(transactionJson.to); + const { baseAddress, addressCreationSalt } = decodeForwarderCreationData(transactionJson.data); + if (baseAddress && addressCreationSalt) { + this.forwarderVersion(1); + this.baseAddress(baseAddress); + this.salt(addressCreationSalt); + const forwarderImplementationAddress = (this._coinConfig.network as EthereumNetwork) + .forwarderImplementationAddress as string; + if (forwarderImplementationAddress) { + this.initCode(forwarderImplementationAddress); + } + } + break; + case TransactionType.SingleSigSend: + this.setContract(transactionJson.to); + break; + case TransactionType.ContractCall: + this.setContract(transactionJson.to); + this.data(transactionJson.data); + break; + default: + throw new BuildTransactionError('Unsupported transaction type'); + // TODO: Add other cases of deserialization + } + } + + /** @inheritdoc */ + protected signImplementation(key: BaseKey): BaseTransaction { + const signer = new KeyPair({ prv: key.key }); + if (this._type === TransactionType.WalletInitialization && this._walletOwnerAddresses.length === 0) { + throw new SigningError('Cannot sign an wallet initialization transaction without owners'); + } + if (this._sourceKeyPair) { + throw new SigningError('Cannot sign multiple times a non send-type transaction'); + } + // Signing the transaction is an async operation, so save the source and leave the actual + // signing for the build step + this._sourceKeyPair = signer; + return this.transaction; + } + + /** @inheritdoc */ + validateAddress(address: BaseAddress): void { + if (!isValidEthAddress(address.address)) { + throw new BuildTransactionError('Invalid address ' + address.address); + } + } + + /** @inheritdoc */ + validateKey(key: BaseKey): void { + if (!(isValidXprv(key.key) || isValidPrv(key.key))) { + throw new BuildTransactionError('Invalid key'); + } + } + + /** + * Validate the raw transaction is either a JSON or + * a hex encoded transaction + * + * @param {any} rawTransaction The raw transaction to be validated + */ + validateRawTransaction(rawTransaction: any): void { + if (!rawTransaction) { + throw new InvalidTransactionError('Raw transaction is empty'); + } + if (typeof rawTransaction === 'string') { + if (/^0x?[0-9a-f]{1,}$/.test(rawTransaction.toLowerCase())) { + const txBytes = ethUtil.toBuffer(ethUtil.addHexPrefix(rawTransaction.toLowerCase())); + if (!this.isEip1559Txn(txBytes) && !this.isRLPDecodable(txBytes)) { + throw new ParseTransactionError('There was error in decoding the hex string'); + } + } else { + try { + JSON.parse(rawTransaction); + } catch (e) { + throw new ParseTransactionError('There was error in parsing the JSON string'); + } + } + } else { + throw new InvalidTransactionError('Transaction is not a hex string or stringified json'); + } + } + + private isEip1559Txn(txn: Buffer): boolean { + try { + FeeMarketEIP1559Transaction.fromSerializedTx(txn); + return true; + } catch (_) { + return false; + } + } + + private isRLPDecodable(bytes: Buffer): boolean { + try { + ethUtil.rlp.decode(bytes); + return true; + } catch (_) { + return false; + } + } + + protected validateBaseTransactionFields(): void { + if (this._fee === undefined || (!this._fee.fee && !this._fee.gasPrice && !this._fee.eip1559)) { + throw new BuildTransactionError('Invalid transaction: missing fee'); + } + if (this._common === undefined) { + throw new BuildTransactionError('Invalid transaction: network common'); + } + if (this._counter === undefined) { + throw new BuildTransactionError('Invalid transaction: missing address counter'); + } + } + + /** @inheritdoc */ + validateTransaction(transaction: BaseTransaction): void { + this.validateBaseTransactionFields(); + switch (this._type) { + case TransactionType.WalletInitialization: + this.validateWalletInitializationFields(); + break; + case TransactionType.RecoveryWalletDeployment: + this.validateDataField(); + break; + case TransactionType.Send: + case TransactionType.SendERC721: + case TransactionType.SendERC1155: + this.validateContractAddress(); + break; + case TransactionType.AddressInitialization: + this.validateContractAddress(); + break; + case TransactionType.FlushCoins: + this.validateContractAddress(); + break; + case TransactionType.FlushTokens: + this.validateContractAddress(); + this.validateForwarderAddress(); + this.validateTokenAddress(); + break; + case TransactionType.SingleSigSend: + // for single sig sends, the contract address is actually the recipient + this.validateContractAddress(); + break; + case TransactionType.StakingLock: + case TransactionType.StakingUnlock: + case TransactionType.StakingVote: + case TransactionType.StakingUnvote: + case TransactionType.StakingActivate: + case TransactionType.StakingWithdraw: + break; + case TransactionType.ContractCall: + this.validateContractAddress(); + this.validateDataField(); + break; + default: + throw new BuildTransactionError('Unsupported transaction type'); + } + } + + /** + * Check wallet owner addresses for wallet initialization transactions are valid or throw. + */ + private validateWalletInitializationFields(): void { + if (this._walletOwnerAddresses === undefined) { + throw new BuildTransactionError('Invalid transaction: missing wallet owners'); + } + + if (this._walletOwnerAddresses.length !== 3) { + throw new BuildTransactionError( + `Invalid transaction: wrong number of owners -- required: 3, found: ${this._walletOwnerAddresses.length}` + ); + } + } + + /** + * Check if a token address for the tx was defined or throw. + */ + private validateTokenAddress(): void { + if (this._tokenAddress === undefined) { + throw new BuildTransactionError('Invalid transaction: missing token address'); + } + } + + /** + * Check if a forwarder address for the tx was defined or throw. + */ + private validateForwarderAddress(): void { + if (this._forwarderAddress === undefined) { + throw new BuildTransactionError('Invalid transaction: missing forwarder address'); + } + } + + /** + * Check if a contract address for the wallet was defined or throw. + */ + private validateContractAddress(): void { + if (this._contractAddress === undefined) { + throw new BuildTransactionError('Invalid transaction: missing contract address'); + } + } + + /** + * Checks if a contract call data field was defined or throws otherwise + */ + private validateDataField(): void { + if (!this._data) { + throw new BuildTransactionError('Invalid transaction: missing contract call data field'); + } + } + + private setContract(address: string | undefined): void { + if (address === undefined) { + throw new BuildTransactionError('Undefined recipient address'); + } + this.contract(address); + } + + validateValue(value: BigNumber): void { + if (value.isLessThan(0)) { + throw new BuildTransactionError('Value cannot be below less than zero'); + } + // TODO: validate the amount is not bigger than the max amount in each Eth family coin + } + + // region Common builder methods + + /** + * The type of transaction being built. + * + * @param {TransactionType} type + */ + type(type: TransactionType): void { + this._type = type; + } + + /** + * Set the transaction fees. Low fees may get a transaction rejected or never picked up by bakers. + * + * @param {Fee} fee Baker fees. May also include the maximum gas to pay + */ + fee(fee: Fee): void { + this.validateValue(new BigNumber(fee.fee)); + if (fee.gasLimit) { + this.validateValue(new BigNumber(fee.gasLimit)); + } + if (fee.eip1559) { + this.validateValue(new BigNumber(fee.eip1559.maxFeePerGas)); + this.validateValue(new BigNumber(fee.eip1559.maxPriorityFeePerGas)); + } + if (fee.gasPrice) { + this.validateValue(new BigNumber(fee.gasPrice)); + } + this._fee = fee; + } + + /** + * Set the transaction counter to prevent submitting repeated transactions. + * + * @param {number} counter The counter to use + */ + counter(counter: number): void { + if (counter < 0) { + throw new BuildTransactionError(`Invalid counter: ${counter}`); + } + + this._counter = counter; + } + + /** + * The value to send along with this transaction. 0 by default + * + * @param {string} value The value to send along with this transaction + */ + value(value: string): void { + this._value = value; + } + + // set args that are required for all types of eth transactions + protected buildBase(data: string): TxData { + const baseParams = { + gasLimit: this._fee.gasLimit, + nonce: this._counter, + data: data, + chainId: this._common.chainIdBN().toString(), + value: this._value, + to: this._contractAddress, + }; + + if (this._fee.eip1559) { + return { + ...baseParams, + _type: ETHTransactionType.EIP1559, + maxFeePerGas: this._fee.eip1559.maxFeePerGas, + maxPriorityFeePerGas: this._fee.eip1559.maxPriorityFeePerGas, + }; + } else { + return { + ...baseParams, + _type: ETHTransactionType.LEGACY, + gasPrice: this._fee?.gasPrice ?? this._fee.fee, + v: this.getFinalV(), + }; + } + } + + // endregion + + // region WalletInitialization builder methods + /** + * Set one of the owners of the multisig wallet. + * + * @param {string} address An Ethereum address + */ + owner(address: string): void { + if (this._type !== TransactionType.WalletInitialization) { + throw new BuildTransactionError('Multisig wallet owner can only be set for initialization transactions'); + } + if (this._walletOwnerAddresses.length >= DEFAULT_M) { + throw new BuildTransactionError('A maximum of ' + DEFAULT_M + ' owners can be set for a multisig wallet'); + } + if (!isValidEthAddress(address)) { + throw new BuildTransactionError('Invalid address: ' + address); + } + if (this._walletOwnerAddresses.includes(address)) { + throw new BuildTransactionError('Repeated owner address: ' + address); + } + this._walletOwnerAddresses.push(address); + } + + /** + * Build a transaction for a generic multisig contract. + * + * @returns {TxData} The Ethereum transaction data + */ + protected buildWalletInitializationTransaction(walletVersion?: number): TxData { + const walletInitData = + walletVersion === defaultWalletVersion + ? this.getContractData(this._walletOwnerAddresses) + : getV1WalletInitializationData(this._walletOwnerAddresses, this._salt); + return this.buildBase(walletInitData); + } + + /** + * Returns the smart contract encoded data + * + * @param {string[]} addresses - the contract signers + * @returns {string} - the smart contract encoded data + */ + protected abstract getContractData(addresses: string[]): string; + + // endregion + + // region Send builder methods + + contract(address: string): void { + if (!isValidEthAddress(address)) { + throw new BuildTransactionError('Invalid address: ' + address); + } + this._contractAddress = address; + } + + /** + * Gets the transfer funds builder if exist, or creates a new one for this transaction and returns it + * + * @param [data] transfer data to initialize the transfer builder with, empty if none given + * @returns {TransferBuilder | ERC721TransferBuilder | ERC1155TransferBuilder} the transfer builder + */ + abstract transfer(data?: string): TransferBuilder | ERC721TransferBuilder | ERC1155TransferBuilder; + + /** + * Returns the serialized sendMultiSig contract method data + * + * @returns {string} serialized sendMultiSig data + */ + private getSendData(): string { + if (!this._transfer) { + throw new BuildTransactionError('Missing transfer information'); + } + return this._transfer.signAndBuild(); + } + + private buildSendTransaction(): TxData { + const sendData = this.getSendData(); + const tx: TxData = this.buildBase(sendData); + tx.to = this._contractAddress; + return tx; + } + + // endregion + + // region AddressInitialization builder methods + + /** + * Set the contract transaction nonce to calculate the forwarder address. + * + * @param {number} contractCounter The counter to use + */ + contractCounter(contractCounter: number): void { + if (contractCounter < 0) { + throw new BuildTransactionError(`Invalid contract counter: ${contractCounter}`); + } + + this._contractCounter = contractCounter; + } + + /** + * Build a transaction to create a forwarder. + * + * @returns {TxData} The Ethereum transaction data + */ + private buildAddressInitializationTransaction(): TxData { + const addressInitData = + this._forwarderVersion === defaultForwarderVersion + ? getAddressInitializationData() + : getV1AddressInitializationData(this._baseAddress, this._salt); + const tx: TxData = this.buildBase(addressInitData); + tx.to = this._contractAddress; + + if (this._contractCounter) { + tx.deployedAddress = calculateForwarderAddress(this._contractAddress, this._contractCounter); + } + + if (this._salt && this._initCode) { + const saltBuffer = ethUtil.setLengthLeft(ethUtil.toBuffer(this._salt), 32); + // Hash the wallet base address with the given salt, so the address directly relies on the base address + const calculationSalt = ethUtil.bufferToHex( + EthereumAbi.soliditySHA3(['address', 'bytes32'], [this._baseAddress, saltBuffer]) + ); + tx.deployedAddress = calculateForwarderV1Address(this._contractAddress, calculationSalt, this._initCode); + } + return tx; + } + // endregion + + // region flush methods + /** + * Set the forwarder address to flush + * + * @param {string} address The address to flush + */ + forwarderAddress(address: string): void { + if (!isValidEthAddress(address)) { + throw new BuildTransactionError('Invalid address: ' + address); + } + this._forwarderAddress = address; + } + + /** + * Set the address of the ERC20 token contract that we are flushing tokens for + * + * @param {string} address the contract address of the token to flush + */ + tokenAddress(address: string): void { + if (!isValidEthAddress(address)) { + throw new BuildTransactionError('Invalid address: ' + address); + } + this._tokenAddress = address; + } + + /** + * Build a transaction to flush tokens from a forwarder. + * + * @returns {TxData} The Ethereum transaction data + */ + private buildFlushTokensTransaction(): TxData { + return this.buildBase(flushTokensData(this._forwarderAddress, this._tokenAddress)); + } + + /** + * Build a transaction to flush tokens from a forwarder. + * + * @returns {TxData} The Ethereum transaction data + */ + private buildFlushCoinsTransaction(): TxData { + return this.buildBase(flushCoinsData()); + } + // endregion + + // region generic contract call + data(encodedCall: string): void { + const supportedTransactionTypes = [TransactionType.ContractCall, TransactionType.RecoveryWalletDeployment]; + if (!supportedTransactionTypes.includes(this._type)) { + throw new BuildTransactionError('data can only be set for contract call transaction types'); + } + this._data = encodedCall; + } + + private buildGenericContractCallTransaction(): TxData { + return this.buildBase(this._data); + } + // endregion + + /** @inheritdoc */ + protected get transaction(): Transaction { + return this._transaction; + } + + /** @inheritdoc */ + protected set transaction(transaction: Transaction) { + this._transaction = transaction; + } + + /** + * Get the final v value. Final v is described in EIP-155. + * + * @protected for internal use when the enableFinalVField flag is true. + */ + protected getFinalV(): string { + return ethUtil.addHexPrefix(this._common.chainIdBN().muln(2).addn(35).toString(16)); + } + + /** + * Set the forwarder version for address to be initialized + * + * @param {number} version forwarder version + */ + forwarderVersion(version: number): void { + if (version < 0 || version > 2) { + throw new BuildTransactionError(`Invalid forwarder version: ${version}`); + } + + this._forwarderVersion = version; + } + + /** + * Set the salt to create the address using create2 + * + * @param {string} salt The salt to create the address using create2, hex string + */ + salt(salt: string): void { + this._salt = salt; + } + + /** + * Take the implementation address for the proxy contract, and get the binary initcode for the associated proxy + * + * @param {string} implementationAddress The address of the implementation contract + */ + initCode(implementationAddress: string): void { + if (!isValidEthAddress(implementationAddress)) { + throw new BuildTransactionError('Invalid address: ' + implementationAddress); + } + this._initCode = getProxyInitcode(implementationAddress); + } + + /** + * Set the wallet version for wallet to be initialized + * + * @param {number} version wallet version + */ + walletVersion(version: number): void { + if (version < 0 || version > 3) { + throw new BuildTransactionError(`Invalid wallet version: ${version}`); + } + + this._walletVersion = version; + } + + /** + * Set the base address of the wallet + * + * @param {string} address The wallet contract address + */ + baseAddress(address: string): void { + if (!isValidEthAddress(address)) { + throw new BuildTransactionError('Invalid address: ' + address); + } + this._baseAddress = address; + } +} diff --git a/modules/abstract-eth/src/lib/transferBuilder.ts b/modules/abstract-eth/src/lib/transferBuilder.ts new file mode 100644 index 0000000000..a010fb7e5a --- /dev/null +++ b/modules/abstract-eth/src/lib/transferBuilder.ts @@ -0,0 +1,245 @@ +import * as ethUtil from 'ethereumjs-util'; +import EthereumAbi from 'ethereumjs-abi'; +import BN from 'bn.js'; +import { coins, BaseCoin, ContractAddressDefinedToken } from '@bitgo/statics'; +import { BuildTransactionError, InvalidParameterValueError } from '@bitgo/sdk-core'; +import { decodeTransferData, sendMultiSigData, sendMultiSigTokenData, isValidEthAddress, isValidAmount } from './utils'; + +/** ETH transfer builder */ +export class TransferBuilder { + private readonly _EMPTY_HEX_VALUE = '0x'; + protected _amount: string; + protected _toAddress: string; + protected _sequenceId: number; + protected _signKey: string; + protected _expirationTime: number; + protected _signature: string; + private _data: string; + private _tokenContractAddress?: string; + private _coin: Readonly; + + constructor(serializedData?: string) { + if (serializedData) { + this.decodeTransferData(serializedData); + } else { + // initialize with default values for non mandatory fields + this._expirationTime = this.getExpirationTime(); + this._data = this._EMPTY_HEX_VALUE; + this._signature = this._EMPTY_HEX_VALUE; + } + } + + /** + * A method to set the ERC20 token to be transferred. + * This ERC20 token may not be compatible with the network. + * + * @param {string} coin the ERC20 coin to be set + * @returns {TransferBuilder} the transfer builder instance modified + */ + coin(coin: string): TransferBuilder { + this._coin = coins.get(coin); + + if (this._coin instanceof ContractAddressDefinedToken) { + this._tokenContractAddress = this._coin.contractAddress.toString(); + } + + return this; + } + + data(additionalData: string): TransferBuilder { + this._signature = this._EMPTY_HEX_VALUE; + this._data = additionalData; + return this; + } + + amount(amount: string): this { + if (!isValidAmount(amount)) { + throw new InvalidParameterValueError('Invalid amount'); + } + this._signature = this._EMPTY_HEX_VALUE; + this._amount = amount; + return this; + } + + to(address: string): TransferBuilder { + if (isValidEthAddress(address)) { + this._signature = this._EMPTY_HEX_VALUE; + this._toAddress = address; + return this; + } + throw new InvalidParameterValueError('Invalid address'); + } + + contractSequenceId(counter: number): TransferBuilder { + if (counter >= 0) { + this._signature = this._EMPTY_HEX_VALUE; + this._sequenceId = counter; + return this; + } + throw new InvalidParameterValueError('Invalid contract sequence id'); + } + + key(signKey: string): TransferBuilder { + this._signKey = signKey; + return this; + } + + expirationTime(date: number): TransferBuilder { + if (date > 0) { + this._signature = this._EMPTY_HEX_VALUE; + this._expirationTime = date; + return this; + } + throw new InvalidParameterValueError('Invalid expiration time'); + } + + signAndBuild(): string { + if (this.hasMandatoryFields()) { + if (this._tokenContractAddress !== undefined) { + return sendMultiSigTokenData( + this._toAddress, + this._amount, + this._tokenContractAddress, + this._expirationTime, + this._sequenceId, + this.getSignature() + ); + } else { + return sendMultiSigData( + this._toAddress, + this._amount, + this._data, + this._expirationTime, + this._sequenceId, + this.getSignature() + ); + } + } + throw new BuildTransactionError( + 'Missing transfer mandatory fields. Amount, destination (to) address and sequenceID are mandatory' + ); + } + + private hasMandatoryFields(): boolean { + return this._amount !== undefined && this._toAddress !== undefined && this._sequenceId !== undefined; + } + + /** + * Obtains the proper operation hash to sign either a sendMultiSig data + * or a sendMultiSigToken data + * + * @returns {string} the operation hash + */ + private getOperationHash(): string { + const operationData = this.getOperationData(); + return ethUtil.bufferToHex(EthereumAbi.soliditySHA3(...operationData)); + } + + protected getOperationData(): (string | Buffer)[][] { + let operationData; + if (this._tokenContractAddress !== undefined) { + operationData = [ + ['string', 'address', 'uint', 'address', 'uint', 'uint'], + [ + this.getTokenOperationHashPrefix(), + new BN(ethUtil.stripHexPrefix(this._toAddress), 16), + this._amount, + new BN(ethUtil.stripHexPrefix(this._tokenContractAddress), 16), + this._expirationTime, + this._sequenceId, + ], + ]; + } else { + operationData = [ + ['string', 'address', 'uint', 'bytes', 'uint', 'uint'], + [ + this.getNativeOperationHashPrefix(), + new BN(ethUtil.stripHexPrefix(this._toAddress), 16), + this._amount, + Buffer.from(ethUtil.padToEven(ethUtil.stripHexPrefix(this._data)) || '', 'hex'), + this._expirationTime, + this._sequenceId, + ], + ]; + } + return operationData; + } + + /** + * Get the prefix used in generating an operation hash for sending tokens + * + * @returns the string prefix + */ + protected getTokenOperationHashPrefix(): string { + return 'ERC20'; + } + + /** + * Get the prefix used in generating an operation hash for sending native coins + * + * @returns the string prefix + */ + protected getNativeOperationHashPrefix(): string { + return 'ETHER'; + } + + /** Return an expiration time, in seconds, set to one hour from now + * + * @returns {number} expiration time + */ + private getExpirationTime(): number { + const currentDate = new Date(); + currentDate.setHours(currentDate.getHours() + 1); + return currentDate.getTime() / 1000; + } + + /** + * If a signing key is set for this builder, recalculates the signature + * + * @returns {string} the signature value + */ + protected getSignature(): string { + if (this._signKey) { + this._signature = this.ethSignMsgHash(); + } + return this._signature!; + } + + protected ethSignMsgHash(): string { + const data = this.getOperationHash(); + const keyBuffer = Buffer.from(ethUtil.padToEven(this._signKey), 'hex'); + if (keyBuffer.length != 32) { + throw new Error('private key length is invalid'); + } + const signatureInParts = ethUtil.ecsign( + Buffer.from(ethUtil.padToEven(ethUtil.stripHexPrefix(data)), 'hex'), + keyBuffer + ); + + // Assemble strings from r, s and v + const r = ethUtil.setLengthLeft(signatureInParts.r, 32).toString('hex'); + const s = ethUtil.setLengthLeft(signatureInParts.s, 32).toString('hex'); + const v = ethUtil.stripHexPrefix(ethUtil.intToHex(signatureInParts.v)); + + // Concatenate the r, s and v parts to make the signature string + return ethUtil.addHexPrefix(r.concat(s, v)); + } + + private decodeTransferData(data: string): void { + const transferData = decodeTransferData(data); + + this._toAddress = transferData.to; + this._amount = transferData.amount; + this._expirationTime = transferData.expireTime; + this._sequenceId = transferData.sequenceId; + this._signature = transferData.signature; + + if (transferData.data) { + this._data = transferData.data; + } + + if (transferData.tokenContractAddress) { + this._tokenContractAddress = transferData.tokenContractAddress; + } + } +} diff --git a/modules/sdk-coin-eth/src/lib/transferBuilders/baseNFTTransferBuilder.ts b/modules/abstract-eth/src/lib/transferBuilders/baseNFTTransferBuilder.ts similarity index 100% rename from modules/sdk-coin-eth/src/lib/transferBuilders/baseNFTTransferBuilder.ts rename to modules/abstract-eth/src/lib/transferBuilders/baseNFTTransferBuilder.ts diff --git a/modules/abstract-eth/src/lib/transferBuilders/index.ts b/modules/abstract-eth/src/lib/transferBuilders/index.ts new file mode 100644 index 0000000000..946d247e92 --- /dev/null +++ b/modules/abstract-eth/src/lib/transferBuilders/index.ts @@ -0,0 +1,3 @@ +export * from './baseNFTTransferBuilder'; +export * from './transferBuilderERC1155'; +export * from './transferBuilderERC721'; diff --git a/modules/sdk-coin-eth/src/lib/transferBuilders/transferBuilderERC1155.ts b/modules/abstract-eth/src/lib/transferBuilders/transferBuilderERC1155.ts similarity index 99% rename from modules/sdk-coin-eth/src/lib/transferBuilders/transferBuilderERC1155.ts rename to modules/abstract-eth/src/lib/transferBuilders/transferBuilderERC1155.ts index f24b2d2576..f5b3988b00 100644 --- a/modules/sdk-coin-eth/src/lib/transferBuilders/transferBuilderERC1155.ts +++ b/modules/abstract-eth/src/lib/transferBuilders/transferBuilderERC1155.ts @@ -1,4 +1,6 @@ import { BuildTransactionError, InvalidParameterValueError } from '@bitgo/sdk-core'; +import { hexlify, hexZeroPad } from 'ethers/lib/utils'; + import { ContractCall } from '../contractCall'; import { decodeERC1155TransferData, isValidEthAddress, sendMultiSigData } from '../utils'; import { @@ -8,7 +10,6 @@ import { ERC1155SafeTransferTypeMethodId, } from '../walletUtil'; import { BaseNFTTransferBuilder } from './baseNFTTransferBuilder'; -import { hexlify, hexZeroPad } from 'ethers/lib/utils'; export class ERC1155TransferBuilder extends BaseNFTTransferBuilder { private _tokenIds: string[]; diff --git a/modules/sdk-coin-eth/src/lib/transferBuilders/transferBuilderERC721.ts b/modules/abstract-eth/src/lib/transferBuilders/transferBuilderERC721.ts similarity index 99% rename from modules/sdk-coin-eth/src/lib/transferBuilders/transferBuilderERC721.ts rename to modules/abstract-eth/src/lib/transferBuilders/transferBuilderERC721.ts index 5667e4c712..5e8149ad63 100644 --- a/modules/sdk-coin-eth/src/lib/transferBuilders/transferBuilderERC721.ts +++ b/modules/abstract-eth/src/lib/transferBuilders/transferBuilderERC721.ts @@ -1,9 +1,10 @@ import { BuildTransactionError, InvalidParameterValueError } from '@bitgo/sdk-core'; +import { hexlify, hexZeroPad } from 'ethers/lib/utils'; + import { ContractCall } from '../contractCall'; import { decodeERC721TransferData, isValidEthAddress, sendMultiSigData } from '../utils'; import { BaseNFTTransferBuilder } from './baseNFTTransferBuilder'; import { ERC721SafeTransferTypeMethodId } from '../walletUtil'; -import { hexlify, hexZeroPad } from 'ethers/lib/utils'; export class ERC721TransferBuilder extends BaseNFTTransferBuilder { private _tokenId: string; diff --git a/modules/sdk-coin-eth/src/lib/types.ts b/modules/abstract-eth/src/lib/types.ts similarity index 100% rename from modules/sdk-coin-eth/src/lib/types.ts rename to modules/abstract-eth/src/lib/types.ts diff --git a/modules/sdk-coin-eth/src/lib/utils.ts b/modules/abstract-eth/src/lib/utils.ts similarity index 100% rename from modules/sdk-coin-eth/src/lib/utils.ts rename to modules/abstract-eth/src/lib/utils.ts diff --git a/modules/abstract-eth/src/lib/walletUtil.ts b/modules/abstract-eth/src/lib/walletUtil.ts new file mode 100644 index 0000000000..2e9bca9c14 --- /dev/null +++ b/modules/abstract-eth/src/lib/walletUtil.ts @@ -0,0 +1,31 @@ +export const sendMultisigMethodId = '0x39125215'; +export const sendMultisigTokenMethodId = '0x0dcd7a6c'; +export const v1CreateForwarderMethodId = '0xfb90b320'; +export const v1WalletInitializationFirstBytes = '0x60806040'; +export const v1CreateWalletMethodId = '0x7117f3fa'; +export const createForwarderMethodId = '0xa68a76cc'; +export const walletInitializationFirstBytes = '0x60606040'; +export const recoveryWalletInitializationFirstBytes = '0x60c06040'; +export const flushForwarderTokensMethodId = '0x2da03409'; +export const flushCoinsMethodId = '0x6b9f96ea'; + +export const ERC721SafeTransferTypeMethodId = '0xb88d4fde'; +export const ERC1155SafeTransferTypeMethodId = '0xf242432a'; +export const ERC1155BatchTransferTypeMethodId = '0x2eb2c2d6'; +export const defaultForwarderVersion = 0; +export const defaultWalletVersion = 0; + +export const walletSimpleConstructor = ['address[]']; +export const createV1WalletTypes = ['address[]', 'bytes32']; +export const flushTokensTypes = ['address', 'address']; +export const flushCoinsTypes = []; + +export const sendMultiSigTypes = ['address', 'uint', 'bytes', 'uint', 'uint', 'bytes']; + +export const sendMultiSigTokenTypes = ['address', 'uint', 'address', 'uint', 'uint', 'bytes']; + +export const ERC721SafeTransferTypes = ['address', 'address', 'uint256', 'bytes']; + +export const ERC1155SafeTransferTypes = ['address', 'address', 'uint256', 'uint256', 'bytes']; +export const ERC1155BatchTransferTypes = ['address', 'address', 'uint256[]', 'uint256[]', 'bytes']; +export const createV1ForwarderTypes = ['address', 'bytes32']; diff --git a/modules/abstract-eth/tsconfig.json b/modules/abstract-eth/tsconfig.json index d3142d801e..2dc888cb8d 100644 --- a/modules/abstract-eth/tsconfig.json +++ b/modules/abstract-eth/tsconfig.json @@ -4,15 +4,12 @@ "outDir": "./dist", "rootDir": "./", "strictPropertyInitialization": false, - "esModuleInterop": false, + "esModuleInterop": true, "typeRoots": ["../../types", "./node_modules/@types", "../../node_modules/@types"] }, "include": ["src/**/*"], "exclude": ["node_modules"], "references": [ - { - "path": "../sdk-coin-eth" - }, { "path": "../sdk-core" }, diff --git a/modules/account-lib/package.json b/modules/account-lib/package.json index ab829072fc..9e9590179d 100644 --- a/modules/account-lib/package.json +++ b/modules/account-lib/package.json @@ -63,7 +63,7 @@ "@bitgo/sdk-core": "^8.26.0", "@bitgo/sdk-lib-mpc": "^8.15.0", "@bitgo/statics": "^29.0.0", - "bignumber.js": "^9.0.0", + "bignumber.js": "^9.1.1", "bs58": "^4.0.1" }, "devDependencies": { diff --git a/modules/bitgo/package.json b/modules/bitgo/package.json index e435bd4b0e..b6872a90e7 100644 --- a/modules/bitgo/package.json +++ b/modules/bitgo/package.json @@ -103,7 +103,7 @@ "@bitgo/utxo-lib": "^9.16.0", "@types/bluebird": "^3.5.25", "@types/superagent": "^4.1.3", - "bignumber.js": "^8.0.1", + "bignumber.js": "^9.1.1", "bitcoinjs-message": "npm:@bitgo-forks/bitcoinjs-message@1.0.0-master.2", "bluebird": "^3.5.3", "fs-extra": "^9.1.0", diff --git a/modules/express/package.json b/modules/express/package.json index 461c090ce8..7e429d04a0 100644 --- a/modules/express/package.json +++ b/modules/express/package.json @@ -62,7 +62,7 @@ "@types/node": "^16.18.46", "@types/sinon": "^10.0.11", "@types/supertest": "^2.0.11", - "bignumber.js": "^8.0.1", + "bignumber.js": "^9.1.1", "keccak": "^3.0.3", "nock": "^13.3.1", "nyc": "^15.0.0", diff --git a/modules/sdk-coin-arbeth/package.json b/modules/sdk-coin-arbeth/package.json index 71e91e811d..14ec3be2f0 100644 --- a/modules/sdk-coin-arbeth/package.json +++ b/modules/sdk-coin-arbeth/package.json @@ -41,10 +41,10 @@ }, "dependencies": { "@bitgo/abstract-eth": "^1.6.0", - "@bitgo/sdk-coin-eth": "^4.10.0", "@bitgo/sdk-core": "^8.26.0", "@bitgo/statics": "^29.0.0", - "@ethereumjs/common": "^2.6.5" + "@ethereumjs/common": "^2.6.5", + "ethereumjs-abi": "^0.6.5" }, "devDependencies": { "@bitgo/sdk-api": "^1.24.0", diff --git a/modules/sdk-coin-arbeth/src/arbeth.ts b/modules/sdk-coin-arbeth/src/arbeth.ts index 6ef4ca893a..bce927602c 100644 --- a/modules/sdk-coin-arbeth/src/arbeth.ts +++ b/modules/sdk-coin-arbeth/src/arbeth.ts @@ -4,11 +4,10 @@ import { BaseCoin, BitGoBase } from '@bitgo/sdk-core'; import { BaseCoin as StaticsBaseCoin, coins } from '@bitgo/statics'; -import { AbstractEthLikeMPCCoin } from '@bitgo/abstract-eth'; -import { TransactionBuilder as EthTransactionBuilder } from '@bitgo/sdk-coin-eth'; +import { AbstractEthLikeNewCoins, TransactionBuilder as EthLikeTransactionBuilder } from '@bitgo/abstract-eth'; import { TransactionBuilder } from './lib'; -export class Arbeth extends AbstractEthLikeMPCCoin { +export class Arbeth extends AbstractEthLikeNewCoins { protected constructor(bitgo: BitGoBase, staticsCoin?: Readonly) { super(bitgo, staticsCoin); } @@ -17,7 +16,7 @@ export class Arbeth extends AbstractEthLikeMPCCoin { return new Arbeth(bitgo, staticsCoin); } - protected getTransactionBuilder(): EthTransactionBuilder { + protected getTransactionBuilder(): EthLikeTransactionBuilder { return new TransactionBuilder(coins.get(this.getBaseChain())); } } diff --git a/modules/sdk-coin-arbeth/src/arbethToken.ts b/modules/sdk-coin-arbeth/src/arbethToken.ts index a3b3ffda69..322dd3440b 100644 --- a/modules/sdk-coin-arbeth/src/arbethToken.ts +++ b/modules/sdk-coin-arbeth/src/arbethToken.ts @@ -1,13 +1,14 @@ /** * @prettier */ -import { EthLikeTokenConfig } from '@bitgo/statics'; +import { EthLikeTokenConfig, coins } from '@bitgo/statics'; import { BitGoBase, CoinConstructor, NamedCoinConstructor } from '@bitgo/sdk-core'; -import { CoinNames, EthLikeMPCToken } from '@bitgo/abstract-eth'; +import { CoinNames, EthLikeToken } from '@bitgo/abstract-eth'; +import { TransactionBuilder } from './lib'; export { EthLikeTokenConfig }; -export class ArbethToken extends EthLikeMPCToken { +export class ArbethToken extends EthLikeToken { public readonly tokenConfig: EthLikeTokenConfig; static coinNames: CoinNames = { Mainnet: 'arbeth', @@ -24,6 +25,10 @@ export class ArbethToken extends EthLikeMPCToken { return super.createTokenConstructors(ArbethToken.coinNames); } + protected getTransactionBuilder(): TransactionBuilder { + return new TransactionBuilder(coins.get(this.getBaseChain())); + } + getFullName(): string { return 'Arbeth Token'; } diff --git a/modules/sdk-coin-arbeth/src/lib/index.ts b/modules/sdk-coin-arbeth/src/lib/index.ts index 79473f2f5a..20f9e761a1 100644 --- a/modules/sdk-coin-arbeth/src/lib/index.ts +++ b/modules/sdk-coin-arbeth/src/lib/index.ts @@ -2,5 +2,5 @@ import * as Utils from './utils'; export { TransactionBuilder } from './transactionBuilder'; export { TransferBuilder } from './transferBuilder'; -export { Transaction, KeyPair } from '@bitgo/sdk-coin-eth'; +export { Transaction, KeyPair } from '@bitgo/abstract-eth'; export { Utils }; diff --git a/modules/sdk-coin-arbeth/src/lib/transactionBuilder.ts b/modules/sdk-coin-arbeth/src/lib/transactionBuilder.ts index c564751558..69304c475e 100644 --- a/modules/sdk-coin-arbeth/src/lib/transactionBuilder.ts +++ b/modules/sdk-coin-arbeth/src/lib/transactionBuilder.ts @@ -1,10 +1,17 @@ import { BaseCoin as CoinConfig } from '@bitgo/statics'; +import EthereumAbi from 'ethereumjs-abi'; import { BuildTransactionError, TransactionType } from '@bitgo/sdk-core'; -import { KeyPair, Transaction, TransactionBuilder as EthTransactionBuilder } from '@bitgo/sdk-coin-eth'; +import { + KeyPair, + Transaction, + TransactionBuilder as EthLikeTransactionBuilder, + walletSimpleConstructor, +} from '@bitgo/abstract-eth'; import { getCommon } from './utils'; import { TransferBuilder } from './transferBuilder'; +import { walletSimpleByteCode } from './walletUtil'; -export class TransactionBuilder extends EthTransactionBuilder { +export class TransactionBuilder extends EthLikeTransactionBuilder { protected _transfer!: TransferBuilder; constructor(_coinConfig: Readonly) { @@ -24,6 +31,20 @@ export class TransactionBuilder extends EthTransactionBuilder { return this._transfer; } + /** + * Returns the smart contract encoded data + * + * @param {string[]} addresses - the contract signers + * @returns {string} - the smart contract encoded data + */ + protected getContractData(addresses: string[]): string { + const params = [addresses]; + const resultEncodedParameters = EthereumAbi.rawEncode(walletSimpleConstructor, params) + .toString('hex') + .replace('0x', ''); + return walletSimpleByteCode + resultEncodedParameters; + } + publicKey(key: string): void { this._sourceKeyPair = new KeyPair({ pub: key }); } diff --git a/modules/sdk-coin-arbeth/src/lib/transferBuilder.ts b/modules/sdk-coin-arbeth/src/lib/transferBuilder.ts index 688cb8e9e2..baeac6df55 100644 --- a/modules/sdk-coin-arbeth/src/lib/transferBuilder.ts +++ b/modules/sdk-coin-arbeth/src/lib/transferBuilder.ts @@ -1,4 +1,4 @@ -import { TransferBuilder as EthTransferBuilder } from '@bitgo/sdk-coin-eth'; +import { TransferBuilder as EthTransferBuilder } from '@bitgo/abstract-eth'; export class TransferBuilder extends EthTransferBuilder { /** @inheritdoc */ diff --git a/modules/sdk-coin-arbeth/src/lib/walletUtil.ts b/modules/sdk-coin-arbeth/src/lib/walletUtil.ts new file mode 100644 index 0000000000..3b2615b77f --- /dev/null +++ b/modules/sdk-coin-arbeth/src/lib/walletUtil.ts @@ -0,0 +1,604 @@ +export const walletSimpleByteCode = + '0x60806040525f60015f6101000a81548160ff0219169083151502179055505f6001806101000a81548160ff021916908315150217905550348015610041575f80fd5b506136aa8061004f5f395ff3fe608060405260043610610122575f3560e01c8063924677761161009f578063c137878411610063578063c137878414610475578063c6044c461461049d578063e6bd0aa4146104c5578063f23a6e61146104ed578063fc0f392d146105295761016b565b80639246777614610395578063a0b7967b146103bd578063abe3219c146103e7578063ad3ad70914610411578063bc197c81146104395761016b565b806334f94047116100e657806334f94047146102a557806339125215146102cd5780635a953d0a146102f5578063736c0d5b1461031d5780637df73e27146103595761016b565b806301ffc9a7146101b35780630dcd7a6c146101ef578063150b7a0214610217578063158ef93e146102535780632da034091461027d5761016b565b3661016b575f341115610169577f6e89d517057028190560dd200cf6bf792842861353d1173761dfa362e1c133f03334604051610160929190611be9565b60405180910390a15b005b5f3411156101b1577f6e89d517057028190560dd200cf6bf792842861353d1173761dfa362e1c133f033345f366040516101a89493929190611c6d565b60405180910390a15b005b3480156101be575f80fd5b506101d960048036038101906101d49190611d11565b61053f565b6040516101e69190611d56565b60405180910390f35b3480156101fa575f80fd5b5061021560048036038101906102109190611e24565b6105b8565b005b348015610222575f80fd5b5061023d60048036038101906102389190611fe8565b61065f565b60405161024a9190612077565b60405180910390f35b34801561025e575f80fd5b50610267610672565b6040516102749190611d56565b60405180910390f35b348015610288575f80fd5b506102a3600480360381019061029e91906120cb565b610683565b005b3480156102b0575f80fd5b506102cb60048036038101906102c6919061215e565b61073a565b005b3480156102d8575f80fd5b506102f360048036038101906102ee91906121cf565b6107f7565b005b348015610300575f80fd5b5061031b60048036038101906103169190612299565b610989565b005b348015610328575f80fd5b50610343600480360381019061033e91906122e9565b610a43565b6040516103509190611d56565b60405180910390f35b348015610364575f80fd5b5061037f600480360381019061037a91906122e9565b610a5f565b60405161038c9190611d56565b60405180910390f35b3480156103a0575f80fd5b506103bb60048036038101906103b6919061233e565b610ab0565b005b3480156103c8575f80fd5b506103d1610b67565b6040516103de919061237c565b60405180910390f35b3480156103f2575f80fd5b506103fb610bd4565b6040516104089190611d56565b60405180910390f35b34801561041c575f80fd5b50610437600480360381019061043291906123ea565b610be6565b005b348015610444575f80fd5b5061045f600480360381019061045a91906124c1565b610df2565b60405161046c9190612077565b60405180910390f35b348015610480575f80fd5b5061049b6004803603810190610496919061233e565b610e09565b005b3480156104a8575f80fd5b506104c360048036038101906104be9190612598565b610ec0565b005b3480156104d0575f80fd5b506104eb60048036038101906104e69190612299565b6110ac565b005b3480156104f8575f80fd5b50610513600480360381019061050e91906125e3565b611166565b6040516105209190612077565b60405180910390f35b348015610534575f80fd5b5061053d61117b565b005b5f7f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806105b157506105b082611215565b5b9050919050565b6105c133610a5f565b610600576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105f7906126d3565b60405180910390fd5b5f61060961127e565b8888888888604051602001610623969594939291906127c2565b6040516020818303038152906040528051906020012090506106498882858589896112bb565b5061065586898961147b565b5050505050505050565b5f63150b7a0260e01b9050949350505050565b60018054906101000a900460ff1681565b61068c33610a5f565b6106cb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c2906126d3565b60405180910390fd5b5f8290508073ffffffffffffffffffffffffffffffffffffffff16633ef13367836040518263ffffffff1660e01b8152600401610708919061282d565b5f604051808303815f87803b15801561071f575f80fd5b505af1158015610731573d5f803e3d5ffd5b50505050505050565b61074333610a5f565b610782576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610779906126d3565b60405180910390fd5b5f8490508073ffffffffffffffffffffffffffffffffffffffff1663c6a2dd248585856040518463ffffffff1660e01b81526004016107c3939291906128be565b5f604051808303815f87803b1580156107da575f80fd5b505af11580156107ec573d5f803e3d5ffd5b505050505050505050565b61080033610a5f565b61083f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610836906126d3565b60405180910390fd5b5f6108486115ab565b898989898989604051602001610864979695949392919061291c565b6040516020818303038152906040528051906020012090505f61088b8a8386868a8a6112bb565b90505f8a73ffffffffffffffffffffffffffffffffffffffff168a8a8a6040516108b6929190612985565b5f6040518083038185875af1925050503d805f81146108f0576040519150601f19603f3d011682016040523d82523d5f602084013e6108f5565b606091505b5050905080610939576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610930906129e7565b60405180910390fd5b7f59bed9ab5d78073465dd642a9e3e76dfdb7d53bcae9d09df7d0b8f5234d5a8063383858e8e8e8e6040516109749796959493929190612a1d565b60405180910390a15050505050505050505050565b61099233610a5f565b6109d1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109c8906126d3565b60405180910390fd5b5f8390508073ffffffffffffffffffffffffffffffffffffffff1663159e44d784846040518363ffffffff1660e01b8152600401610a10929190612a85565b5f604051808303815f87803b158015610a27575f80fd5b505af1158015610a39573d5f803e3d5ffd5b5050505050505050565b5f602052805f5260405f205f915054906101000a900460ff1681565b5f805f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff169050919050565b610ab933610a5f565b610af8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610aef906126d3565b60405180910390fd5b5f8290508073ffffffffffffffffffffffffffffffffffffffff16638acc01be836040518263ffffffff1660e01b8152600401610b359190611d56565b5f604051808303815f87803b158015610b4c575f80fd5b505af1158015610b5e573d5f803e3d5ffd5b50505050505050565b5f805f90505f5b600a811015610bc05781600282600a8110610b8c57610b8b612aac565b5b01541115610bad57600281600a8110610ba857610ba7612aac565b5b015491505b8080610bb890612b06565b915050610b6e565b50600181610bce9190612b4d565b91505090565b60015f9054906101000a900460ff1681565b610bef33610a5f565b610c2e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c25906126d3565b60405180910390fd5b5f8888905003610c73576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6a90612bca565b60405180910390fd5b858590508888905014610cbb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cb290612c32565b60405180910390fd5b6101008888905010610d02576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cf990612c9a565b60405180910390fd5b5f610d0b6115e8565b898989898989604051602001610d279796959493929190612dd3565b60405160208183030381529060405280519060200120905060015f9054906101000a900460ff1615610d8e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d8590612e73565b60405180910390fd5b5f610d9d5f8386868a8a6112bb565b9050610dab8a8a8a8a611625565b7fe4c9047a729726b729cf4fa62c95ef9a434bbaf206a7ea0c7c77515db1584022338284604051610dde93929190612e91565b60405180910390a150505050505050505050565b5f63bc197c8160e01b905098975050505050505050565b610e1233610a5f565b610e51576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e48906126d3565b60405180910390fd5b5f8290508073ffffffffffffffffffffffffffffffffffffffff1663c59f9f19836040518263ffffffff1660e01b8152600401610e8e9190611d56565b5f604051808303815f87803b158015610ea5575f80fd5b505af1158015610eb7573d5f803e3d5ffd5b50505050505050565b60018054906101000a900460ff1615610f0e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f0590612f10565b60405180910390fd5b60038282905014610f54576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f4b90612f78565b60405180910390fd5b5f5b828290508160ff16101561108d575f73ffffffffffffffffffffffffffffffffffffffff1683838360ff16818110610f9157610f90612aac565b5b9050602002016020810190610fa691906122e9565b73ffffffffffffffffffffffffffffffffffffffff1603610ffc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ff390612fe0565b60405180910390fd5b60015f8085858560ff1681811061101657611015612aac565b5b905060200201602081019061102b91906122e9565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff02191690831515021790555080806110859061300a565b915050610f56565b5060018060016101000a81548160ff0219169083151502179055505050565b6110b533610a5f565b6110f4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110eb906126d3565b60405180910390fd5b5f8390508073ffffffffffffffffffffffffffffffffffffffff16638972c17c84846040518363ffffffff1660e01b8152600401611133929190612a85565b5f604051808303815f87803b15801561114a575f80fd5b505af115801561115c573d5f803e3d5ffd5b5050505050505050565b5f63f23a6e6160e01b90509695505050505050565b61118433610a5f565b6111c3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111ba906126d3565b60405180910390fd5b6001805f6101000a81548160ff0219169083151502179055507f0909e8f76a4fd3e970f2eaef56c0ee6dfaf8b87c5b8d3f56ffce78e825a911573360405161120b919061282d565b60405180910390a1565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60606040518060400160405280600c81526020017f4152424554482d45524332300000000000000000000000000000000000000000815250905090565b5f8061130a8787878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505061180c565b905060015f9054906101000a900460ff16158061132c575061132b88610a5f565b5b61136b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113629061307c565b60405180910390fd5b428410156113ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113a5906130e4565b60405180910390fd5b6113b783611944565b6113c081610a5f565b6113ff576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113f690612fe0565b60405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361146d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114649061314c565b60405180910390fd5b809150509695505050505050565b5f808473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb85856040516024016114ac929190612a85565b6040516020818303038152906040529060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516114fa91906131a4565b5f604051808303815f865af19150503d805f8114611533576040519150601f19603f3d011682016040523d82523d5f602084013e611538565b606091505b509150915081801561156557505f8151148061156457508080602001905181019061156391906131ce565b5b5b6115a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161159b90613269565b60405180910390fd5b5050505050565b60606040518060400160405280600681526020017f4152424554480000000000000000000000000000000000000000000000000000815250905090565b60606040518060400160405280600c81526020017f4152424554482d42617463680000000000000000000000000000000000000000815250905090565b5f5b848490508110156118055782828281811061164557611644612aac565b5b9050602002013547101561168e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611685906132d1565b60405180910390fd5b5f8585838181106116a2576116a1612aac565b5b90506020020160208101906116b791906122e9565b73ffffffffffffffffffffffffffffffffffffffff168484848181106116e0576116df612aac565b5b905060200201356040516116f39061330f565b5f6040518083038185875af1925050503d805f811461172d576040519150601f19603f3d011682016040523d82523d5f602084013e611732565b606091505b5050905080611776576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161176d9061336d565b60405180910390fd5b7fc42fa155158786a1dd6ccc3a785f35845467353c3cc700e0e31a79f90e22227d338787858181106117ab576117aa612aac565b5b90506020020160208101906117c091906122e9565b8686868181106117d3576117d2612aac565b5b905060200201356040516117e99392919061338b565b60405180910390a15080806117fd90612b06565b915050611627565b5050505050565b5f6041825114611851576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118489061340a565b60405180910390fd5b5f805f602085015192506040850151915060ff6041860151169050601b8160ff16101561188857601b816118859190613428565b90505b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0825f1c11156118ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118e4906134cc565b60405180910390fd5b6001868285856040515f815260200160405260405161190f94939291906134f9565b6020604051602081039080840390855afa15801561192f573d5f803e3d5ffd5b50505060206040510351935050505092915050565b61194d33610a5f565b61198c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611983906126d3565b60405180910390fd5b5f806002600a806020026040519081016040528092919082600a80156119c7576020028201915b8154815260200190600101908083116119b3575b505050505090505f5b600a811015611a7f57838282600a81106119ed576119ec612aac565b5b602002015103611a32576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a2990613586565b60405180910390fd5b8183600a8110611a4557611a44612aac565b5b60200201518282600a8110611a5d57611a5c612aac565b5b60200201511015611a6c578092505b8080611a7790612b06565b9150506119d0565b508082600a8110611a9357611a92612aac565b5b60200201518311611ad9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ad0906135ee565b60405180910390fd5b6127108183600a8110611aef57611aee612aac565b5b6020020151611afe9190612b4d565b831115611b40576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b3790613656565b60405180910390fd5b82600283600a8110611b5557611b54612aac565b5b0181905550505050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f611b8882611b5f565b9050919050565b611b9881611b7e565b82525050565b5f819050919050565b611bb081611b9e565b82525050565b5f82825260208201905092915050565b50565b5f611bd45f83611bb6565b9150611bdf82611bc6565b5f82019050919050565b5f606082019050611bfc5f830185611b8f565b611c096020830184611ba7565b8181036040830152611c1a81611bc9565b90509392505050565b828183375f83830152505050565b5f601f19601f8301169050919050565b5f611c4c8385611bb6565b9350611c59838584611c23565b611c6283611c31565b840190509392505050565b5f606082019050611c805f830187611b8f565b611c8d6020830186611ba7565b8181036040830152611ca0818486611c41565b905095945050505050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b611cf081611cbc565b8114611cfa575f80fd5b50565b5f81359050611d0b81611ce7565b92915050565b5f60208284031215611d2657611d25611cb4565b5b5f611d3384828501611cfd565b91505092915050565b5f8115159050919050565b611d5081611d3c565b82525050565b5f602082019050611d695f830184611d47565b92915050565b611d7881611b7e565b8114611d82575f80fd5b50565b5f81359050611d9381611d6f565b92915050565b611da281611b9e565b8114611dac575f80fd5b50565b5f81359050611dbd81611d99565b92915050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f840112611de457611de3611dc3565b5b8235905067ffffffffffffffff811115611e0157611e00611dc7565b5b602083019150836001820283011115611e1d57611e1c611dcb565b5b9250929050565b5f805f805f805f60c0888a031215611e3f57611e3e611cb4565b5b5f611e4c8a828b01611d85565b9750506020611e5d8a828b01611daf565b9650506040611e6e8a828b01611d85565b9550506060611e7f8a828b01611daf565b9450506080611e908a828b01611daf565b93505060a088013567ffffffffffffffff811115611eb157611eb0611cb8565b5b611ebd8a828b01611dcf565b925092505092959891949750929550565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b611f0882611c31565b810181811067ffffffffffffffff82111715611f2757611f26611ed2565b5b80604052505050565b5f611f39611cab565b9050611f458282611eff565b919050565b5f67ffffffffffffffff821115611f6457611f63611ed2565b5b611f6d82611c31565b9050602081019050919050565b5f611f8c611f8784611f4a565b611f30565b905082815260208101848484011115611fa857611fa7611ece565b5b611fb3848285611c23565b509392505050565b5f82601f830112611fcf57611fce611dc3565b5b8135611fdf848260208601611f7a565b91505092915050565b5f805f806080858703121561200057611fff611cb4565b5b5f61200d87828801611d85565b945050602061201e87828801611d85565b935050604061202f87828801611daf565b925050606085013567ffffffffffffffff8111156120505761204f611cb8565b5b61205c87828801611fbb565b91505092959194509250565b61207181611cbc565b82525050565b5f60208201905061208a5f830184612068565b92915050565b5f61209a82611b5f565b9050919050565b6120aa81612090565b81146120b4575f80fd5b50565b5f813590506120c5816120a1565b92915050565b5f80604083850312156120e1576120e0611cb4565b5b5f6120ee858286016120b7565b92505060206120ff85828601611d85565b9150509250929050565b5f8083601f84011261211e5761211d611dc3565b5b8235905067ffffffffffffffff81111561213b5761213a611dc7565b5b60208301915083602082028301111561215757612156611dcb565b5b9250929050565b5f805f806060858703121561217657612175611cb4565b5b5f612183878288016120b7565b945050602061219487828801611d85565b935050604085013567ffffffffffffffff8111156121b5576121b4611cb8565b5b6121c187828801612109565b925092505092959194509250565b5f805f805f805f8060c0898b0312156121eb576121ea611cb4565b5b5f6121f88b828c01611d85565b98505060206122098b828c01611daf565b975050604089013567ffffffffffffffff81111561222a57612229611cb8565b5b6122368b828c01611dcf565b965096505060606122498b828c01611daf565b945050608061225a8b828c01611daf565b93505060a089013567ffffffffffffffff81111561227b5761227a611cb8565b5b6122878b828c01611dcf565b92509250509295985092959890939650565b5f805f606084860312156122b0576122af611cb4565b5b5f6122bd868287016120b7565b93505060206122ce86828701611d85565b92505060406122df86828701611daf565b9150509250925092565b5f602082840312156122fe576122fd611cb4565b5b5f61230b84828501611d85565b91505092915050565b61231d81611d3c565b8114612327575f80fd5b50565b5f8135905061233881612314565b92915050565b5f806040838503121561235457612353611cb4565b5b5f61236185828601611d85565b92505060206123728582860161232a565b9150509250929050565b5f60208201905061238f5f830184611ba7565b92915050565b5f8083601f8401126123aa576123a9611dc3565b5b8235905067ffffffffffffffff8111156123c7576123c6611dc7565b5b6020830191508360208202830111156123e3576123e2611dcb565b5b9250929050565b5f805f805f805f8060a0898b03121561240657612405611cb4565b5b5f89013567ffffffffffffffff81111561242357612422611cb8565b5b61242f8b828c01612395565b9850985050602089013567ffffffffffffffff81111561245257612451611cb8565b5b61245e8b828c01612109565b965096505060406124718b828c01611daf565b94505060606124828b828c01611daf565b935050608089013567ffffffffffffffff8111156124a3576124a2611cb8565b5b6124af8b828c01611dcf565b92509250509295985092959890939650565b5f805f805f805f8060a0898b0312156124dd576124dc611cb4565b5b5f6124ea8b828c01611d85565b98505060206124fb8b828c01611d85565b975050604089013567ffffffffffffffff81111561251c5761251b611cb8565b5b6125288b828c01612109565b9650965050606089013567ffffffffffffffff81111561254b5761254a611cb8565b5b6125578b828c01612109565b9450945050608089013567ffffffffffffffff81111561257a57612579611cb8565b5b6125868b828c01611dcf565b92509250509295985092959890939650565b5f80602083850312156125ae576125ad611cb4565b5b5f83013567ffffffffffffffff8111156125cb576125ca611cb8565b5b6125d785828601612395565b92509250509250929050565b5f805f805f8060a087890312156125fd576125fc611cb4565b5b5f61260a89828a01611d85565b965050602061261b89828a01611d85565b955050604061262c89828a01611daf565b945050606061263d89828a01611daf565b935050608087013567ffffffffffffffff81111561265e5761265d611cb8565b5b61266a89828a01611dcf565b92509250509295509295509295565b5f82825260208201905092915050565b7f4e6f6e2d7369676e657220696e206f6e6c795369676e6572206d6574686f64005f82015250565b5f6126bd601f83612679565b91506126c882612689565b602082019050919050565b5f6020820190508181035f8301526126ea816126b1565b9050919050565b5f81519050919050565b5f81905092915050565b5f5b83811015612722578082015181840152602081019050612707565b5f8484015250505050565b5f612737826126f1565b61274181856126fb565b9350612751818560208601612705565b80840191505092915050565b5f8160601b9050919050565b5f6127738261275d565b9050919050565b5f61278482612769565b9050919050565b61279c61279782611b7e565b61277a565b82525050565b5f819050919050565b6127bc6127b782611b9e565b6127a2565b82525050565b5f6127cd828961272d565b91506127d9828861278b565b6014820191506127e982876127ab565b6020820191506127f9828661278b565b60148201915061280982856127ab565b60208201915061281982846127ab565b602082019150819050979650505050505050565b5f6020820190506128405f830184611b8f565b92915050565b5f82825260208201905092915050565b5f80fd5b82818337505050565b5f61286e8385612846565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156128a1576128a0612856565b5b6020830292506128b283858461285a565b82840190509392505050565b5f6040820190506128d15f830186611b8f565b81810360208301526128e4818486612863565b9050949350505050565b5f81905092915050565b5f61290383856128ee565b9350612910838584611c23565b82840190509392505050565b5f612927828a61272d565b9150612933828961278b565b60148201915061294382886127ab565b6020820191506129548286886128f8565b915061296082856127ab565b60208201915061297082846127ab565b60208201915081905098975050505050505050565b5f6129918284866128f8565b91508190509392505050565b7f43616c6c20657865637574696f6e206661696c656400000000000000000000005f82015250565b5f6129d1601583612679565b91506129dc8261299d565b602082019050919050565b5f6020820190508181035f8301526129fe816129c5565b9050919050565b5f819050919050565b612a1781612a05565b82525050565b5f60c082019050612a305f83018a611b8f565b612a3d6020830189611b8f565b612a4a6040830188612a0e565b612a576060830187611b8f565b612a646080830186611ba7565b81810360a0830152612a77818486611c41565b905098975050505050505050565b5f604082019050612a985f830185611b8f565b612aa56020830184611ba7565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f612b1082611b9e565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612b4257612b41612ad9565b5b600182019050919050565b5f612b5782611b9e565b9150612b6283611b9e565b9250828201905080821115612b7a57612b79612ad9565b5b92915050565b7f4e6f7420656e6f75676820726563697069656e747300000000000000000000005f82015250565b5f612bb4601583612679565b9150612bbf82612b80565b602082019050919050565b5f6020820190508181035f830152612be181612ba8565b9050919050565b7f556e657175616c20726563697069656e747320616e642076616c7565730000005f82015250565b5f612c1c601d83612679565b9150612c2782612be8565b602082019050919050565b5f6020820190508181035f830152612c4981612c10565b9050919050565b7f546f6f206d616e7920726563697069656e74732c206d617820323535000000005f82015250565b5f612c84601c83612679565b9150612c8f82612c50565b602082019050919050565b5f6020820190508181035f830152612cb181612c78565b9050919050565b5f81905092915050565b5f819050919050565b612cd481611b7e565b82525050565b5f612ce58383612ccb565b60208301905092915050565b5f612cff6020840184611d85565b905092915050565b5f602082019050919050565b5f612d1e8385612cb8565b9350612d2982612cc2565b805f5b85811015612d6157612d3e8284612cf1565b612d488882612cda565b9750612d5383612d07565b925050600181019050612d2c565b5085925050509392505050565b5f81905092915050565b5f612d838385612d6e565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115612db657612db5612856565b5b602083029250612dc783858461285a565b82840190509392505050565b5f612dde828a61272d565b9150612deb82888a612d13565b9150612df8828688612d78565b9150612e0482856127ab565b602082019150612e1482846127ab565b60208201915081905098975050505050505050565b7f426174636820696e2073616665206d6f646500000000000000000000000000005f82015250565b5f612e5d601283612679565b9150612e6882612e29565b602082019050919050565b5f6020820190508181035f830152612e8a81612e51565b9050919050565b5f606082019050612ea45f830186611b8f565b612eb16020830185611b8f565b612ebe6040830184612a0e565b949350505050565b7f436f6e747261637420616c726561647920696e697469616c697a6564000000005f82015250565b5f612efa601c83612679565b9150612f0582612ec6565b602082019050919050565b5f6020820190508181035f830152612f2781612eee565b9050919050565b7f496e76616c6964206e756d626572206f66207369676e657273000000000000005f82015250565b5f612f62601983612679565b9150612f6d82612f2e565b602082019050919050565b5f6020820190508181035f830152612f8f81612f56565b9050919050565b7f496e76616c6964207369676e65720000000000000000000000000000000000005f82015250565b5f612fca600e83612679565b9150612fd582612f96565b602082019050919050565b5f6020820190508181035f830152612ff781612fbe565b9050919050565b5f60ff82169050919050565b5f61301482612ffe565b915060ff820361302757613026612ad9565b5b600182019050919050565b7f45787465726e616c207472616e7366657220696e2073616665206d6f646500005f82015250565b5f613066601e83612679565b915061307182613032565b602082019050919050565b5f6020820190508181035f8301526130938161305a565b9050919050565b7f5472616e73616374696f6e2065787069726564000000000000000000000000005f82015250565b5f6130ce601383612679565b91506130d98261309a565b602082019050919050565b5f6020820190508181035f8301526130fb816130c2565b9050919050565b7f5369676e6572732063616e6e6f7420626520657175616c0000000000000000005f82015250565b5f613136601783612679565b915061314182613102565b602082019050919050565b5f6020820190508181035f8301526131638161312a565b9050919050565b5f81519050919050565b5f61317e8261316a565b61318881856128ee565b9350613198818560208601612705565b80840191505092915050565b5f6131af8284613174565b915081905092915050565b5f815190506131c881612314565b92915050565b5f602082840312156131e3576131e2611cb4565b5b5f6131f0848285016131ba565b91505092915050565b7f5472616e7366657248656c7065723a3a736166655472616e736665723a2074725f8201527f616e73666572206661696c656400000000000000000000000000000000000000602082015250565b5f613253602d83612679565b915061325e826131f9565b604082019050919050565b5f6020820190508181035f83015261328081613247565b9050919050565b7f496e73756666696369656e742066756e647300000000000000000000000000005f82015250565b5f6132bb601283612679565b91506132c682613287565b602082019050919050565b5f6020820190508181035f8301526132e8816132af565b9050919050565b5f6132fa5f836128ee565b915061330582611bc6565b5f82019050919050565b5f613319826132ef565b9150819050919050565b7f43616c6c206661696c65640000000000000000000000000000000000000000005f82015250565b5f613357600b83612679565b915061336282613323565b602082019050919050565b5f6020820190508181035f8301526133848161334b565b9050919050565b5f60608201905061339e5f830186611b8f565b6133ab6020830185611b8f565b6133b86040830184611ba7565b949350505050565b7f496e76616c6964207369676e6174757265202d2077726f6e67206c656e6774685f82015250565b5f6133f4602083612679565b91506133ff826133c0565b602082019050919050565b5f6020820190508181035f830152613421816133e8565b9050919050565b5f61343282612ffe565b915061343d83612ffe565b9250828201905060ff81111561345657613455612ad9565b5b92915050565b7f45434453413a20696e76616c6964207369676e6174757265202773272076616c5f8201527f7565000000000000000000000000000000000000000000000000000000000000602082015250565b5f6134b6602283612679565b91506134c18261345c565b604082019050919050565b5f6020820190508181035f8301526134e3816134aa565b9050919050565b6134f381612ffe565b82525050565b5f60808201905061350c5f830187612a0e565b61351960208301866134ea565b6135266040830185612a0e565b6135336060830184612a0e565b95945050505050565b7f53657175656e636520494420616c7265616479207573656400000000000000005f82015250565b5f613570601883612679565b915061357b8261353c565b602082019050919050565b5f6020820190508181035f83015261359d81613564565b9050919050565b7f53657175656e63652049442062656c6f772077696e646f7700000000000000005f82015250565b5f6135d8601883612679565b91506135e3826135a4565b602082019050919050565b5f6020820190508181035f830152613605816135cc565b9050919050565b7f53657175656e63652049442061626f7665206d6178696d756d000000000000005f82015250565b5f613640601983612679565b915061364b8261360c565b602082019050919050565b5f6020820190508181035f83015261366d81613634565b905091905056fea26469706673582212200c5a1256669073f019b8de41e297f5970cf2463edf5b2a09c205aec4be9c2dc964736f6c63430008140033'; + +export const walletSimpleAbi = [ + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'msgSender', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'otherSigner', + type: 'address', + }, + { + indexed: false, + internalType: 'bytes32', + name: 'operation', + type: 'bytes32', + }, + ], + name: 'BatchTransacted', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'recipient', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + ], + name: 'BatchTransfer', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'from', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + { + indexed: false, + internalType: 'bytes', + name: 'data', + type: 'bytes', + }, + ], + name: 'Deposited', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'msgSender', + type: 'address', + }, + ], + name: 'SafeModeActivated', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'msgSender', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'otherSigner', + type: 'address', + }, + { + indexed: false, + internalType: 'bytes32', + name: 'operation', + type: 'bytes32', + }, + { + indexed: false, + internalType: 'address', + name: 'toAddress', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + { + indexed: false, + internalType: 'bytes', + name: 'data', + type: 'bytes', + }, + ], + name: 'Transacted', + type: 'event', + }, + { + stateMutability: 'payable', + type: 'fallback', + }, + { + inputs: [], + name: 'activateSafeMode', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address payable', + name: 'forwarderAddress', + type: 'address', + }, + { + internalType: 'address', + name: 'tokenContractAddress', + type: 'address', + }, + { + internalType: 'uint256[]', + name: 'tokenIds', + type: 'uint256[]', + }, + ], + name: 'batchFlushERC1155ForwarderTokens', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address payable', + name: 'forwarderAddress', + type: 'address', + }, + { + internalType: 'address', + name: 'tokenContractAddress', + type: 'address', + }, + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256', + }, + ], + name: 'flushERC1155ForwarderTokens', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address payable', + name: 'forwarderAddress', + type: 'address', + }, + { + internalType: 'address', + name: 'tokenContractAddress', + type: 'address', + }, + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256', + }, + ], + name: 'flushERC721ForwarderTokens', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address payable', + name: 'forwarderAddress', + type: 'address', + }, + { + internalType: 'address', + name: 'tokenContractAddress', + type: 'address', + }, + ], + name: 'flushForwarderTokens', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'getNextSequenceId', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address[]', + name: 'allowedSigners', + type: 'address[]', + }, + ], + name: 'init', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'initialized', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'signer', + type: 'address', + }, + ], + name: 'isSigner', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_operator', + type: 'address', + }, + { + internalType: 'address', + name: '_from', + type: 'address', + }, + { + internalType: 'uint256[]', + name: 'ids', + type: 'uint256[]', + }, + { + internalType: 'uint256[]', + name: 'values', + type: 'uint256[]', + }, + { + internalType: 'bytes', + name: 'data', + type: 'bytes', + }, + ], + name: 'onERC1155BatchReceived', + outputs: [ + { + internalType: 'bytes4', + name: '', + type: 'bytes4', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_operator', + type: 'address', + }, + { + internalType: 'address', + name: '_from', + type: 'address', + }, + { + internalType: 'uint256', + name: 'id', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + { + internalType: 'bytes', + name: 'data', + type: 'bytes', + }, + ], + name: 'onERC1155Received', + outputs: [ + { + internalType: 'bytes4', + name: '', + type: 'bytes4', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_operator', + type: 'address', + }, + { + internalType: 'address', + name: '_from', + type: 'address', + }, + { + internalType: 'uint256', + name: '_tokenId', + type: 'uint256', + }, + { + internalType: 'bytes', + name: '_data', + type: 'bytes', + }, + ], + name: 'onERC721Received', + outputs: [ + { + internalType: 'bytes4', + name: '', + type: 'bytes4', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'safeMode', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'toAddress', + type: 'address', + }, + { + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + { + internalType: 'bytes', + name: 'data', + type: 'bytes', + }, + { + internalType: 'uint256', + name: 'expireTime', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'sequenceId', + type: 'uint256', + }, + { + internalType: 'bytes', + name: 'signature', + type: 'bytes', + }, + ], + name: 'sendMultiSig', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address[]', + name: 'recipients', + type: 'address[]', + }, + { + internalType: 'uint256[]', + name: 'values', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'expireTime', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'sequenceId', + type: 'uint256', + }, + { + internalType: 'bytes', + name: 'signature', + type: 'bytes', + }, + ], + name: 'sendMultiSigBatch', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'toAddress', + type: 'address', + }, + { + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + { + internalType: 'address', + name: 'tokenContractAddress', + type: 'address', + }, + { + internalType: 'uint256', + name: 'expireTime', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'sequenceId', + type: 'uint256', + }, + { + internalType: 'bytes', + name: 'signature', + type: 'bytes', + }, + ], + name: 'sendMultiSigToken', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'forwarderAddress', + type: 'address', + }, + { + internalType: 'bool', + name: 'autoFlush', + type: 'bool', + }, + ], + name: 'setAutoFlush1155', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'forwarderAddress', + type: 'address', + }, + { + internalType: 'bool', + name: 'autoFlush', + type: 'bool', + }, + ], + name: 'setAutoFlush721', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + name: 'signers', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'bytes4', + name: 'interfaceId', + type: 'bytes4', + }, + ], + name: 'supportsInterface', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + stateMutability: 'payable', + type: 'receive', + }, +]; diff --git a/modules/sdk-coin-arbeth/test/unit/arbeth.ts b/modules/sdk-coin-arbeth/test/unit/arbeth.ts index 1bba10a192..5ec74bf6db 100644 --- a/modules/sdk-coin-arbeth/test/unit/arbeth.ts +++ b/modules/sdk-coin-arbeth/test/unit/arbeth.ts @@ -23,7 +23,6 @@ describe('Arbitrum', function () { arbeth.getFamily().should.equal('arbeth'); arbeth.getFullName().should.equal('Arbitrum Ethereum'); arbeth.getBaseFactor().should.equal(1e18); - arbeth.supportsTss().should.equal(true); }); it('should return the right info for tarbeth', function () { @@ -34,7 +33,6 @@ describe('Arbitrum', function () { tarbeth.getFamily().should.equal('arbeth'); tarbeth.getFullName().should.equal('Testnet Arbitrum Ethereum'); tarbeth.getBaseFactor().should.equal(1e18); - tarbeth.supportsTss().should.equal(true); }); }); }); diff --git a/modules/sdk-coin-avaxc/package.json b/modules/sdk-coin-avaxc/package.json index 7036fc1c2e..055e2e1dad 100644 --- a/modules/sdk-coin-avaxc/package.json +++ b/modules/sdk-coin-avaxc/package.json @@ -46,7 +46,7 @@ "@bitgo/statics": "^29.0.0", "@bitgo/utxo-lib": "^9.16.0", "@ethereumjs/common": "^2.6.5", - "bignumber.js": "^8.0.1", + "bignumber.js": "^9.1.1", "ethereumjs-abi": "^0.6.5", "ethereumjs-util": "7.1.5", "keccak": "^3.0.3", diff --git a/modules/sdk-coin-bsc/src/bsc.ts b/modules/sdk-coin-bsc/src/bsc.ts index 6d0b197bba..68e0ab8f81 100644 --- a/modules/sdk-coin-bsc/src/bsc.ts +++ b/modules/sdk-coin-bsc/src/bsc.ts @@ -1,10 +1,10 @@ -import { BaseCoin, BitGoBase } from '@bitgo/sdk-core'; +import { BaseCoin, BitGoBase, MPCAlgorithm } from '@bitgo/sdk-core'; import { BaseCoin as StaticsBaseCoin, coins } from '@bitgo/statics'; -import { AbstractEthLikeMPCCoin } from '@bitgo/abstract-eth'; +import { AbstractEthLikeCoin } from '@bitgo/abstract-eth'; import { TransactionBuilder as EthTransactionBuilder } from '@bitgo/sdk-coin-eth'; import { TransactionBuilder } from './lib'; -export class Bsc extends AbstractEthLikeMPCCoin { +export class Bsc extends AbstractEthLikeCoin { protected constructor(bitgo: BitGoBase, staticsCoin?: Readonly) { super(bitgo, staticsCoin); } @@ -21,4 +21,14 @@ export class Bsc extends AbstractEthLikeMPCCoin { allowsAccountConsolidations(): boolean { return true; } + + /** @inheritDoc */ + supportsTss(): boolean { + return true; + } + + /** @inheritDoc */ + getMPCAlgorithm(): MPCAlgorithm { + return 'ecdsa'; + } } diff --git a/modules/sdk-coin-bsc/src/bscToken.ts b/modules/sdk-coin-bsc/src/bscToken.ts index f3489414ee..c015368b86 100644 --- a/modules/sdk-coin-bsc/src/bscToken.ts +++ b/modules/sdk-coin-bsc/src/bscToken.ts @@ -2,13 +2,14 @@ * @prettier */ -import { EthLikeTokenConfig } from '@bitgo/statics'; -import { BitGoBase, CoinConstructor, NamedCoinConstructor } from '@bitgo/sdk-core'; -import { CoinNames, EthLikeMPCToken } from '@bitgo/abstract-eth'; +import { EthLikeTokenConfig, coins } from '@bitgo/statics'; +import { BitGoBase, CoinConstructor, NamedCoinConstructor, MPCAlgorithm } from '@bitgo/sdk-core'; +import { CoinNames, EthLikeToken } from '@bitgo/abstract-eth'; +import { TransactionBuilder } from './lib'; export { EthLikeTokenConfig }; -export class BscToken extends EthLikeMPCToken { +export class BscToken extends EthLikeToken { public readonly tokenConfig: EthLikeTokenConfig; static coinNames: CoinNames = { Mainnet: 'bsc', @@ -25,6 +26,20 @@ export class BscToken extends EthLikeMPCToken { return super.createTokenConstructors(BscToken.coinNames); } + protected getTransactionBuilder(): TransactionBuilder { + return new TransactionBuilder(coins.get(this.getBaseChain())); + } + + /** @inheritDoc */ + supportsTss(): boolean { + return true; + } + + /** @inheritDoc */ + getMPCAlgorithm(): MPCAlgorithm { + return 'ecdsa'; + } + getFullName(): string { return 'Bsc Token'; } diff --git a/modules/sdk-coin-bsc/src/lib/transactionBuilder.ts b/modules/sdk-coin-bsc/src/lib/transactionBuilder.ts index debdb55ea1..ffb6f2aafd 100644 --- a/modules/sdk-coin-bsc/src/lib/transactionBuilder.ts +++ b/modules/sdk-coin-bsc/src/lib/transactionBuilder.ts @@ -27,4 +27,8 @@ export class TransactionBuilder extends EthTransactionBuilder { publicKey(key: string): void { this._sourceKeyPair = new KeyPair({ pub: key }); } + + protected getContractData(addresses: string[]): string { + throw new Error('Method not implemented.'); + } } diff --git a/modules/sdk-coin-eth/package.json b/modules/sdk-coin-eth/package.json index 9484a5d040..890b5d5ce1 100644 --- a/modules/sdk-coin-eth/package.json +++ b/modules/sdk-coin-eth/package.json @@ -40,6 +40,7 @@ ] }, "dependencies": { + "@bitgo/abstract-eth": "^1.6.0", "@bitgo/sdk-core": "^8.26.0", "@bitgo/sdk-lib-mpc": "^8.15.0", "@bitgo/statics": "^29.0.0", @@ -50,7 +51,6 @@ "@metamask/eth-sig-util": "^5.0.2", "bignumber.js": "^9.0.0", "bn.js": "^5.2.1", - "debug": "^3.1.0", "ethereumjs-abi": "^0.6.5", "ethereumjs-util": "7.1.5", "ethers": "^5.1.3", diff --git a/modules/sdk-coin-eth/src/eth.ts b/modules/sdk-coin-eth/src/eth.ts index b1f76e421b..771ca15ef0 100644 --- a/modules/sdk-coin-eth/src/eth.ts +++ b/modules/sdk-coin-eth/src/eth.ts @@ -4,7 +4,6 @@ import { bip32 } from '@bitgo/utxo-lib'; import { BigNumber } from 'bignumber.js'; import { randomBytes } from 'crypto'; -import debugLib from 'debug'; import Keccak from 'keccak'; import _ from 'lodash'; import secp256k1 from 'secp256k1'; @@ -20,7 +19,6 @@ import { ECDSA, Ecdsa, ECDSAMethodTypes, - EthereumLibraryUnavailableError, FeeEstimateOptions, FullySignedTransaction, getIsKrsRecovery, @@ -39,8 +37,6 @@ import { Recipient, SignTransactionOptions as BaseSignTransactionOptions, TransactionParams, - TransactionPrebuild as BaseTransactionPrebuild, - TransactionRecipient, TypedData, UnexpectedAddressError, Util, @@ -49,68 +45,20 @@ import { Wallet, } from '@bitgo/sdk-core'; import { EcdsaPaillierProof, EcdsaRangeProof, EcdsaTypes } from '@bitgo/sdk-lib-mpc'; +import { TransactionPrebuild, optionalDeps } from '@bitgo/abstract-eth'; import { BaseCoin as StaticsBaseCoin, coins, EthereumNetwork, ethGasConfigs } from '@bitgo/statics'; import type * as EthTxLib from '@ethereumjs/tx'; import { FeeMarketEIP1559Transaction, Transaction as LegacyTransaction } from '@ethereumjs/tx'; import type * as EthCommon from '@ethereumjs/common'; -import { - calculateForwarderV1Address, - getProxyInitcode, - getToken, - KeyPair as KeyPairLib, - TransactionBuilder, - TransferBuilder, -} from './lib'; +import { calculateForwarderV1Address, getProxyInitcode, getToken, KeyPair as KeyPairLib } from './lib'; import { addHexPrefix, stripHexPrefix } from 'ethereumjs-util'; import BN from 'bn.js'; import { SignTypedDataVersion, TypedDataUtils, TypedMessage } from '@metamask/eth-sig-util'; +import { TransactionBuilder } from './lib/transactionBuilder'; +import { TransferBuilder } from './lib/transferBuilder'; -export { Recipient, HalfSignedTransaction, FullySignedTransaction }; - -const debug = debugLib('bitgo:v2:eth'); - -export const optionalDeps = { - get ethAbi() { - try { - return require('ethereumjs-abi'); - } catch (e) { - debug('unable to load ethereumjs-abi:'); - debug(e.stack); - throw new EthereumLibraryUnavailableError(`ethereumjs-abi`); - } - }, - - get ethUtil() { - try { - return require('ethereumjs-util'); - } catch (e) { - debug('unable to load ethereumjs-util:'); - debug(e.stack); - throw new EthereumLibraryUnavailableError(`ethereumjs-util`); - } - }, - - get EthTx(): typeof EthTxLib { - try { - return require('@ethereumjs/tx'); - } catch (e) { - debug('unable to load @ethereumjs/tx'); - debug(e.stack); - throw new EthereumLibraryUnavailableError(`@ethereumjs/tx`); - } - }, - - get EthCommon(): typeof EthCommon { - try { - return require('@ethereumjs/common'); - } catch (e) { - debug('unable to load @ethereumjs/common:'); - debug(e.stack); - throw new EthereumLibraryUnavailableError(`@ethereumjs/common`); - } - }, -}; +export { Recipient, HalfSignedTransaction, FullySignedTransaction, TransactionPrebuild, optionalDeps }; /** * The extra parameters to send to platform build route for hop transactions @@ -307,20 +255,6 @@ interface FeeEstimate { feeEstimate: number; } -export interface TransactionPrebuild extends BaseTransactionPrebuild { - hopTransaction?: HopPrebuild; - buildParams: { - recipients: Recipient[]; - }; - recipients: TransactionRecipient[]; - nextContractSequenceId: string; - gasPrice: number; - gasLimit: number; - isBatch: boolean; - coin: string; - token?: string; -} - // TODO: This interface will need to be updated for the new fee model introduced in the London Hard Fork interface EthTransactionParams extends TransactionParams { gasPrice?: number; diff --git a/modules/sdk-coin-eth/src/lib/index.ts b/modules/sdk-coin-eth/src/lib/index.ts index ae53d5a67b..cc9125d691 100644 --- a/modules/sdk-coin-eth/src/lib/index.ts +++ b/modules/sdk-coin-eth/src/lib/index.ts @@ -1,17 +1,10 @@ -export * from './contractCall'; -export * from './iface'; -export * from './keyPair'; -export * from './transaction'; -export * from './transactionBuilder'; -export * from './transferBuilder'; -export * from './transferBuilders'; -export * from './transferBuilder'; -export * from './types'; -export * from './utils'; -export * from './walletUtil'; - // for Backwards Compatibility -import * as Interface from './iface'; -import * as Utils from './utils'; +export * from '@bitgo/abstract-eth'; + +// exporting Ethereum TransactionBuilder and TransferBuilder +export { TransactionBuilder } from './transactionBuilder'; +export { TransferBuilder } from './transferBuilder'; +// for Backwards Compatibility +import { Interface, Utils } from '@bitgo/abstract-eth'; export { Interface, Utils }; diff --git a/modules/sdk-coin-eth/src/lib/transactionBuilder.ts b/modules/sdk-coin-eth/src/lib/transactionBuilder.ts index 728ce0024d..7e9a3761cb 100644 --- a/modules/sdk-coin-eth/src/lib/transactionBuilder.ts +++ b/modules/sdk-coin-eth/src/lib/transactionBuilder.ts @@ -1,95 +1,21 @@ import { BaseCoin as CoinConfig, EthereumNetwork } from '@bitgo/statics'; -import EthereumCommon from '@ethereumjs/common'; import EthereumAbi from 'ethereumjs-abi'; -import BigNumber from 'bignumber.js'; - -import { - BaseAddress, - BaseKey, - BaseTransaction, - BaseTransactionBuilder, - BuildTransactionError, - InvalidTransactionError, - isValidPrv, - isValidXprv, - ParseTransactionError, - SigningError, - TransactionType, -} from '@bitgo/sdk-core'; - -import { KeyPair } from './keyPair'; -import { ETHTransactionType, Fee, SignatureParts, TxData } from './iface'; import { - calculateForwarderAddress, - calculateForwarderV1Address, - classifyTransaction, - decodeForwarderCreationData, - decodeFlushTokensData, - decodeWalletCreationData, - flushCoinsData, - flushTokensData, - getAddressInitializationData, - getV1AddressInitializationData, + Transaction, getCommon, - getProxyInitcode, - hasSignature, - isValidEthAddress, - getV1WalletInitializationData, -} from './utils'; -import { - defaultWalletVersion, - walletSimpleByteCode, + TransactionBuilder as EthLikeTransactionBuilder, + TransferBuilder, walletSimpleConstructor, - defaultForwarderVersion, -} from './walletUtil'; -import * as ethUtil from 'ethereumjs-util'; -import { FeeMarketEIP1559Transaction } from '@ethereumjs/tx'; -import { ERC1155TransferBuilder } from './transferBuilders/transferBuilderERC1155'; -import { ERC721TransferBuilder } from './transferBuilders/transferBuilderERC721'; -import { Transaction } from './transaction'; -import { TransferBuilder } from './transferBuilder'; +} from '@bitgo/abstract-eth'; +import { BuildTransactionError, TransactionType } from '@bitgo/sdk-core'; -const DEFAULT_M = 3; +import { walletSimpleByteCode } from './walletUtil'; +import { ERC721TransferBuilder, ERC1155TransferBuilder } from './transferBuilders'; /** * Ethereum transaction builder. */ -export class TransactionBuilder extends BaseTransactionBuilder { - protected _type: TransactionType; - // Specifies common chain and hardfork parameters. - protected _common: EthereumCommon; - protected _sourceKeyPair: KeyPair; - private _transaction: Transaction; - private _counter: number; - private _fee: Fee; - protected _value: string; - - // the signature on the external ETH transaction - private _txSignature: SignatureParts; - - // Wallet initialization transaction parameters - private _walletOwnerAddresses: string[]; - private _walletVersion: number; - - // flush tokens parameters - private _forwarderAddress: string; - private _tokenAddress: string; - - // Send and AddressInitialization transaction specific parameters - protected _transfer: TransferBuilder | ERC721TransferBuilder | ERC1155TransferBuilder; - private _contractAddress: string; - private _contractCounter: number; - private _forwarderVersion: number; - private _initCode: string; - private _baseAddress: string; - - // generic contract call builder - // encoded contract call hex - private _data: string; - - // Common parameter for wallet initialization and address initialization transaction - private _salt: string; - +export class TransactionBuilder extends EthLikeTransactionBuilder { /** * Public constructor. * @@ -98,480 +24,9 @@ export class TransactionBuilder extends BaseTransactionBuilder { constructor(_coinConfig: Readonly) { super(_coinConfig); this._common = getCommon(this._coinConfig.network as EthereumNetwork); - this._type = TransactionType.Send; - this._counter = 0; - this._value = '0'; - this._walletOwnerAddresses = []; - this._forwarderVersion = 0; - this._walletVersion = 0; this.transaction = new Transaction(this._coinConfig, this._common); } - /** @inheritdoc */ - protected async buildImplementation(): Promise { - const transactionData = this.getTransactionData(); - - if (this._txSignature) { - Object.assign(transactionData, this._txSignature); - } - - this.transaction.setTransactionType(this._type); - transactionData.from = this._sourceKeyPair ? this._sourceKeyPair.getAddress() : undefined; - this.transaction.setTransactionData(transactionData); - - // Build and sign a new transaction based on the latest changes - if (this._sourceKeyPair && this._sourceKeyPair.getKeys().prv) { - await this.transaction.sign(this._sourceKeyPair); - } - return this.transaction; - } - - protected getTransactionData(): TxData { - switch (this._type) { - case TransactionType.WalletInitialization: - return this.buildWalletInitializationTransaction(this._walletVersion); - case TransactionType.RecoveryWalletDeployment: - return this.buildBase(this._data); - case TransactionType.Send: - case TransactionType.SendERC721: - case TransactionType.SendERC1155: - return this.buildSendTransaction(); - case TransactionType.AddressInitialization: - return this.buildAddressInitializationTransaction(); - case TransactionType.FlushTokens: - return this.buildFlushTokensTransaction(); - case TransactionType.FlushCoins: - return this.buildFlushCoinsTransaction(); - case TransactionType.SingleSigSend: - return this.buildBase('0x'); - case TransactionType.ContractCall: - return this.buildGenericContractCallTransaction(); - default: - throw new BuildTransactionError('Unsupported transaction type'); - } - } - - /** @inheritdoc */ - protected fromImplementation(rawTransaction: string): Transaction { - let tx: Transaction; - if (/^0x?[0-9a-f]{1,}$/.test(rawTransaction.toLowerCase())) { - tx = Transaction.fromSerialized(this._coinConfig, this._common, rawTransaction); - this.loadBuilderInput(tx.toJson()); - } else { - const txData = JSON.parse(rawTransaction); - tx = new Transaction(this._coinConfig, txData); - } - return tx; - } - - /** - * Load the builder data using the deserialized transaction - * - * @param {TxData} transactionJson the deserialized transaction json - */ - protected loadBuilderInput(transactionJson: TxData): void { - const decodedType = classifyTransaction(transactionJson.data); - this.type(decodedType); - this.counter(transactionJson.nonce); - this.value(transactionJson.value); - - if (transactionJson._type === ETHTransactionType.LEGACY) { - this.fee({ - fee: transactionJson.gasPrice, - gasPrice: transactionJson.gasPrice, - gasLimit: transactionJson.gasLimit, - }); - } else { - this.fee({ - gasLimit: transactionJson.gasLimit, - fee: transactionJson.maxFeePerGas, - eip1559: { - maxFeePerGas: transactionJson.maxFeePerGas, - maxPriorityFeePerGas: transactionJson.maxPriorityFeePerGas, - }, - }); - } - - if (hasSignature(transactionJson)) { - this._txSignature = { v: transactionJson.v!, r: transactionJson.r!, s: transactionJson.s! }; - } - this.setTransactionTypeFields(decodedType, transactionJson); - } - - protected setTransactionTypeFields(decodedType: TransactionType, transactionJson: TxData): void { - switch (decodedType) { - case TransactionType.WalletInitialization: - const { owners, salt } = decodeWalletCreationData(transactionJson.data); - owners.forEach((element) => { - this.owner(element); - }); - if (salt) { - this.salt(salt as string); - this.walletVersion(1); - this.setContract(transactionJson.to); - } - break; - case TransactionType.RecoveryWalletDeployment: - this.data(transactionJson.data); - break; - case TransactionType.FlushTokens: - this.setContract(transactionJson.to); - const { forwarderAddress, tokenAddress } = decodeFlushTokensData(transactionJson.data); - this.forwarderAddress(forwarderAddress); - this.tokenAddress(tokenAddress); - break; - case TransactionType.FlushCoins: - this.setContract(transactionJson.to); - break; - case TransactionType.Send: - case TransactionType.SendERC1155: - case TransactionType.SendERC721: - this.setContract(transactionJson.to); - this._transfer = this.transfer(transactionJson.data); - break; - case TransactionType.AddressInitialization: - this.setContract(transactionJson.to); - const { baseAddress, addressCreationSalt } = decodeForwarderCreationData(transactionJson.data); - if (baseAddress && addressCreationSalt) { - this.forwarderVersion(1); - this.baseAddress(baseAddress); - this.salt(addressCreationSalt); - const forwarderImplementationAddress = (this._coinConfig.network as EthereumNetwork) - .forwarderImplementationAddress as string; - if (forwarderImplementationAddress) { - this.initCode(forwarderImplementationAddress); - } - } - break; - case TransactionType.SingleSigSend: - this.setContract(transactionJson.to); - break; - case TransactionType.ContractCall: - this.setContract(transactionJson.to); - this.data(transactionJson.data); - break; - default: - throw new BuildTransactionError('Unsupported transaction type'); - // TODO: Add other cases of deserialization - } - } - - /** @inheritdoc */ - protected signImplementation(key: BaseKey): BaseTransaction { - const signer = new KeyPair({ prv: key.key }); - if (this._type === TransactionType.WalletInitialization && this._walletOwnerAddresses.length === 0) { - throw new SigningError('Cannot sign an wallet initialization transaction without owners'); - } - if (this._sourceKeyPair) { - throw new SigningError('Cannot sign multiple times a non send-type transaction'); - } - // Signing the transaction is an async operation, so save the source and leave the actual - // signing for the build step - this._sourceKeyPair = signer; - return this.transaction; - } - - /** @inheritdoc */ - validateAddress(address: BaseAddress): void { - if (!isValidEthAddress(address.address)) { - throw new BuildTransactionError('Invalid address ' + address.address); - } - } - - /** @inheritdoc */ - validateKey(key: BaseKey): void { - if (!(isValidXprv(key.key) || isValidPrv(key.key))) { - throw new BuildTransactionError('Invalid key'); - } - } - - /** - * Validate the raw transaction is either a JSON or - * a hex encoded transaction - * - * @param {any} rawTransaction The raw transaction to be validated - */ - validateRawTransaction(rawTransaction: any): void { - if (!rawTransaction) { - throw new InvalidTransactionError('Raw transaction is empty'); - } - if (typeof rawTransaction === 'string') { - if (/^0x?[0-9a-f]{1,}$/.test(rawTransaction.toLowerCase())) { - const txBytes = ethUtil.toBuffer(ethUtil.addHexPrefix(rawTransaction.toLowerCase())); - if (!this.isEip1559Txn(txBytes) && !this.isRLPDecodable(txBytes)) { - throw new ParseTransactionError('There was error in decoding the hex string'); - } - } else { - try { - JSON.parse(rawTransaction); - } catch (e) { - throw new ParseTransactionError('There was error in parsing the JSON string'); - } - } - } else { - throw new InvalidTransactionError('Transaction is not a hex string or stringified json'); - } - } - - private isEip1559Txn(txn: Buffer): boolean { - try { - FeeMarketEIP1559Transaction.fromSerializedTx(txn); - return true; - } catch (_) { - return false; - } - } - - private isRLPDecodable(bytes: Buffer): boolean { - try { - ethUtil.rlp.decode(bytes); - return true; - } catch (_) { - return false; - } - } - - protected validateBaseTransactionFields(): void { - if (this._fee === undefined || (!this._fee.fee && !this._fee.gasPrice && !this._fee.eip1559)) { - throw new BuildTransactionError('Invalid transaction: missing fee'); - } - if (this._common === undefined) { - throw new BuildTransactionError('Invalid transaction: network common'); - } - if (this._counter === undefined) { - throw new BuildTransactionError('Invalid transaction: missing address counter'); - } - } - - /** @inheritdoc */ - validateTransaction(transaction: BaseTransaction): void { - this.validateBaseTransactionFields(); - switch (this._type) { - case TransactionType.WalletInitialization: - this.validateWalletInitializationFields(); - break; - case TransactionType.RecoveryWalletDeployment: - this.validateDataField(); - break; - case TransactionType.Send: - case TransactionType.SendERC721: - case TransactionType.SendERC1155: - this.validateContractAddress(); - break; - case TransactionType.AddressInitialization: - this.validateContractAddress(); - break; - case TransactionType.FlushCoins: - this.validateContractAddress(); - break; - case TransactionType.FlushTokens: - this.validateContractAddress(); - this.validateForwarderAddress(); - this.validateTokenAddress(); - break; - case TransactionType.SingleSigSend: - // for single sig sends, the contract address is actually the recipient - this.validateContractAddress(); - break; - case TransactionType.StakingLock: - case TransactionType.StakingUnlock: - case TransactionType.StakingVote: - case TransactionType.StakingUnvote: - case TransactionType.StakingActivate: - case TransactionType.StakingWithdraw: - break; - case TransactionType.ContractCall: - this.validateContractAddress(); - this.validateDataField(); - break; - default: - throw new BuildTransactionError('Unsupported transaction type'); - } - } - - /** - * Check wallet owner addresses for wallet initialization transactions are valid or throw. - */ - private validateWalletInitializationFields(): void { - if (this._walletOwnerAddresses === undefined) { - throw new BuildTransactionError('Invalid transaction: missing wallet owners'); - } - - if (this._walletOwnerAddresses.length !== 3) { - throw new BuildTransactionError( - `Invalid transaction: wrong number of owners -- required: 3, found: ${this._walletOwnerAddresses.length}` - ); - } - } - - /** - * Check if a token address for the tx was defined or throw. - */ - private validateTokenAddress(): void { - if (this._tokenAddress === undefined) { - throw new BuildTransactionError('Invalid transaction: missing token address'); - } - } - - /** - * Check if a forwarder address for the tx was defined or throw. - */ - private validateForwarderAddress(): void { - if (this._forwarderAddress === undefined) { - throw new BuildTransactionError('Invalid transaction: missing forwarder address'); - } - } - - /** - * Check if a contract address for the wallet was defined or throw. - */ - private validateContractAddress(): void { - if (this._contractAddress === undefined) { - throw new BuildTransactionError('Invalid transaction: missing contract address'); - } - } - - /** - * Checks if a contract call data field was defined or throws otherwise - */ - private validateDataField(): void { - if (!this._data) { - throw new BuildTransactionError('Invalid transaction: missing contract call data field'); - } - } - - private setContract(address: string | undefined): void { - if (address === undefined) { - throw new BuildTransactionError('Undefined recipient address'); - } - this.contract(address); - } - - validateValue(value: BigNumber): void { - if (value.isLessThan(0)) { - throw new BuildTransactionError('Value cannot be below less than zero'); - } - // TODO: validate the amount is not bigger than the max amount in each Eth family coin - } - - // region Common builder methods - - /** - * The type of transaction being built. - * - * @param {TransactionType} type - */ - type(type: TransactionType): void { - this._type = type; - } - - /** - * Set the transaction fees. Low fees may get a transaction rejected or never picked up by bakers. - * - * @param {Fee} fee Baker fees. May also include the maximum gas to pay - */ - fee(fee: Fee): void { - this.validateValue(new BigNumber(fee.fee)); - if (fee.gasLimit) { - this.validateValue(new BigNumber(fee.gasLimit)); - } - if (fee.eip1559) { - this.validateValue(new BigNumber(fee.eip1559.maxFeePerGas)); - this.validateValue(new BigNumber(fee.eip1559.maxPriorityFeePerGas)); - } - if (fee.gasPrice) { - this.validateValue(new BigNumber(fee.gasPrice)); - } - this._fee = fee; - } - - /** - * Set the transaction counter to prevent submitting repeated transactions. - * - * @param {number} counter The counter to use - */ - counter(counter: number): void { - if (counter < 0) { - throw new BuildTransactionError(`Invalid counter: ${counter}`); - } - - this._counter = counter; - } - - /** - * The value to send along with this transaction. 0 by default - * - * @param {string} value The value to send along with this transaction - */ - value(value: string): void { - this._value = value; - } - - // set args that are required for all types of eth transactions - protected buildBase(data: string): TxData { - const baseParams = { - gasLimit: this._fee.gasLimit, - nonce: this._counter, - data: data, - chainId: this._common.chainIdBN().toString(), - value: this._value, - to: this._contractAddress, - }; - - if (this._fee.eip1559) { - return { - ...baseParams, - _type: ETHTransactionType.EIP1559, - maxFeePerGas: this._fee.eip1559.maxFeePerGas, - maxPriorityFeePerGas: this._fee.eip1559.maxPriorityFeePerGas, - }; - } else { - return { - ...baseParams, - _type: ETHTransactionType.LEGACY, - gasPrice: this._fee?.gasPrice ?? this._fee.fee, - v: this.getFinalV(), - }; - } - } - - // endregion - - // region WalletInitialization builder methods - /** - * Set one of the owners of the multisig wallet. - * - * @param {string} address An Ethereum address - */ - owner(address: string): void { - if (this._type !== TransactionType.WalletInitialization) { - throw new BuildTransactionError('Multisig wallet owner can only be set for initialization transactions'); - } - if (this._walletOwnerAddresses.length >= DEFAULT_M) { - throw new BuildTransactionError('A maximum of ' + DEFAULT_M + ' owners can be set for a multisig wallet'); - } - if (!isValidEthAddress(address)) { - throw new BuildTransactionError('Invalid address: ' + address); - } - if (this._walletOwnerAddresses.includes(address)) { - throw new BuildTransactionError('Repeated owner address: ' + address); - } - this._walletOwnerAddresses.push(address); - } - - /** - * Build a transaction for a generic multisig contract. - * - * @returns {TxData} The Ethereum transaction data - */ - protected buildWalletInitializationTransaction(walletVersion?: number): TxData { - const walletInitData = - walletVersion === defaultWalletVersion - ? this.getContractData(this._walletOwnerAddresses) - : getV1WalletInitializationData(this._walletOwnerAddresses, this._salt); - return this.buildBase(walletInitData); - } - /** * Returns the smart contract encoded data * @@ -587,15 +42,6 @@ export class TransactionBuilder extends BaseTransactionBuilder { } // endregion - // region Send builder methods - - contract(address: string): void { - if (!isValidEthAddress(address)) { - throw new BuildTransactionError('Invalid address: ' + address); - } - this._contractAddress = address; - } - /** * Gets the transfer funds builder if exist, or creates a new one for this transaction and returns it * @@ -622,205 +68,4 @@ export class TransactionBuilder extends BaseTransactionBuilder { } return this._transfer; } - - /** - * Returns the serialized sendMultiSig contract method data - * - * @returns {string} serialized sendMultiSig data - */ - private getSendData(): string { - if (!this._transfer) { - throw new BuildTransactionError('Missing transfer information'); - } - return this._transfer.signAndBuild(); - } - - private buildSendTransaction(): TxData { - const sendData = this.getSendData(); - const tx: TxData = this.buildBase(sendData); - tx.to = this._contractAddress; - return tx; - } - - // endregion - - // region AddressInitialization builder methods - - /** - * Set the contract transaction nonce to calculate the forwarder address. - * - * @param {number} contractCounter The counter to use - */ - contractCounter(contractCounter: number): void { - if (contractCounter < 0) { - throw new BuildTransactionError(`Invalid contract counter: ${contractCounter}`); - } - - this._contractCounter = contractCounter; - } - - /** - * Build a transaction to create a forwarder. - * - * @returns {TxData} The Ethereum transaction data - */ - private buildAddressInitializationTransaction(): TxData { - const addressInitData = - this._forwarderVersion === defaultForwarderVersion - ? getAddressInitializationData() - : getV1AddressInitializationData(this._baseAddress, this._salt); - const tx: TxData = this.buildBase(addressInitData); - tx.to = this._contractAddress; - - if (this._contractCounter) { - tx.deployedAddress = calculateForwarderAddress(this._contractAddress, this._contractCounter); - } - - if (this._salt && this._initCode) { - const saltBuffer = ethUtil.setLengthLeft(ethUtil.toBuffer(this._salt), 32); - // Hash the wallet base address with the given salt, so the address directly relies on the base address - const calculationSalt = ethUtil.bufferToHex( - EthereumAbi.soliditySHA3(['address', 'bytes32'], [this._baseAddress, saltBuffer]) - ); - tx.deployedAddress = calculateForwarderV1Address(this._contractAddress, calculationSalt, this._initCode); - } - return tx; - } - // endregion - - // region flush methods - /** - * Set the forwarder address to flush - * - * @param {string} address The address to flush - */ - forwarderAddress(address: string): void { - if (!isValidEthAddress(address)) { - throw new BuildTransactionError('Invalid address: ' + address); - } - this._forwarderAddress = address; - } - - /** - * Set the address of the ERC20 token contract that we are flushing tokens for - * - * @param {string} address the contract address of the token to flush - */ - tokenAddress(address: string): void { - if (!isValidEthAddress(address)) { - throw new BuildTransactionError('Invalid address: ' + address); - } - this._tokenAddress = address; - } - - /** - * Build a transaction to flush tokens from a forwarder. - * - * @returns {TxData} The Ethereum transaction data - */ - private buildFlushTokensTransaction(): TxData { - return this.buildBase(flushTokensData(this._forwarderAddress, this._tokenAddress)); - } - - /** - * Build a transaction to flush tokens from a forwarder. - * - * @returns {TxData} The Ethereum transaction data - */ - private buildFlushCoinsTransaction(): TxData { - return this.buildBase(flushCoinsData()); - } - // endregion - - // region generic contract call - data(encodedCall: string): void { - const supportedTransactionTypes = [TransactionType.ContractCall, TransactionType.RecoveryWalletDeployment]; - if (!supportedTransactionTypes.includes(this._type)) { - throw new BuildTransactionError('data can only be set for contract call transaction types'); - } - this._data = encodedCall; - } - - private buildGenericContractCallTransaction(): TxData { - return this.buildBase(this._data); - } - // endregion - - /** @inheritdoc */ - protected get transaction(): Transaction { - return this._transaction; - } - - /** @inheritdoc */ - protected set transaction(transaction: Transaction) { - this._transaction = transaction; - } - - /** - * Get the final v value. Final v is described in EIP-155. - * - * @protected for internal use when the enableFinalVField flag is true. - */ - protected getFinalV(): string { - return ethUtil.addHexPrefix(this._common.chainIdBN().muln(2).addn(35).toString(16)); - } - - /** - * Set the forwarder version for address to be initialized - * - * @param {number} version forwarder version - */ - forwarderVersion(version: number): void { - if (version < 0 || version > 2) { - throw new BuildTransactionError(`Invalid forwarder version: ${version}`); - } - - this._forwarderVersion = version; - } - - /** - * Set the salt to create the address using create2 - * - * @param {string} salt The salt to create the address using create2, hex string - */ - salt(salt: string): void { - this._salt = salt; - } - - /** - * Take the implementation address for the proxy contract, and get the binary initcode for the associated proxy - * - * @param {string} implementationAddress The address of the implementation contract - */ - initCode(implementationAddress: string): void { - if (!isValidEthAddress(implementationAddress)) { - throw new BuildTransactionError('Invalid address: ' + implementationAddress); - } - this._initCode = getProxyInitcode(implementationAddress); - } - - /** - * Set the wallet version for wallet to be initialized - * - * @param {number} version wallet version - */ - walletVersion(version: number): void { - if (version < 0 || version > 3) { - throw new BuildTransactionError(`Invalid wallet version: ${version}`); - } - - this._walletVersion = version; - } - - /** - * Set the base address of the wallet - * - * @param {string} address The wallet contract address - */ - baseAddress(address: string): void { - if (!isValidEthAddress(address)) { - throw new BuildTransactionError('Invalid address: ' + address); - } - this._baseAddress = address; - } } diff --git a/modules/sdk-coin-eth/src/lib/transferBuilder.ts b/modules/sdk-coin-eth/src/lib/transferBuilder.ts index a010fb7e5a..502bca7c9a 100644 --- a/modules/sdk-coin-eth/src/lib/transferBuilder.ts +++ b/modules/sdk-coin-eth/src/lib/transferBuilder.ts @@ -1,170 +1,7 @@ -import * as ethUtil from 'ethereumjs-util'; -import EthereumAbi from 'ethereumjs-abi'; -import BN from 'bn.js'; -import { coins, BaseCoin, ContractAddressDefinedToken } from '@bitgo/statics'; -import { BuildTransactionError, InvalidParameterValueError } from '@bitgo/sdk-core'; -import { decodeTransferData, sendMultiSigData, sendMultiSigTokenData, isValidEthAddress, isValidAmount } from './utils'; +import { TransferBuilder as EthTransferBuilder } from '@bitgo/abstract-eth'; /** ETH transfer builder */ -export class TransferBuilder { - private readonly _EMPTY_HEX_VALUE = '0x'; - protected _amount: string; - protected _toAddress: string; - protected _sequenceId: number; - protected _signKey: string; - protected _expirationTime: number; - protected _signature: string; - private _data: string; - private _tokenContractAddress?: string; - private _coin: Readonly; - - constructor(serializedData?: string) { - if (serializedData) { - this.decodeTransferData(serializedData); - } else { - // initialize with default values for non mandatory fields - this._expirationTime = this.getExpirationTime(); - this._data = this._EMPTY_HEX_VALUE; - this._signature = this._EMPTY_HEX_VALUE; - } - } - - /** - * A method to set the ERC20 token to be transferred. - * This ERC20 token may not be compatible with the network. - * - * @param {string} coin the ERC20 coin to be set - * @returns {TransferBuilder} the transfer builder instance modified - */ - coin(coin: string): TransferBuilder { - this._coin = coins.get(coin); - - if (this._coin instanceof ContractAddressDefinedToken) { - this._tokenContractAddress = this._coin.contractAddress.toString(); - } - - return this; - } - - data(additionalData: string): TransferBuilder { - this._signature = this._EMPTY_HEX_VALUE; - this._data = additionalData; - return this; - } - - amount(amount: string): this { - if (!isValidAmount(amount)) { - throw new InvalidParameterValueError('Invalid amount'); - } - this._signature = this._EMPTY_HEX_VALUE; - this._amount = amount; - return this; - } - - to(address: string): TransferBuilder { - if (isValidEthAddress(address)) { - this._signature = this._EMPTY_HEX_VALUE; - this._toAddress = address; - return this; - } - throw new InvalidParameterValueError('Invalid address'); - } - - contractSequenceId(counter: number): TransferBuilder { - if (counter >= 0) { - this._signature = this._EMPTY_HEX_VALUE; - this._sequenceId = counter; - return this; - } - throw new InvalidParameterValueError('Invalid contract sequence id'); - } - - key(signKey: string): TransferBuilder { - this._signKey = signKey; - return this; - } - - expirationTime(date: number): TransferBuilder { - if (date > 0) { - this._signature = this._EMPTY_HEX_VALUE; - this._expirationTime = date; - return this; - } - throw new InvalidParameterValueError('Invalid expiration time'); - } - - signAndBuild(): string { - if (this.hasMandatoryFields()) { - if (this._tokenContractAddress !== undefined) { - return sendMultiSigTokenData( - this._toAddress, - this._amount, - this._tokenContractAddress, - this._expirationTime, - this._sequenceId, - this.getSignature() - ); - } else { - return sendMultiSigData( - this._toAddress, - this._amount, - this._data, - this._expirationTime, - this._sequenceId, - this.getSignature() - ); - } - } - throw new BuildTransactionError( - 'Missing transfer mandatory fields. Amount, destination (to) address and sequenceID are mandatory' - ); - } - - private hasMandatoryFields(): boolean { - return this._amount !== undefined && this._toAddress !== undefined && this._sequenceId !== undefined; - } - - /** - * Obtains the proper operation hash to sign either a sendMultiSig data - * or a sendMultiSigToken data - * - * @returns {string} the operation hash - */ - private getOperationHash(): string { - const operationData = this.getOperationData(); - return ethUtil.bufferToHex(EthereumAbi.soliditySHA3(...operationData)); - } - - protected getOperationData(): (string | Buffer)[][] { - let operationData; - if (this._tokenContractAddress !== undefined) { - operationData = [ - ['string', 'address', 'uint', 'address', 'uint', 'uint'], - [ - this.getTokenOperationHashPrefix(), - new BN(ethUtil.stripHexPrefix(this._toAddress), 16), - this._amount, - new BN(ethUtil.stripHexPrefix(this._tokenContractAddress), 16), - this._expirationTime, - this._sequenceId, - ], - ]; - } else { - operationData = [ - ['string', 'address', 'uint', 'bytes', 'uint', 'uint'], - [ - this.getNativeOperationHashPrefix(), - new BN(ethUtil.stripHexPrefix(this._toAddress), 16), - this._amount, - Buffer.from(ethUtil.padToEven(ethUtil.stripHexPrefix(this._data)) || '', 'hex'), - this._expirationTime, - this._sequenceId, - ], - ]; - } - return operationData; - } - +export class TransferBuilder extends EthTransferBuilder { /** * Get the prefix used in generating an operation hash for sending tokens * @@ -182,64 +19,4 @@ export class TransferBuilder { protected getNativeOperationHashPrefix(): string { return 'ETHER'; } - - /** Return an expiration time, in seconds, set to one hour from now - * - * @returns {number} expiration time - */ - private getExpirationTime(): number { - const currentDate = new Date(); - currentDate.setHours(currentDate.getHours() + 1); - return currentDate.getTime() / 1000; - } - - /** - * If a signing key is set for this builder, recalculates the signature - * - * @returns {string} the signature value - */ - protected getSignature(): string { - if (this._signKey) { - this._signature = this.ethSignMsgHash(); - } - return this._signature!; - } - - protected ethSignMsgHash(): string { - const data = this.getOperationHash(); - const keyBuffer = Buffer.from(ethUtil.padToEven(this._signKey), 'hex'); - if (keyBuffer.length != 32) { - throw new Error('private key length is invalid'); - } - const signatureInParts = ethUtil.ecsign( - Buffer.from(ethUtil.padToEven(ethUtil.stripHexPrefix(data)), 'hex'), - keyBuffer - ); - - // Assemble strings from r, s and v - const r = ethUtil.setLengthLeft(signatureInParts.r, 32).toString('hex'); - const s = ethUtil.setLengthLeft(signatureInParts.s, 32).toString('hex'); - const v = ethUtil.stripHexPrefix(ethUtil.intToHex(signatureInParts.v)); - - // Concatenate the r, s and v parts to make the signature string - return ethUtil.addHexPrefix(r.concat(s, v)); - } - - private decodeTransferData(data: string): void { - const transferData = decodeTransferData(data); - - this._toAddress = transferData.to; - this._amount = transferData.amount; - this._expirationTime = transferData.expireTime; - this._sequenceId = transferData.sequenceId; - this._signature = transferData.signature; - - if (transferData.data) { - this._data = transferData.data; - } - - if (transferData.tokenContractAddress) { - this._tokenContractAddress = transferData.tokenContractAddress; - } - } } diff --git a/modules/sdk-coin-eth/src/lib/transferBuilders/index.ts b/modules/sdk-coin-eth/src/lib/transferBuilders/index.ts index 946d247e92..6bc0ee382d 100644 --- a/modules/sdk-coin-eth/src/lib/transferBuilders/index.ts +++ b/modules/sdk-coin-eth/src/lib/transferBuilders/index.ts @@ -1,3 +1,3 @@ -export * from './baseNFTTransferBuilder'; -export * from './transferBuilderERC1155'; -export * from './transferBuilderERC721'; +import { BaseNFTTransferBuilder, ERC721TransferBuilder, ERC1155TransferBuilder } from '@bitgo/abstract-eth'; + +export { BaseNFTTransferBuilder, ERC721TransferBuilder, ERC1155TransferBuilder }; diff --git a/modules/sdk-coin-eth/src/lib/walletUtil.ts b/modules/sdk-coin-eth/src/lib/walletUtil.ts index 29a1fda451..2e85252a72 100644 --- a/modules/sdk-coin-eth/src/lib/walletUtil.ts +++ b/modules/sdk-coin-eth/src/lib/walletUtil.ts @@ -1,20 +1,3 @@ -export const sendMultisigMethodId = '0x39125215'; -export const sendMultisigTokenMethodId = '0x0dcd7a6c'; -export const v1CreateForwarderMethodId = '0xfb90b320'; -export const v1WalletInitializationFirstBytes = '0x60806040'; -export const v1CreateWalletMethodId = '0x7117f3fa'; -export const createForwarderMethodId = '0xa68a76cc'; -export const walletInitializationFirstBytes = '0x60606040'; -export const recoveryWalletInitializationFirstBytes = '0x60c06040'; -export const flushForwarderTokensMethodId = '0x2da03409'; -export const flushCoinsMethodId = '0x6b9f96ea'; - -export const ERC721SafeTransferTypeMethodId = '0xb88d4fde'; -export const ERC1155SafeTransferTypeMethodId = '0xf242432a'; -export const ERC1155BatchTransferTypeMethodId = '0x2eb2c2d6'; -export const defaultForwarderVersion = 0; -export const defaultWalletVersion = 0; - /* Steps to reproduce: Checkout https://github.com/bitgo/eth-multisig-v2 @@ -24,18 +7,3 @@ export const defaultWalletVersion = 0; */ export const walletSimpleByteCode = '0x60606040526000600160006101000a81548160ff021916908315150217905550341561002a57600080fd5b60405161155b38038061155b833981016040528080518201919050506003815114151561005657600080fd5b806000908051906020019061006c929190610073565b5050610140565b8280548282559060005260206000209081019282156100ec579160200282015b828111156100eb5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555091602001919060010190610093565b5b5090506100f991906100fd565b5090565b61013d91905b8082111561013957600081816101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550600101610103565b5090565b90565b61140c8061014f6000396000f300606060405260043610610099576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630dcd7a6c146101335780632079fb9a146101e95780632da034091461024c57806339125215146102a45780637df73e271461037e578063a0b7967b146103cf578063a68a76cc146103f8578063abe3219c1461044d578063fc0f392d1461047a575b6000341115610131577f6e89d517057028190560dd200cf6bf792842861353d1173761dfa362e1c133f03334600036604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200180602001828103825284848281815260200192508082843782019150509550505050505060405180910390a15b005b341561013e57600080fd5b6101e7600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803590602001909190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190505061048f565b005b34156101f457600080fd5b61020a6004808035906020019091905050610668565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561025757600080fd5b6102a2600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506106a7565b005b34156102af57600080fd5b61037c600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190803590602001909190803590602001909190803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050610773565b005b341561038957600080fd5b6103b5600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610a72565b604051808215151515815260200191505060405180910390f35b34156103da57600080fd5b6103e2610b16565b6040518082815260200191505060405180910390f35b341561040357600080fd5b61040b610b70565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561045857600080fd5b610460610b95565b604051808215151515815260200191505060405180910390f35b341561048557600080fd5b61048d610ba8565b005b60008061049b33610a72565b15156104a657600080fd5b878787878760405180807f45524332300000000000000000000000000000000000000000000000000000008152506005018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018581526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140183815260200182815260200195505050505050604051809103902091506105898883858888610c3b565b508590508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb89896000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b151561063857600080fd5b6102c65a03f1151561064957600080fd5b50505060405180519050151561065e57600080fd5b5050505050505050565b60008181548110151561067757fe5b90600052602060002090016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006106b233610a72565b15156106bd57600080fd5b8290508073ffffffffffffffffffffffffffffffffffffffff16633ef13367836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b151561075a57600080fd5b6102c65a03f1151561076b57600080fd5b505050505050565b60008061077f33610a72565b151561078a57600080fd5b878787878760405180807f45544845520000000000000000000000000000000000000000000000000000008152506005018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140185815260200184805190602001908083835b602083101515610833578051825260208201915060208101905060208303925061080e565b6001836020036101000a038019825116818451168082178552505050505050905001838152602001828152602001955050505050506040518091039020915061087f8883858888610c3b565b90508773ffffffffffffffffffffffffffffffffffffffff16878760405180828051906020019080838360005b838110156108c75780820151818401526020810190506108ac565b50505050905090810190601f1680156108f45780820380516001836020036101000a031916815260200191505b5091505060006040518083038185876187965a03f192505050151561091857600080fd5b7f59bed9ab5d78073465dd642a9e3e76dfdb7d53bcae9d09df7d0b8f5234d5a8063382848b8b8b604051808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200185600019166000191681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610a29578082015181840152602081019050610a0e565b50505050905090810190601f168015610a565780820380516001836020036101000a031916815260200191505b5097505050505050505060405180910390a15050505050505050565b600080600090505b600080549050811015610b0b578273ffffffffffffffffffffffffffffffffffffffff16600082815481101515610aad57fe5b906000526020600020900160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610afe5760019150610b10565b8080600101915050610a7a565b600091505b50919050565b6000806000809150600090505b600a811015610b655781600282600a81101515610b3c57fe5b01541115610b5857600281600a81101515610b5357fe5b015491505b8080600101915050610b23565b600182019250505090565b6000610b7a610e90565b604051809103906000f0801515610b9057600080fd5b905090565b600160009054906101000a900460ff1681565b610bb133610a72565b1515610bbc57600080fd5b60018060006101000a81548160ff0219169083151502179055507f0909e8f76a4fd3e970f2eaef56c0ee6dfaf8b87c5b8d3f56ffce78e825a9115733604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a1565b600080610c488686610ce6565b9050600160009054906101000a900460ff168015610c6c5750610c6a87610a72565b155b15610c7657600080fd5b42841015610c8357600080fd5b610c8c83610db9565b610c9581610a72565b1515610ca057600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610cd957600080fd5b8091505095945050505050565b60008060008060418551141515610cfc57600080fd5b602085015192506040850151915060ff6041860151169050601b8160ff161015610d2757601b810190505b600186828585604051600081526020016040526000604051602001526040518085600019166000191681526020018460ff1660ff16815260200183600019166000191681526020018260001916600019168152602001945050505050602060405160208103908084039060008661646e5a03f11515610da557600080fd5b505060206040510351935050505092915050565b600080610dc533610a72565b1515610dd057600080fd5b60009150600090505b600a811015610e385782600282600a81101515610df257fe5b01541415610dff57600080fd5b600282600a81101515610e0e57fe5b0154600282600a81101515610e1f57fe5b01541015610e2b578091505b8080600101915050610dd9565b600282600a81101515610e4757fe5b0154831015610e5557600080fd5b612710600283600a81101515610e6757fe5b015401831115610e7657600080fd5b82600283600a81101515610e8657fe5b0181905550505050565b60405161054080610ea18339019056006060604052341561000f57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506104e28061005e6000396000f300606060405260043610610056576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168062821de3146101475780633ef133671461019c5780636b9f96ea146101d5575b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f1935050505015156100b757600080fd5b7f69b31548dea9b3b707b4dff357d326e3e9348b24e7a6080a218a6edeeec48f9b3334600036604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200180602001828103825284848281815260200192508082843782019150509550505050505060405180910390a1005b341561015257600080fd5b61015a6101ea565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101a757600080fd5b6101d3600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061020f565b005b34156101e057600080fd5b6101e861043c565b005b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561026f57600080fd5b8392503091508273ffffffffffffffffffffffffffffffffffffffff166370a08231836000604051602001526040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b151561031857600080fd5b6102c65a03f1151561032957600080fd5b505050604051805190509050600081141561034357610436565b8273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b151561040f57600080fd5b6102c65a03f1151561042057600080fd5b50505060405180519050151561043557600080fd5b5b50505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f1935050505015156104b457600080fd5b5600a165627a7a72305820088cce905e424bfe474510efe41761893e9e34b54b885b8fee546d8be88aee3c0029a165627a7a72305820827adc3ef3a179757bc33003e41070fbbfcdfc5db31275af3cb0395155cd3bbb0029'; - -export const walletSimpleConstructor = ['address[]']; -export const createV1WalletTypes = ['address[]', 'bytes32']; -export const flushTokensTypes = ['address', 'address']; -export const flushCoinsTypes = []; - -export const sendMultiSigTypes = ['address', 'uint', 'bytes', 'uint', 'uint', 'bytes']; - -export const sendMultiSigTokenTypes = ['address', 'uint', 'address', 'uint', 'uint', 'bytes']; - -export const ERC721SafeTransferTypes = ['address', 'address', 'uint256', 'bytes']; - -export const ERC1155SafeTransferTypes = ['address', 'address', 'uint256', 'uint256', 'bytes']; -export const ERC1155BatchTransferTypes = ['address', 'address', 'uint256[]', 'uint256[]', 'bytes']; -export const createV1ForwarderTypes = ['address', 'bytes32']; diff --git a/modules/sdk-coin-eth/test/unit/getBuilder.ts b/modules/sdk-coin-eth/test/unit/getBuilder.ts index 261b490989..0366d86283 100644 --- a/modules/sdk-coin-eth/test/unit/getBuilder.ts +++ b/modules/sdk-coin-eth/test/unit/getBuilder.ts @@ -1,4 +1,4 @@ -import { TransactionBuilder } from '../../src'; +import { TransactionBuilder } from '../../src/lib/transactionBuilder'; import { coins } from '@bitgo/statics'; export const getBuilder = (coin: string): TransactionBuilder => { diff --git a/modules/sdk-coin-eth/test/unit/utils.ts b/modules/sdk-coin-eth/test/unit/utils.ts index c5d3f68d5e..8697d6333b 100644 --- a/modules/sdk-coin-eth/test/unit/utils.ts +++ b/modules/sdk-coin-eth/test/unit/utils.ts @@ -6,9 +6,9 @@ import { calculateForwarderAddress, calculateForwarderV1Address, getProxyInitcode, + createForwarderMethodId, } from '../../src'; import * as testData from '../resources/eth'; -import * as walletUtilConstants from '../../src/lib/walletUtil'; import { bufferToHex, setLengthLeft } from 'ethereumjs-util'; import EthereumAbi from 'ethereumjs-abi'; @@ -25,7 +25,7 @@ describe('ETH util library', function () { }); it('Should validate valid createForwarder Id for forwarder', function () { - should.equal(getAddressInitializationData(), walletUtilConstants.createForwarderMethodId); + should.equal(getAddressInitializationData(), createForwarderMethodId); }); it('should validate valid address', function () { diff --git a/modules/sdk-coin-eth/tsconfig.json b/modules/sdk-coin-eth/tsconfig.json index bf32e8272f..8cc7ae1497 100644 --- a/modules/sdk-coin-eth/tsconfig.json +++ b/modules/sdk-coin-eth/tsconfig.json @@ -10,6 +10,9 @@ "include": ["src/**/*", "test/**/*"], "exclude": ["node_modules"], "references": [ + { + "path": "../abstract-eth" + }, { "path": "../sdk-core" }, diff --git a/modules/sdk-coin-eth2/package.json b/modules/sdk-coin-eth2/package.json index 3f5f320c96..155b978962 100644 --- a/modules/sdk-coin-eth2/package.json +++ b/modules/sdk-coin-eth2/package.json @@ -41,7 +41,7 @@ }, "dependencies": { "@bitgo/sdk-core": "^8.26.0", - "bignumber.js": "^8.0.1", + "bignumber.js": "^9.1.1", "ethereumjs-util": "7.1.5", "lodash": "^4.17.14", "superagent": "^3.8.3" diff --git a/modules/sdk-coin-ethw/src/ethw.ts b/modules/sdk-coin-ethw/src/ethw.ts index d3441124d8..4f513ccc00 100644 --- a/modules/sdk-coin-ethw/src/ethw.ts +++ b/modules/sdk-coin-ethw/src/ethw.ts @@ -1,4 +1,5 @@ import request from 'superagent'; + import BigNumber from 'bignumber.js'; import { BN } from 'ethereumjs-util'; diff --git a/modules/sdk-coin-ethw/tsconfig.json b/modules/sdk-coin-ethw/tsconfig.json index 52c51f35c6..d1e64cf30a 100644 --- a/modules/sdk-coin-ethw/tsconfig.json +++ b/modules/sdk-coin-ethw/tsconfig.json @@ -10,6 +10,9 @@ "include": ["src/**/*", "test/**/*"], "exclude": ["node_modules"], "references": [ + { + "path": "../sdk-coin-eth" + }, { "path": "../abstract-eth" }, diff --git a/modules/sdk-coin-opeth/package.json b/modules/sdk-coin-opeth/package.json index e5e29259f1..ab5789e864 100644 --- a/modules/sdk-coin-opeth/package.json +++ b/modules/sdk-coin-opeth/package.json @@ -41,10 +41,10 @@ }, "dependencies": { "@bitgo/abstract-eth": "^1.6.0", - "@bitgo/sdk-coin-eth": "^4.10.0", "@bitgo/sdk-core": "^8.26.0", "@bitgo/statics": "^29.0.0", - "@ethereumjs/common": "^2.6.5" + "@ethereumjs/common": "^2.6.5", + "ethereumjs-abi": "^0.6.5" }, "devDependencies": { "@bitgo/sdk-api": "^1.24.0", diff --git a/modules/sdk-coin-opeth/src/lib/index.ts b/modules/sdk-coin-opeth/src/lib/index.ts index 79473f2f5a..20f9e761a1 100644 --- a/modules/sdk-coin-opeth/src/lib/index.ts +++ b/modules/sdk-coin-opeth/src/lib/index.ts @@ -2,5 +2,5 @@ import * as Utils from './utils'; export { TransactionBuilder } from './transactionBuilder'; export { TransferBuilder } from './transferBuilder'; -export { Transaction, KeyPair } from '@bitgo/sdk-coin-eth'; +export { Transaction, KeyPair } from '@bitgo/abstract-eth'; export { Utils }; diff --git a/modules/sdk-coin-opeth/src/lib/transactionBuilder.ts b/modules/sdk-coin-opeth/src/lib/transactionBuilder.ts index c564751558..7f46195588 100644 --- a/modules/sdk-coin-opeth/src/lib/transactionBuilder.ts +++ b/modules/sdk-coin-opeth/src/lib/transactionBuilder.ts @@ -1,10 +1,17 @@ import { BaseCoin as CoinConfig } from '@bitgo/statics'; +import EthereumAbi from 'ethereumjs-abi'; import { BuildTransactionError, TransactionType } from '@bitgo/sdk-core'; -import { KeyPair, Transaction, TransactionBuilder as EthTransactionBuilder } from '@bitgo/sdk-coin-eth'; +import { + KeyPair, + Transaction, + TransactionBuilder as EthLikeTransactionBuilder, + walletSimpleConstructor, +} from '@bitgo/abstract-eth'; import { getCommon } from './utils'; import { TransferBuilder } from './transferBuilder'; +import { walletSimpleByteCode } from './walletUtil'; -export class TransactionBuilder extends EthTransactionBuilder { +export class TransactionBuilder extends EthLikeTransactionBuilder { protected _transfer!: TransferBuilder; constructor(_coinConfig: Readonly) { @@ -13,6 +20,20 @@ export class TransactionBuilder extends EthTransactionBuilder { this.transaction = new Transaction(this._coinConfig, this._common); } + /** + * Returns the smart contract encoded data + * + * @param {string[]} addresses - the contract signers + * @returns {string} - the smart contract encoded data + */ + protected getContractData(addresses: string[]): string { + const params = [addresses]; + const resultEncodedParameters = EthereumAbi.rawEncode(walletSimpleConstructor, params) + .toString('hex') + .replace('0x', ''); + return walletSimpleByteCode + resultEncodedParameters; + } + /** @inheritdoc */ transfer(data?: string): TransferBuilder { if (this._type !== TransactionType.Send) { diff --git a/modules/sdk-coin-opeth/src/lib/transferBuilder.ts b/modules/sdk-coin-opeth/src/lib/transferBuilder.ts index f833119559..a470442578 100644 --- a/modules/sdk-coin-opeth/src/lib/transferBuilder.ts +++ b/modules/sdk-coin-opeth/src/lib/transferBuilder.ts @@ -1,4 +1,4 @@ -import { TransferBuilder as EthTransferBuilder } from '@bitgo/sdk-coin-eth'; +import { TransferBuilder as EthTransferBuilder } from '@bitgo/abstract-eth'; export class TransferBuilder extends EthTransferBuilder { /** @inheritdoc */ diff --git a/modules/sdk-coin-opeth/src/lib/walletUtil.ts b/modules/sdk-coin-opeth/src/lib/walletUtil.ts new file mode 100644 index 0000000000..cd96c87dfe --- /dev/null +++ b/modules/sdk-coin-opeth/src/lib/walletUtil.ts @@ -0,0 +1,612 @@ +/* +The steps used to obtain the bytecode and ABI of the contract were: + +1. Go to: https://remix.ethereum.org/ +2. Copy the content of the contract OpethWalletSimple.sol into the IDE + The content of all the required contracts like Forwarder.sol and ERC20Interface.sol also need to be present to replicate the imports structure of OpethWalletSimple.sol +3. Compile the contract with the compiler version 0.8.20+commit.a1b79de6 and then get the generated bytecode and ABI + */ +export const walletSimpleByteCode = + '0x60806040525f60015f6101000a81548160ff0219169083151502179055505f6001806101000a81548160ff021916908315150217905550348015610041575f80fd5b506136aa8061004f5f395ff3fe608060405260043610610122575f3560e01c8063924677761161009f578063c137878411610063578063c137878414610475578063c6044c461461049d578063e6bd0aa4146104c5578063f23a6e61146104ed578063fc0f392d146105295761016b565b80639246777614610395578063a0b7967b146103bd578063abe3219c146103e7578063ad3ad70914610411578063bc197c81146104395761016b565b806334f94047116100e657806334f94047146102a557806339125215146102cd5780635a953d0a146102f5578063736c0d5b1461031d5780637df73e27146103595761016b565b806301ffc9a7146101b35780630dcd7a6c146101ef578063150b7a0214610217578063158ef93e146102535780632da034091461027d5761016b565b3661016b575f341115610169577f6e89d517057028190560dd200cf6bf792842861353d1173761dfa362e1c133f03334604051610160929190611be9565b60405180910390a15b005b5f3411156101b1577f6e89d517057028190560dd200cf6bf792842861353d1173761dfa362e1c133f033345f366040516101a89493929190611c6d565b60405180910390a15b005b3480156101be575f80fd5b506101d960048036038101906101d49190611d11565b61053f565b6040516101e69190611d56565b60405180910390f35b3480156101fa575f80fd5b5061021560048036038101906102109190611e24565b6105b8565b005b348015610222575f80fd5b5061023d60048036038101906102389190611fe8565b61065f565b60405161024a9190612077565b60405180910390f35b34801561025e575f80fd5b50610267610672565b6040516102749190611d56565b60405180910390f35b348015610288575f80fd5b506102a3600480360381019061029e91906120cb565b610683565b005b3480156102b0575f80fd5b506102cb60048036038101906102c6919061215e565b61073a565b005b3480156102d8575f80fd5b506102f360048036038101906102ee91906121cf565b6107f7565b005b348015610300575f80fd5b5061031b60048036038101906103169190612299565b610989565b005b348015610328575f80fd5b50610343600480360381019061033e91906122e9565b610a43565b6040516103509190611d56565b60405180910390f35b348015610364575f80fd5b5061037f600480360381019061037a91906122e9565b610a5f565b60405161038c9190611d56565b60405180910390f35b3480156103a0575f80fd5b506103bb60048036038101906103b6919061233e565b610ab0565b005b3480156103c8575f80fd5b506103d1610b67565b6040516103de919061237c565b60405180910390f35b3480156103f2575f80fd5b506103fb610bd4565b6040516104089190611d56565b60405180910390f35b34801561041c575f80fd5b50610437600480360381019061043291906123ea565b610be6565b005b348015610444575f80fd5b5061045f600480360381019061045a91906124c1565b610df2565b60405161046c9190612077565b60405180910390f35b348015610480575f80fd5b5061049b6004803603810190610496919061233e565b610e09565b005b3480156104a8575f80fd5b506104c360048036038101906104be9190612598565b610ec0565b005b3480156104d0575f80fd5b506104eb60048036038101906104e69190612299565b6110ac565b005b3480156104f8575f80fd5b50610513600480360381019061050e91906125e3565b611166565b6040516105209190612077565b60405180910390f35b348015610534575f80fd5b5061053d61117b565b005b5f7f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806105b157506105b082611215565b5b9050919050565b6105c133610a5f565b610600576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105f7906126d3565b60405180910390fd5b5f61060961127e565b8888888888604051602001610623969594939291906127c2565b6040516020818303038152906040528051906020012090506106498882858589896112bb565b5061065586898961147b565b5050505050505050565b5f63150b7a0260e01b9050949350505050565b60018054906101000a900460ff1681565b61068c33610a5f565b6106cb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c2906126d3565b60405180910390fd5b5f8290508073ffffffffffffffffffffffffffffffffffffffff16633ef13367836040518263ffffffff1660e01b8152600401610708919061282d565b5f604051808303815f87803b15801561071f575f80fd5b505af1158015610731573d5f803e3d5ffd5b50505050505050565b61074333610a5f565b610782576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610779906126d3565b60405180910390fd5b5f8490508073ffffffffffffffffffffffffffffffffffffffff1663c6a2dd248585856040518463ffffffff1660e01b81526004016107c3939291906128be565b5f604051808303815f87803b1580156107da575f80fd5b505af11580156107ec573d5f803e3d5ffd5b505050505050505050565b61080033610a5f565b61083f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610836906126d3565b60405180910390fd5b5f6108486115ab565b898989898989604051602001610864979695949392919061291c565b6040516020818303038152906040528051906020012090505f61088b8a8386868a8a6112bb565b90505f8a73ffffffffffffffffffffffffffffffffffffffff168a8a8a6040516108b6929190612985565b5f6040518083038185875af1925050503d805f81146108f0576040519150601f19603f3d011682016040523d82523d5f602084013e6108f5565b606091505b5050905080610939576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610930906129e7565b60405180910390fd5b7f59bed9ab5d78073465dd642a9e3e76dfdb7d53bcae9d09df7d0b8f5234d5a8063383858e8e8e8e6040516109749796959493929190612a1d565b60405180910390a15050505050505050505050565b61099233610a5f565b6109d1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109c8906126d3565b60405180910390fd5b5f8390508073ffffffffffffffffffffffffffffffffffffffff1663159e44d784846040518363ffffffff1660e01b8152600401610a10929190612a85565b5f604051808303815f87803b158015610a27575f80fd5b505af1158015610a39573d5f803e3d5ffd5b5050505050505050565b5f602052805f5260405f205f915054906101000a900460ff1681565b5f805f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff169050919050565b610ab933610a5f565b610af8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610aef906126d3565b60405180910390fd5b5f8290508073ffffffffffffffffffffffffffffffffffffffff16638acc01be836040518263ffffffff1660e01b8152600401610b359190611d56565b5f604051808303815f87803b158015610b4c575f80fd5b505af1158015610b5e573d5f803e3d5ffd5b50505050505050565b5f805f90505f5b600a811015610bc05781600282600a8110610b8c57610b8b612aac565b5b01541115610bad57600281600a8110610ba857610ba7612aac565b5b015491505b8080610bb890612b06565b915050610b6e565b50600181610bce9190612b4d565b91505090565b60015f9054906101000a900460ff1681565b610bef33610a5f565b610c2e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c25906126d3565b60405180910390fd5b5f8888905003610c73576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6a90612bca565b60405180910390fd5b858590508888905014610cbb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cb290612c32565b60405180910390fd5b6101008888905010610d02576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cf990612c9a565b60405180910390fd5b5f610d0b6115e8565b898989898989604051602001610d279796959493929190612dd3565b60405160208183030381529060405280519060200120905060015f9054906101000a900460ff1615610d8e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d8590612e73565b60405180910390fd5b5f610d9d5f8386868a8a6112bb565b9050610dab8a8a8a8a611625565b7fe4c9047a729726b729cf4fa62c95ef9a434bbaf206a7ea0c7c77515db1584022338284604051610dde93929190612e91565b60405180910390a150505050505050505050565b5f63bc197c8160e01b905098975050505050505050565b610e1233610a5f565b610e51576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e48906126d3565b60405180910390fd5b5f8290508073ffffffffffffffffffffffffffffffffffffffff1663c59f9f19836040518263ffffffff1660e01b8152600401610e8e9190611d56565b5f604051808303815f87803b158015610ea5575f80fd5b505af1158015610eb7573d5f803e3d5ffd5b50505050505050565b60018054906101000a900460ff1615610f0e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f0590612f10565b60405180910390fd5b60038282905014610f54576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f4b90612f78565b60405180910390fd5b5f5b828290508160ff16101561108d575f73ffffffffffffffffffffffffffffffffffffffff1683838360ff16818110610f9157610f90612aac565b5b9050602002016020810190610fa691906122e9565b73ffffffffffffffffffffffffffffffffffffffff1603610ffc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ff390612fe0565b60405180910390fd5b60015f8085858560ff1681811061101657611015612aac565b5b905060200201602081019061102b91906122e9565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff02191690831515021790555080806110859061300a565b915050610f56565b5060018060016101000a81548160ff0219169083151502179055505050565b6110b533610a5f565b6110f4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110eb906126d3565b60405180910390fd5b5f8390508073ffffffffffffffffffffffffffffffffffffffff16638972c17c84846040518363ffffffff1660e01b8152600401611133929190612a85565b5f604051808303815f87803b15801561114a575f80fd5b505af115801561115c573d5f803e3d5ffd5b5050505050505050565b5f63f23a6e6160e01b90509695505050505050565b61118433610a5f565b6111c3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111ba906126d3565b60405180910390fd5b6001805f6101000a81548160ff0219169083151502179055507f0909e8f76a4fd3e970f2eaef56c0ee6dfaf8b87c5b8d3f56ffce78e825a911573360405161120b919061282d565b60405180910390a1565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60606040518060400160405280600b81526020017f4f504554482d4552433230000000000000000000000000000000000000000000815250905090565b5f8061130a8787878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505061180c565b905060015f9054906101000a900460ff16158061132c575061132b88610a5f565b5b61136b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113629061307c565b60405180910390fd5b428410156113ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113a5906130e4565b60405180910390fd5b6113b783611944565b6113c081610a5f565b6113ff576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113f690612fe0565b60405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361146d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114649061314c565b60405180910390fd5b809150509695505050505050565b5f808473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb85856040516024016114ac929190612a85565b6040516020818303038152906040529060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516114fa91906131a4565b5f604051808303815f865af19150503d805f8114611533576040519150601f19603f3d011682016040523d82523d5f602084013e611538565b606091505b509150915081801561156557505f8151148061156457508080602001905181019061156391906131ce565b5b5b6115a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161159b90613269565b60405180910390fd5b5050505050565b60606040518060400160405280600581526020017f4f50455448000000000000000000000000000000000000000000000000000000815250905090565b60606040518060400160405280600b81526020017f4f504554482d4261746368000000000000000000000000000000000000000000815250905090565b5f5b848490508110156118055782828281811061164557611644612aac565b5b9050602002013547101561168e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611685906132d1565b60405180910390fd5b5f8585838181106116a2576116a1612aac565b5b90506020020160208101906116b791906122e9565b73ffffffffffffffffffffffffffffffffffffffff168484848181106116e0576116df612aac565b5b905060200201356040516116f39061330f565b5f6040518083038185875af1925050503d805f811461172d576040519150601f19603f3d011682016040523d82523d5f602084013e611732565b606091505b5050905080611776576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161176d9061336d565b60405180910390fd5b7fc42fa155158786a1dd6ccc3a785f35845467353c3cc700e0e31a79f90e22227d338787858181106117ab576117aa612aac565b5b90506020020160208101906117c091906122e9565b8686868181106117d3576117d2612aac565b5b905060200201356040516117e99392919061338b565b60405180910390a15080806117fd90612b06565b915050611627565b5050505050565b5f6041825114611851576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118489061340a565b60405180910390fd5b5f805f602085015192506040850151915060ff6041860151169050601b8160ff16101561188857601b816118859190613428565b90505b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0825f1c11156118ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118e4906134cc565b60405180910390fd5b6001868285856040515f815260200160405260405161190f94939291906134f9565b6020604051602081039080840390855afa15801561192f573d5f803e3d5ffd5b50505060206040510351935050505092915050565b61194d33610a5f565b61198c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611983906126d3565b60405180910390fd5b5f806002600a806020026040519081016040528092919082600a80156119c7576020028201915b8154815260200190600101908083116119b3575b505050505090505f5b600a811015611a7f57838282600a81106119ed576119ec612aac565b5b602002015103611a32576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a2990613586565b60405180910390fd5b8183600a8110611a4557611a44612aac565b5b60200201518282600a8110611a5d57611a5c612aac565b5b60200201511015611a6c578092505b8080611a7790612b06565b9150506119d0565b508082600a8110611a9357611a92612aac565b5b60200201518311611ad9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ad0906135ee565b60405180910390fd5b6127108183600a8110611aef57611aee612aac565b5b6020020151611afe9190612b4d565b831115611b40576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b3790613656565b60405180910390fd5b82600283600a8110611b5557611b54612aac565b5b0181905550505050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f611b8882611b5f565b9050919050565b611b9881611b7e565b82525050565b5f819050919050565b611bb081611b9e565b82525050565b5f82825260208201905092915050565b50565b5f611bd45f83611bb6565b9150611bdf82611bc6565b5f82019050919050565b5f606082019050611bfc5f830185611b8f565b611c096020830184611ba7565b8181036040830152611c1a81611bc9565b90509392505050565b828183375f83830152505050565b5f601f19601f8301169050919050565b5f611c4c8385611bb6565b9350611c59838584611c23565b611c6283611c31565b840190509392505050565b5f606082019050611c805f830187611b8f565b611c8d6020830186611ba7565b8181036040830152611ca0818486611c41565b905095945050505050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b611cf081611cbc565b8114611cfa575f80fd5b50565b5f81359050611d0b81611ce7565b92915050565b5f60208284031215611d2657611d25611cb4565b5b5f611d3384828501611cfd565b91505092915050565b5f8115159050919050565b611d5081611d3c565b82525050565b5f602082019050611d695f830184611d47565b92915050565b611d7881611b7e565b8114611d82575f80fd5b50565b5f81359050611d9381611d6f565b92915050565b611da281611b9e565b8114611dac575f80fd5b50565b5f81359050611dbd81611d99565b92915050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f840112611de457611de3611dc3565b5b8235905067ffffffffffffffff811115611e0157611e00611dc7565b5b602083019150836001820283011115611e1d57611e1c611dcb565b5b9250929050565b5f805f805f805f60c0888a031215611e3f57611e3e611cb4565b5b5f611e4c8a828b01611d85565b9750506020611e5d8a828b01611daf565b9650506040611e6e8a828b01611d85565b9550506060611e7f8a828b01611daf565b9450506080611e908a828b01611daf565b93505060a088013567ffffffffffffffff811115611eb157611eb0611cb8565b5b611ebd8a828b01611dcf565b925092505092959891949750929550565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b611f0882611c31565b810181811067ffffffffffffffff82111715611f2757611f26611ed2565b5b80604052505050565b5f611f39611cab565b9050611f458282611eff565b919050565b5f67ffffffffffffffff821115611f6457611f63611ed2565b5b611f6d82611c31565b9050602081019050919050565b5f611f8c611f8784611f4a565b611f30565b905082815260208101848484011115611fa857611fa7611ece565b5b611fb3848285611c23565b509392505050565b5f82601f830112611fcf57611fce611dc3565b5b8135611fdf848260208601611f7a565b91505092915050565b5f805f806080858703121561200057611fff611cb4565b5b5f61200d87828801611d85565b945050602061201e87828801611d85565b935050604061202f87828801611daf565b925050606085013567ffffffffffffffff8111156120505761204f611cb8565b5b61205c87828801611fbb565b91505092959194509250565b61207181611cbc565b82525050565b5f60208201905061208a5f830184612068565b92915050565b5f61209a82611b5f565b9050919050565b6120aa81612090565b81146120b4575f80fd5b50565b5f813590506120c5816120a1565b92915050565b5f80604083850312156120e1576120e0611cb4565b5b5f6120ee858286016120b7565b92505060206120ff85828601611d85565b9150509250929050565b5f8083601f84011261211e5761211d611dc3565b5b8235905067ffffffffffffffff81111561213b5761213a611dc7565b5b60208301915083602082028301111561215757612156611dcb565b5b9250929050565b5f805f806060858703121561217657612175611cb4565b5b5f612183878288016120b7565b945050602061219487828801611d85565b935050604085013567ffffffffffffffff8111156121b5576121b4611cb8565b5b6121c187828801612109565b925092505092959194509250565b5f805f805f805f8060c0898b0312156121eb576121ea611cb4565b5b5f6121f88b828c01611d85565b98505060206122098b828c01611daf565b975050604089013567ffffffffffffffff81111561222a57612229611cb8565b5b6122368b828c01611dcf565b965096505060606122498b828c01611daf565b945050608061225a8b828c01611daf565b93505060a089013567ffffffffffffffff81111561227b5761227a611cb8565b5b6122878b828c01611dcf565b92509250509295985092959890939650565b5f805f606084860312156122b0576122af611cb4565b5b5f6122bd868287016120b7565b93505060206122ce86828701611d85565b92505060406122df86828701611daf565b9150509250925092565b5f602082840312156122fe576122fd611cb4565b5b5f61230b84828501611d85565b91505092915050565b61231d81611d3c565b8114612327575f80fd5b50565b5f8135905061233881612314565b92915050565b5f806040838503121561235457612353611cb4565b5b5f61236185828601611d85565b92505060206123728582860161232a565b9150509250929050565b5f60208201905061238f5f830184611ba7565b92915050565b5f8083601f8401126123aa576123a9611dc3565b5b8235905067ffffffffffffffff8111156123c7576123c6611dc7565b5b6020830191508360208202830111156123e3576123e2611dcb565b5b9250929050565b5f805f805f805f8060a0898b03121561240657612405611cb4565b5b5f89013567ffffffffffffffff81111561242357612422611cb8565b5b61242f8b828c01612395565b9850985050602089013567ffffffffffffffff81111561245257612451611cb8565b5b61245e8b828c01612109565b965096505060406124718b828c01611daf565b94505060606124828b828c01611daf565b935050608089013567ffffffffffffffff8111156124a3576124a2611cb8565b5b6124af8b828c01611dcf565b92509250509295985092959890939650565b5f805f805f805f8060a0898b0312156124dd576124dc611cb4565b5b5f6124ea8b828c01611d85565b98505060206124fb8b828c01611d85565b975050604089013567ffffffffffffffff81111561251c5761251b611cb8565b5b6125288b828c01612109565b9650965050606089013567ffffffffffffffff81111561254b5761254a611cb8565b5b6125578b828c01612109565b9450945050608089013567ffffffffffffffff81111561257a57612579611cb8565b5b6125868b828c01611dcf565b92509250509295985092959890939650565b5f80602083850312156125ae576125ad611cb4565b5b5f83013567ffffffffffffffff8111156125cb576125ca611cb8565b5b6125d785828601612395565b92509250509250929050565b5f805f805f8060a087890312156125fd576125fc611cb4565b5b5f61260a89828a01611d85565b965050602061261b89828a01611d85565b955050604061262c89828a01611daf565b945050606061263d89828a01611daf565b935050608087013567ffffffffffffffff81111561265e5761265d611cb8565b5b61266a89828a01611dcf565b92509250509295509295509295565b5f82825260208201905092915050565b7f4e6f6e2d7369676e657220696e206f6e6c795369676e6572206d6574686f64005f82015250565b5f6126bd601f83612679565b91506126c882612689565b602082019050919050565b5f6020820190508181035f8301526126ea816126b1565b9050919050565b5f81519050919050565b5f81905092915050565b5f5b83811015612722578082015181840152602081019050612707565b5f8484015250505050565b5f612737826126f1565b61274181856126fb565b9350612751818560208601612705565b80840191505092915050565b5f8160601b9050919050565b5f6127738261275d565b9050919050565b5f61278482612769565b9050919050565b61279c61279782611b7e565b61277a565b82525050565b5f819050919050565b6127bc6127b782611b9e565b6127a2565b82525050565b5f6127cd828961272d565b91506127d9828861278b565b6014820191506127e982876127ab565b6020820191506127f9828661278b565b60148201915061280982856127ab565b60208201915061281982846127ab565b602082019150819050979650505050505050565b5f6020820190506128405f830184611b8f565b92915050565b5f82825260208201905092915050565b5f80fd5b82818337505050565b5f61286e8385612846565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156128a1576128a0612856565b5b6020830292506128b283858461285a565b82840190509392505050565b5f6040820190506128d15f830186611b8f565b81810360208301526128e4818486612863565b9050949350505050565b5f81905092915050565b5f61290383856128ee565b9350612910838584611c23565b82840190509392505050565b5f612927828a61272d565b9150612933828961278b565b60148201915061294382886127ab565b6020820191506129548286886128f8565b915061296082856127ab565b60208201915061297082846127ab565b60208201915081905098975050505050505050565b5f6129918284866128f8565b91508190509392505050565b7f43616c6c20657865637574696f6e206661696c656400000000000000000000005f82015250565b5f6129d1601583612679565b91506129dc8261299d565b602082019050919050565b5f6020820190508181035f8301526129fe816129c5565b9050919050565b5f819050919050565b612a1781612a05565b82525050565b5f60c082019050612a305f83018a611b8f565b612a3d6020830189611b8f565b612a4a6040830188612a0e565b612a576060830187611b8f565b612a646080830186611ba7565b81810360a0830152612a77818486611c41565b905098975050505050505050565b5f604082019050612a985f830185611b8f565b612aa56020830184611ba7565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f612b1082611b9e565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612b4257612b41612ad9565b5b600182019050919050565b5f612b5782611b9e565b9150612b6283611b9e565b9250828201905080821115612b7a57612b79612ad9565b5b92915050565b7f4e6f7420656e6f75676820726563697069656e747300000000000000000000005f82015250565b5f612bb4601583612679565b9150612bbf82612b80565b602082019050919050565b5f6020820190508181035f830152612be181612ba8565b9050919050565b7f556e657175616c20726563697069656e747320616e642076616c7565730000005f82015250565b5f612c1c601d83612679565b9150612c2782612be8565b602082019050919050565b5f6020820190508181035f830152612c4981612c10565b9050919050565b7f546f6f206d616e7920726563697069656e74732c206d617820323535000000005f82015250565b5f612c84601c83612679565b9150612c8f82612c50565b602082019050919050565b5f6020820190508181035f830152612cb181612c78565b9050919050565b5f81905092915050565b5f819050919050565b612cd481611b7e565b82525050565b5f612ce58383612ccb565b60208301905092915050565b5f612cff6020840184611d85565b905092915050565b5f602082019050919050565b5f612d1e8385612cb8565b9350612d2982612cc2565b805f5b85811015612d6157612d3e8284612cf1565b612d488882612cda565b9750612d5383612d07565b925050600181019050612d2c565b5085925050509392505050565b5f81905092915050565b5f612d838385612d6e565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115612db657612db5612856565b5b602083029250612dc783858461285a565b82840190509392505050565b5f612dde828a61272d565b9150612deb82888a612d13565b9150612df8828688612d78565b9150612e0482856127ab565b602082019150612e1482846127ab565b60208201915081905098975050505050505050565b7f426174636820696e2073616665206d6f646500000000000000000000000000005f82015250565b5f612e5d601283612679565b9150612e6882612e29565b602082019050919050565b5f6020820190508181035f830152612e8a81612e51565b9050919050565b5f606082019050612ea45f830186611b8f565b612eb16020830185611b8f565b612ebe6040830184612a0e565b949350505050565b7f436f6e747261637420616c726561647920696e697469616c697a6564000000005f82015250565b5f612efa601c83612679565b9150612f0582612ec6565b602082019050919050565b5f6020820190508181035f830152612f2781612eee565b9050919050565b7f496e76616c6964206e756d626572206f66207369676e657273000000000000005f82015250565b5f612f62601983612679565b9150612f6d82612f2e565b602082019050919050565b5f6020820190508181035f830152612f8f81612f56565b9050919050565b7f496e76616c6964207369676e65720000000000000000000000000000000000005f82015250565b5f612fca600e83612679565b9150612fd582612f96565b602082019050919050565b5f6020820190508181035f830152612ff781612fbe565b9050919050565b5f60ff82169050919050565b5f61301482612ffe565b915060ff820361302757613026612ad9565b5b600182019050919050565b7f45787465726e616c207472616e7366657220696e2073616665206d6f646500005f82015250565b5f613066601e83612679565b915061307182613032565b602082019050919050565b5f6020820190508181035f8301526130938161305a565b9050919050565b7f5472616e73616374696f6e2065787069726564000000000000000000000000005f82015250565b5f6130ce601383612679565b91506130d98261309a565b602082019050919050565b5f6020820190508181035f8301526130fb816130c2565b9050919050565b7f5369676e6572732063616e6e6f7420626520657175616c0000000000000000005f82015250565b5f613136601783612679565b915061314182613102565b602082019050919050565b5f6020820190508181035f8301526131638161312a565b9050919050565b5f81519050919050565b5f61317e8261316a565b61318881856128ee565b9350613198818560208601612705565b80840191505092915050565b5f6131af8284613174565b915081905092915050565b5f815190506131c881612314565b92915050565b5f602082840312156131e3576131e2611cb4565b5b5f6131f0848285016131ba565b91505092915050565b7f5472616e7366657248656c7065723a3a736166655472616e736665723a2074725f8201527f616e73666572206661696c656400000000000000000000000000000000000000602082015250565b5f613253602d83612679565b915061325e826131f9565b604082019050919050565b5f6020820190508181035f83015261328081613247565b9050919050565b7f496e73756666696369656e742066756e647300000000000000000000000000005f82015250565b5f6132bb601283612679565b91506132c682613287565b602082019050919050565b5f6020820190508181035f8301526132e8816132af565b9050919050565b5f6132fa5f836128ee565b915061330582611bc6565b5f82019050919050565b5f613319826132ef565b9150819050919050565b7f43616c6c206661696c65640000000000000000000000000000000000000000005f82015250565b5f613357600b83612679565b915061336282613323565b602082019050919050565b5f6020820190508181035f8301526133848161334b565b9050919050565b5f60608201905061339e5f830186611b8f565b6133ab6020830185611b8f565b6133b86040830184611ba7565b949350505050565b7f496e76616c6964207369676e6174757265202d2077726f6e67206c656e6774685f82015250565b5f6133f4602083612679565b91506133ff826133c0565b602082019050919050565b5f6020820190508181035f830152613421816133e8565b9050919050565b5f61343282612ffe565b915061343d83612ffe565b9250828201905060ff81111561345657613455612ad9565b5b92915050565b7f45434453413a20696e76616c6964207369676e6174757265202773272076616c5f8201527f7565000000000000000000000000000000000000000000000000000000000000602082015250565b5f6134b6602283612679565b91506134c18261345c565b604082019050919050565b5f6020820190508181035f8301526134e3816134aa565b9050919050565b6134f381612ffe565b82525050565b5f60808201905061350c5f830187612a0e565b61351960208301866134ea565b6135266040830185612a0e565b6135336060830184612a0e565b95945050505050565b7f53657175656e636520494420616c7265616479207573656400000000000000005f82015250565b5f613570601883612679565b915061357b8261353c565b602082019050919050565b5f6020820190508181035f83015261359d81613564565b9050919050565b7f53657175656e63652049442062656c6f772077696e646f7700000000000000005f82015250565b5f6135d8601883612679565b91506135e3826135a4565b602082019050919050565b5f6020820190508181035f830152613605816135cc565b9050919050565b7f53657175656e63652049442061626f7665206d6178696d756d000000000000005f82015250565b5f613640601983612679565b915061364b8261360c565b602082019050919050565b5f6020820190508181035f83015261366d81613634565b905091905056fea2646970667358221220352fb8295c03d20c2fa9c3132064e8e6f08bba7c3de60d897024de1f6eef56eb64736f6c63430008140033'; + +export const walletSimpleAbi = [ + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'msgSender', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'otherSigner', + type: 'address', + }, + { + indexed: false, + internalType: 'bytes32', + name: 'operation', + type: 'bytes32', + }, + ], + name: 'BatchTransacted', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'recipient', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + ], + name: 'BatchTransfer', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'from', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + { + indexed: false, + internalType: 'bytes', + name: 'data', + type: 'bytes', + }, + ], + name: 'Deposited', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'msgSender', + type: 'address', + }, + ], + name: 'SafeModeActivated', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'msgSender', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'otherSigner', + type: 'address', + }, + { + indexed: false, + internalType: 'bytes32', + name: 'operation', + type: 'bytes32', + }, + { + indexed: false, + internalType: 'address', + name: 'toAddress', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + { + indexed: false, + internalType: 'bytes', + name: 'data', + type: 'bytes', + }, + ], + name: 'Transacted', + type: 'event', + }, + { + stateMutability: 'payable', + type: 'fallback', + }, + { + inputs: [], + name: 'activateSafeMode', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address payable', + name: 'forwarderAddress', + type: 'address', + }, + { + internalType: 'address', + name: 'tokenContractAddress', + type: 'address', + }, + { + internalType: 'uint256[]', + name: 'tokenIds', + type: 'uint256[]', + }, + ], + name: 'batchFlushERC1155ForwarderTokens', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address payable', + name: 'forwarderAddress', + type: 'address', + }, + { + internalType: 'address', + name: 'tokenContractAddress', + type: 'address', + }, + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256', + }, + ], + name: 'flushERC1155ForwarderTokens', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address payable', + name: 'forwarderAddress', + type: 'address', + }, + { + internalType: 'address', + name: 'tokenContractAddress', + type: 'address', + }, + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256', + }, + ], + name: 'flushERC721ForwarderTokens', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address payable', + name: 'forwarderAddress', + type: 'address', + }, + { + internalType: 'address', + name: 'tokenContractAddress', + type: 'address', + }, + ], + name: 'flushForwarderTokens', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'getNextSequenceId', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address[]', + name: 'allowedSigners', + type: 'address[]', + }, + ], + name: 'init', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'initialized', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'signer', + type: 'address', + }, + ], + name: 'isSigner', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_operator', + type: 'address', + }, + { + internalType: 'address', + name: '_from', + type: 'address', + }, + { + internalType: 'uint256[]', + name: 'ids', + type: 'uint256[]', + }, + { + internalType: 'uint256[]', + name: 'values', + type: 'uint256[]', + }, + { + internalType: 'bytes', + name: 'data', + type: 'bytes', + }, + ], + name: 'onERC1155BatchReceived', + outputs: [ + { + internalType: 'bytes4', + name: '', + type: 'bytes4', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_operator', + type: 'address', + }, + { + internalType: 'address', + name: '_from', + type: 'address', + }, + { + internalType: 'uint256', + name: 'id', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + { + internalType: 'bytes', + name: 'data', + type: 'bytes', + }, + ], + name: 'onERC1155Received', + outputs: [ + { + internalType: 'bytes4', + name: '', + type: 'bytes4', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_operator', + type: 'address', + }, + { + internalType: 'address', + name: '_from', + type: 'address', + }, + { + internalType: 'uint256', + name: '_tokenId', + type: 'uint256', + }, + { + internalType: 'bytes', + name: '_data', + type: 'bytes', + }, + ], + name: 'onERC721Received', + outputs: [ + { + internalType: 'bytes4', + name: '', + type: 'bytes4', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'safeMode', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'toAddress', + type: 'address', + }, + { + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + { + internalType: 'bytes', + name: 'data', + type: 'bytes', + }, + { + internalType: 'uint256', + name: 'expireTime', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'sequenceId', + type: 'uint256', + }, + { + internalType: 'bytes', + name: 'signature', + type: 'bytes', + }, + ], + name: 'sendMultiSig', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address[]', + name: 'recipients', + type: 'address[]', + }, + { + internalType: 'uint256[]', + name: 'values', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'expireTime', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'sequenceId', + type: 'uint256', + }, + { + internalType: 'bytes', + name: 'signature', + type: 'bytes', + }, + ], + name: 'sendMultiSigBatch', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'toAddress', + type: 'address', + }, + { + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + { + internalType: 'address', + name: 'tokenContractAddress', + type: 'address', + }, + { + internalType: 'uint256', + name: 'expireTime', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'sequenceId', + type: 'uint256', + }, + { + internalType: 'bytes', + name: 'signature', + type: 'bytes', + }, + ], + name: 'sendMultiSigToken', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'forwarderAddress', + type: 'address', + }, + { + internalType: 'bool', + name: 'autoFlush', + type: 'bool', + }, + ], + name: 'setAutoFlush1155', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'forwarderAddress', + type: 'address', + }, + { + internalType: 'bool', + name: 'autoFlush', + type: 'bool', + }, + ], + name: 'setAutoFlush721', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + name: 'signers', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'bytes4', + name: 'interfaceId', + type: 'bytes4', + }, + ], + name: 'supportsInterface', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + stateMutability: 'payable', + type: 'receive', + }, +]; diff --git a/modules/sdk-coin-opeth/src/opeth.ts b/modules/sdk-coin-opeth/src/opeth.ts index 3bd9b10db9..2c29edbea8 100644 --- a/modules/sdk-coin-opeth/src/opeth.ts +++ b/modules/sdk-coin-opeth/src/opeth.ts @@ -1,10 +1,9 @@ import { BaseCoin, BitGoBase } from '@bitgo/sdk-core'; import { BaseCoin as StaticsBaseCoin, coins } from '@bitgo/statics'; -import { AbstractEthLikeMPCCoin } from '@bitgo/abstract-eth'; -import { TransactionBuilder as EthTransactionBuilder } from '@bitgo/sdk-coin-eth'; +import { AbstractEthLikeNewCoins, TransactionBuilder as EthLikeTransactionBuilder } from '@bitgo/abstract-eth'; import { TransactionBuilder } from './lib'; -export class Opeth extends AbstractEthLikeMPCCoin { +export class Opeth extends AbstractEthLikeNewCoins { protected constructor(bitgo: BitGoBase, staticsCoin?: Readonly) { super(bitgo, staticsCoin); } @@ -13,7 +12,7 @@ export class Opeth extends AbstractEthLikeMPCCoin { return new Opeth(bitgo, staticsCoin); } - protected getTransactionBuilder(): EthTransactionBuilder { + protected getTransactionBuilder(): EthLikeTransactionBuilder { return new TransactionBuilder(coins.get(this.getBaseChain())); } } diff --git a/modules/sdk-coin-opeth/test/unit/opeth.ts b/modules/sdk-coin-opeth/test/unit/opeth.ts index afa1c7d420..2985b7247c 100644 --- a/modules/sdk-coin-opeth/test/unit/opeth.ts +++ b/modules/sdk-coin-opeth/test/unit/opeth.ts @@ -23,7 +23,6 @@ describe('Optimism', function () { opeth.getFamily().should.equal('opeth'); opeth.getFullName().should.equal('Optimism Ethereum'); opeth.getBaseFactor().should.equal(1e18); - opeth.supportsTss().should.equal(true); }); it('should return the right info for topeth', function () { @@ -34,7 +33,6 @@ describe('Optimism', function () { topeth.getFamily().should.equal('opeth'); topeth.getFullName().should.equal('Testnet Optimism Ethereum'); topeth.getBaseFactor().should.equal(1e18); - topeth.supportsTss().should.equal(true); }); }); }); diff --git a/modules/sdk-coin-opeth/tsconfig.json b/modules/sdk-coin-opeth/tsconfig.json index 2862c10c0e..52c51f35c6 100644 --- a/modules/sdk-coin-opeth/tsconfig.json +++ b/modules/sdk-coin-opeth/tsconfig.json @@ -16,9 +16,6 @@ { "path": "../sdk-api" }, - { - "path": "../sdk-coin-eth" - }, { "path": "../sdk-core" }, diff --git a/modules/sdk-coin-polygon/src/lib/index.ts b/modules/sdk-coin-polygon/src/lib/index.ts index 2faea7e23d..3a79251f4b 100644 --- a/modules/sdk-coin-polygon/src/lib/index.ts +++ b/modules/sdk-coin-polygon/src/lib/index.ts @@ -1,4 +1,4 @@ -export { Interface, KeyPair, Transaction } from '@bitgo/sdk-coin-eth'; +export { Interface, KeyPair, Transaction } from '@bitgo/abstract-eth'; export { TransactionBuilder } from './transactionBuilder'; export { TransferBuilder } from './transferBuilder'; diff --git a/modules/sdk-coin-polygon/src/lib/transferBuilder.ts b/modules/sdk-coin-polygon/src/lib/transferBuilder.ts index 019378853e..bcc7e8dac8 100644 --- a/modules/sdk-coin-polygon/src/lib/transferBuilder.ts +++ b/modules/sdk-coin-polygon/src/lib/transferBuilder.ts @@ -1,4 +1,4 @@ -import { TransferBuilder as EthTransferBuilder } from '@bitgo/sdk-coin-eth'; +import { TransferBuilder as EthTransferBuilder } from '@bitgo/abstract-eth'; /** POLYGON transfer builder */ export class TransferBuilder extends EthTransferBuilder { diff --git a/modules/sdk-coin-polygon/src/lib/utils.ts b/modules/sdk-coin-polygon/src/lib/utils.ts index 0ddaa2327f..e4a2909397 100644 --- a/modules/sdk-coin-polygon/src/lib/utils.ts +++ b/modules/sdk-coin-polygon/src/lib/utils.ts @@ -1,4 +1,4 @@ -import { Utils, KeyPair, TxData } from '@bitgo/sdk-coin-eth'; +import { Utils, KeyPair, TxData } from '@bitgo/abstract-eth'; import { InvalidTransactionError } from '@bitgo/sdk-core'; import { NetworkType } from '@bitgo/statics'; import EthereumCommon from '@ethereumjs/common'; diff --git a/modules/sdk-coin-polygon/src/polygonToken.ts b/modules/sdk-coin-polygon/src/polygonToken.ts index 4d87befa56..f007984dda 100644 --- a/modules/sdk-coin-polygon/src/polygonToken.ts +++ b/modules/sdk-coin-polygon/src/polygonToken.ts @@ -3,7 +3,7 @@ */ import { Polygon } from './polygon'; -import { TransactionPrebuild } from '@bitgo/sdk-coin-eth'; +import { TransactionPrebuild } from '@bitgo/abstract-eth'; import { EthLikeTokenConfig, tokens, coins } from '@bitgo/statics'; import { BitGoBase, CoinConstructor, NamedCoinConstructor } from '@bitgo/sdk-core'; diff --git a/modules/sdk-coin-xlm/package.json b/modules/sdk-coin-xlm/package.json index 3226539f7d..4b799cf2c9 100644 --- a/modules/sdk-coin-xlm/package.json +++ b/modules/sdk-coin-xlm/package.json @@ -43,7 +43,7 @@ "@bitgo/sdk-core": "^8.26.0", "@bitgo/statics": "^29.0.0", "@bitgo/utxo-lib": "^9.16.0", - "bignumber.js": "^8.0.1", + "bignumber.js": "^9.1.1", "lodash": "^4.17.14", "stellar-sdk": "^10.0.1", "superagent": "^3.8.3" diff --git a/modules/sdk-core/package.json b/modules/sdk-core/package.json index 66c5579da6..84a1b4b4f4 100644 --- a/modules/sdk-core/package.json +++ b/modules/sdk-core/package.json @@ -47,7 +47,7 @@ "bech32": "^2.0.0", "big.js": "^3.1.3", "bigint-crypto-utils": "3.1.4", - "bignumber.js": "^9.0.0", + "bignumber.js": "^9.1.1", "bitcoinjs-message": "npm:@bitgo-forks/bitcoinjs-message@1.0.0-master.2", "bolt11": "^1.4.0", "bs58": "^4.0.1", diff --git a/modules/sdk-test/package.json b/modules/sdk-test/package.json index 3836b88736..bc19bbf334 100644 --- a/modules/sdk-test/package.json +++ b/modules/sdk-test/package.json @@ -29,7 +29,7 @@ "dependencies": { "@bitgo/sdk-api": "^1.24.0", "@bitgo/sdk-core": "^8.26.0", - "bignumber.js": "^8.0.1", + "bignumber.js": "^9.1.1", "should-http": "^0.1.1" } } diff --git a/yarn.lock b/yarn.lock index 0e48a05782..b0de195043 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6673,7 +6673,7 @@ bigint-mod-arith@^3.1.0: resolved "https://registry.npmjs.org/bigint-mod-arith/-/bigint-mod-arith-3.2.1.tgz" integrity sha512-roLlzeQ0okNjT8Ph9zL9Nvw85ucHSQkNndLRfAR2CVaYOEAMtbpIK3f6oJb3Jv/hg9mkrYaw/DknysTuvc8QhA== -bignumber.js@8.1.1, bignumber.js@^8.0.1: +bignumber.js@8.1.1: version "8.1.1" resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-8.1.1.tgz" integrity sha512-QD46ppGintwPGuL1KqmwhR0O+N2cZUg8JG/VzwI2e28sM9TqHjQB10lI4QAaMHVbLzwVLLAwEglpKPViWX+5NQ==