diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5af4d725..fe8f0841 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: with: cache: yarn node-version: ${{ env.node_version }} - - run: yarn --frozen-lockfile + - run: yarn --frozen-lockfile --network-timeout 1000000 - run: yarn test --ci --coverage --maxWorkers=2 Lint: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index cc8e07dc..b6727e3d 100644 --- a/.gitignore +++ b/.gitignore @@ -111,5 +111,5 @@ public/ # End of https://www.gitignore.io/api/node.idea/* .markdownlint.json - +TODO.md diff --git a/package.json b/package.json index d0accfd9..91fb5e74 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "docs:watch": "typedoc --watch src/index.ts" }, "peerDependencies": { - "avalanche": "3.8.*" + "avalanche": "3.10.*" }, "lint-staged": { "**/*": "prettier --write --ignore-unknown" @@ -40,6 +40,7 @@ "@babel/core": "^7.14.0", "@babel/preset-env": "^7.14.1", "@babel/preset-typescript": "^7.13.0", + "@rollup/plugin-commonjs": "^21.0.1", "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-typescript": "^8.2.1", "@types/big.js": "^6.0.2", @@ -50,6 +51,7 @@ "@typescript-eslint/eslint-plugin": "^4.22.1", "@typescript-eslint/parser": "^4.22.1", "@zerollup/ts-transform-paths": "^1.7.18", + "avalanche": "3.10.1", "babel-jest": "^26.6.3", "babel-plugin-module-resolver": "^4.1.0", "eslint": "^7.25.0", @@ -69,12 +71,12 @@ "typescript": "^4.2.4" }, "dependencies": { - "@ethereumjs/common": "2.4.0", - "@ethereumjs/tx": "3.3.0", + "@ethereumjs/common": "2.6.0", + "@ethereumjs/tx": "3.4.0", "@ledgerhq/hw-app-eth": "6.12.2", + "@ledgerhq/hw-transport": "^6.19.0", "@obsidiansystems/hw-app-avalanche": "0.2.2", - "@openzeppelin/contracts": "4.3.3", - "avalanche": "3.8.1", + "@openzeppelin/contracts": "4.4.1", "big.js": "^6.1.1", "bip32": "^2.0.6", "bip32-path": "^0.4.2", @@ -83,13 +85,11 @@ "create-hash": "1.2.0", "ethereumjs-util": "^7.0.7", "ethers": "^5.1.4", - "moment": "^2.29.1", - "rollup-plugin-commonjs": "^10.1.0", "sockette": "^2.0.6", "typescript-transform-paths": "^2.2.3", "url": "^0.11.0", - "web3": "^1.3.5", - "web3-eth-contract": "^1.3.6", + "web3": "1.6.0", + "web3-eth-contract": "1.6.0", "xss": "^1.0.10" } } diff --git a/rollup.config.js b/rollup.config.js index 38e488d0..81c13f96 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,5 +1,5 @@ import json from '@rollup/plugin-json'; -import commonjs from 'rollup-plugin-commonjs'; +import commonjs from '@rollup/plugin-commonjs'; import del from 'rollup-plugin-delete'; import ttypescript from 'ttypescript'; import typescript from 'rollup-plugin-typescript2'; diff --git a/src/Keystore/keystore.ts b/src/Keystore/keystore.ts index f96f71a5..cbd76141 100644 --- a/src/Keystore/keystore.ts +++ b/src/Keystore/keystore.ts @@ -26,13 +26,14 @@ import { } from './types'; import { xChain } from '@/Network/network'; import { Buffer } from 'buffer/'; -import MnemonicWallet from '@/Wallet/MnemonicWallet'; +import { MnemonicWallet } from '@/Wallet/MnemonicWallet'; import Crypto from './Crypto'; -import SingletonWallet from '@/Wallet/SingletonWallet'; +import { SingletonWallet } from '@/Wallet/SingletonWallet'; import { AccessWalletMultipleInput } from './types'; // import { keyToKeypair } from '@/helpers/helper' import * as bip39 from 'bip39'; import { bintools } from '@/common'; +import { Buffer as AjsBuffer } from 'avalanche'; const cryptoHelpers = new Crypto(); @@ -63,7 +64,7 @@ async function readV2(data: KeyFileV2, pass: string) { let checkHashString: string; let checkHash: Buffer = await cryptoHelpers._pwcleaner(pass, salt); - checkHashString = bintools.cb58Encode(checkHash); + checkHashString = bintools.cb58Encode(AjsBuffer.from(checkHash)); if (checkHashString !== pass_hash) { throw 'INVALID_PASS'; @@ -79,7 +80,7 @@ async function readV2(data: KeyFileV2, pass: string) { let nonce: Buffer = bintools.cb58Decode(key_data.iv); let key_decrypt: Buffer = await cryptoHelpers.decrypt(pass, key, salt, nonce); - let key_string = bintools.cb58Encode(key_decrypt); + let key_string = bintools.cb58Encode(AjsBuffer.from(key_decrypt)); keysDecrypt.push({ key: key_string, @@ -101,7 +102,7 @@ async function readV3(data: KeyFileV3, pass: string) { let checkHashString: string; let checkHash: IHash = await cryptoHelpers.pwhash(pass, salt); - checkHashString = bintools.cb58Encode(checkHash.hash); + checkHashString = bintools.cb58Encode(AjsBuffer.from(checkHash.hash)); if (checkHashString !== pass_hash) { throw 'INVALID_PASS'; @@ -117,7 +118,7 @@ async function readV3(data: KeyFileV3, pass: string) { let nonce: Buffer = bintools.cb58Decode(key_data.iv); let key_decrypt: Buffer = await cryptoHelpers.decrypt(pass, key, salt, nonce); - let key_string = bintools.cb58Encode(key_decrypt); + let key_string = bintools.cb58Encode(AjsBuffer.from(key_decrypt)); keysDecrypt.push({ key: key_string, @@ -139,7 +140,7 @@ async function readV4(data: KeyFileV4, pass: string): Promise { + // Subtract transfer fees from parent balance + // import + export + let parentBalance = node.reduceTotalBalanceFromParents(); + parentBalance = parentBalance.sub(this.feeImport).sub(node.feeExport); + let zero = new BN(0); + return BN.max(parentBalance, zero); + }); + + let tot = parentBals.reduce((prev, current) => { + return prev.add(current); + }, new BN(0)); + + return tot.add(this.balance); + } + + /** + * Returns the export action type from this node to its child + * @param to + */ + abstract getExportMethod(to: ChainIdType): UniversalTxActionExport; + + /** + * Returns the import action type from this node to its child + * @param from Which chain are we importing from + */ + abstract getImportMethod(from: ChainIdType): UniversalTxActionImport; + + buildExportTx(destChain: ChainIdType, amount: BN): UniversalTxExport { + return { + action: this.getExportMethod(destChain), + amount: amount, + fee: this.feeExport, + }; + } + + buildImportTx(sourceChain: ChainIdType): UniversalTxImport { + return { + action: this.getImportMethod(sourceChain), + fee: this.feeImport, + }; + } + + /*** + * Assumes there is enough balance on node tree + * Returns empty array even if transaction not possible! + * What steps to take to have the target balance on this node. + * @param target Amount of nAVAX needed on this node. + */ + getStepsForTargetBalance(target: BN): UniversalTx[] { + // If the node has enough balance no transaction needed + // If target is negative or zero no transaction needed + if (this.balance.gte(target) || target.lte(new BN(0))) { + return []; + } + + // If not enough balance and no parents + // return all the balance + if (this.balance.lt(target) && this.parents.length === 0) { + return []; + } + + // If not enough balance on this node, try to collect it from parents + // Amount needed to collect from parents + let remaining = target.sub(this.balance); + + let transactions = []; + for (let i = 0; i < this.parents.length; i++) { + let p = this.parents[i]; + + if (remaining.lte(new BN(0))) break; + + // Parent's balance + let pBal = p.reduceTotalBalanceFromParents(); + const exportFee = p.feeExport; + const importFee = this.feeImport; + const feeImportExport = exportFee.add(importFee); + // Maximum balance we can import from parent + let pBalMax = pBal.sub(feeImportExport); + // The parent needs to have this balance to satisfy the needed amount + + // Try to export the remaining amount, if the parent balance is lower than that export the maximum amount + // Import amount is the usable amount imported + const importAmt = BN.min(pBalMax, remaining); // The amount that will cross to the target chain + // Exported amount should include the import fees + const exportAmt = importAmt.add(importFee); + + if (exportAmt.lte(new BN(0))) continue; + + let pTx = p.buildExportTx(this.chain, exportAmt); + let importTx = this.buildImportTx(p.chain); + + transactions.push(pTx); + transactions.push(importTx); + + remaining = remaining.sub(importAmt); + } + + // If we still have remaining balance, we can not complete this transfer + if (remaining.gt(new BN(0))) { + throw new Error('Insufficient AVAX balances.'); + } + + return transactions; + } + + addParent(node: UniversalNodeAbstract) { + this.parents.push(node); + } + + setChild(node: UniversalNodeAbstract) { + this.child = node; + } +} diff --git a/src/UniversalTx/UniversalNodeC.ts b/src/UniversalTx/UniversalNodeC.ts new file mode 100644 index 00000000..f46ce23a --- /dev/null +++ b/src/UniversalTx/UniversalNodeC.ts @@ -0,0 +1,39 @@ +import { UniversalNodeAbstract } from '@/UniversalTx/UniversalNode'; +import { ExportChainsC } from '@/Wallet/types'; +import { + UniversalTxActionExportC, + UniversalTxActionImportC, + UniversalTxExportC, + UniversalTxImportC, +} from '@/UniversalTx/types'; +import { BN } from 'avalanche'; + +export default class UniversalNodeC extends UniversalNodeAbstract { + constructor(balance: BN, feeExport: BN, feeImport: BN) { + super(balance, 'C', feeExport, feeImport); + } + + buildExportTx(destChain: ExportChainsC, amount: BN): UniversalTxExportC { + return super.buildExportTx(destChain, amount) as UniversalTxExportC; + } + + buildImportTx(sourceChain: ExportChainsC): UniversalTxImportC { + return super.buildImportTx(sourceChain) as UniversalTxImportC; + } + + getExportMethod(to: ExportChainsC): UniversalTxActionExportC { + if (to === 'X') { + return 'export_c_x'; + } else { + return 'export_c_p'; + } + } + + getImportMethod(from: ExportChainsC): UniversalTxActionImportC { + if (from === 'X') { + return 'import_x_c'; + } else { + return 'import_p_c'; + } + } +} diff --git a/src/UniversalTx/UniversalNodeP.ts b/src/UniversalTx/UniversalNodeP.ts new file mode 100644 index 00000000..75965278 --- /dev/null +++ b/src/UniversalTx/UniversalNodeP.ts @@ -0,0 +1,39 @@ +import { UniversalNodeAbstract } from '@/UniversalTx/UniversalNode'; +import { ExportChainsP } from '@/Wallet/types'; +import { + UniversalTxActionExportP, + UniversalTxActionImportP, + UniversalTxExportP, + UniversalTxImportP, +} from '@/UniversalTx/types'; +import { BN } from 'avalanche'; + +export default class UniversalNodeP extends UniversalNodeAbstract { + constructor(balance: BN, feeExport: BN, feeImport: BN) { + super(balance, 'P', feeExport, feeImport); + } + + buildExportTx(destChain: ExportChainsP, amount: BN): UniversalTxExportP { + return super.buildExportTx(destChain, amount) as UniversalTxExportP; + } + + buildImportTx(sourceChain: ExportChainsP): UniversalTxImportP { + return super.buildImportTx(sourceChain) as UniversalTxImportP; + } + + getExportMethod(to: ExportChainsP): UniversalTxActionExportP { + if (to === 'X') { + return 'export_p_x'; + } else { + return 'export_p_c'; + } + } + + getImportMethod(from: ExportChainsP): UniversalTxActionImportP { + if (from === 'X') { + return 'import_x_p'; + } else { + return 'import_c_p'; + } + } +} diff --git a/src/UniversalTx/UniversalNodeX.ts b/src/UniversalTx/UniversalNodeX.ts new file mode 100644 index 00000000..fb5e037c --- /dev/null +++ b/src/UniversalTx/UniversalNodeX.ts @@ -0,0 +1,39 @@ +import { UniversalNodeAbstract } from '@/UniversalTx/UniversalNode'; +import { ExportChainsX } from '@/Wallet/types'; +import { + UniversalTxActionExportX, + UniversalTxActionImportX, + UniversalTxExportX, + UniversalTxImportX, +} from '@/UniversalTx/types'; +import { BN } from 'avalanche'; + +export default class UniversalNodeX extends UniversalNodeAbstract { + constructor(balance: BN, feeExport: BN, feeImport: BN) { + super(balance, 'X', feeExport, feeImport); + } + + buildExportTx(destChain: ExportChainsX, amount: BN): UniversalTxExportX { + return super.buildExportTx(destChain, amount) as UniversalTxExportX; + } + + buildImportTx(sourceChain: ExportChainsX): UniversalTxImportX { + return super.buildImportTx(sourceChain) as UniversalTxImportX; + } + + getExportMethod(to: ExportChainsX): UniversalTxActionExportX { + if (to === 'P') { + return 'export_x_p'; + } else { + return 'export_x_c'; + } + } + + getImportMethod(from: ExportChainsX): UniversalTxActionImportX { + if (from === 'P') { + return 'import_p_x'; + } else { + return 'import_c_x'; + } + } +} diff --git a/src/UniversalTx/index.ts b/src/UniversalTx/index.ts new file mode 100644 index 00000000..73310aa8 --- /dev/null +++ b/src/UniversalTx/index.ts @@ -0,0 +1,6 @@ +export * from './types'; +export * from './utils'; +export * from './UniversalNode'; +export * from './UniversalNodeX'; +export * from './UniversalNodeP'; +export * from './UniversalNodeC'; diff --git a/src/UniversalTx/types.ts b/src/UniversalTx/types.ts new file mode 100644 index 00000000..16dfa087 --- /dev/null +++ b/src/UniversalTx/types.ts @@ -0,0 +1,62 @@ +import { BN } from 'avalanche'; + +export type UniversalTxActionExportC = 'export_c_x' | 'export_c_p'; +export type UniversalTxActionImportC = 'import_x_c' | 'import_p_c'; + +export type UniversalTxActionExportX = 'export_x_p' | 'export_x_c'; +export type UniversalTxActionImportX = 'import_p_x' | 'import_c_x'; + +export type UniversalTxActionExportP = 'export_p_x' | 'export_p_c'; +export type UniversalTxActionImportP = 'import_x_p' | 'import_c_p'; + +export type UniversalTxActionExport = UniversalTxActionExportC | UniversalTxActionExportX | UniversalTxActionExportP; + +export type UniversalTxActionImport = UniversalTxActionImportC | UniversalTxActionImportX | UniversalTxActionImportP; + +export interface UniversalTxExport { + action: UniversalTxActionExport; + amount: BN; + fee: BN; +} + +export interface UniversalTxImport { + action: UniversalTxActionImport; + fee: BN; +} + +type UniversalTxActionTypesX = UniversalTxActionExportX | UniversalTxActionImportX; +type UniversalTxActionTypesC = UniversalTxActionExportC | UniversalTxActionImportC; +type UniversalTxActionTypesP = UniversalTxActionExportP | UniversalTxActionImportP; + +export type UniversalTxActionType = UniversalTxActionTypesX | UniversalTxActionTypesC | UniversalTxActionTypesP; + +export type UniversalTx = UniversalTxsX | UniversalTxsP | UniversalTxsC; + +type UniversalTxsX = UniversalTxExportX | UniversalTxImportX; +type UniversalTxsP = UniversalTxExportP | UniversalTxImportP; +type UniversalTxsC = UniversalTxExportC | UniversalTxImportC; + +export interface UniversalTxExportC extends UniversalTxExport { + action: UniversalTxActionExportC; +} + +export interface UniversalTxExportX extends UniversalTxExport { + action: UniversalTxActionExportX; +} + +export interface UniversalTxExportP extends UniversalTxExport { + action: UniversalTxActionExportP; +} + +export interface UniversalTxImportC extends UniversalTxImport { + action: UniversalTxActionImportC; + fee: BN; +} + +export interface UniversalTxImportX extends UniversalTxImport { + action: UniversalTxActionImportX; +} + +export interface UniversalTxImportP extends UniversalTxImport { + action: UniversalTxActionImportP; +} diff --git a/src/UniversalTx/utils.ts b/src/UniversalTx/utils.ts new file mode 100644 index 00000000..3af3b446 --- /dev/null +++ b/src/UniversalTx/utils.ts @@ -0,0 +1,136 @@ +import { BN } from 'avalanche'; +import { UniversalTx } from '@/UniversalTx/types'; +import UniversalNodeX from '@/UniversalTx/UniversalNodeX'; +import UniversalNodeP from '@/UniversalTx/UniversalNodeP'; +import UniversalNodeC from '@/UniversalTx/UniversalNodeC'; + +export function createGraphForP(balX: BN, balP: BN, balC: BN, atomicFeeXP: BN, atomicFeeC: BN): UniversalNodeP { + let xNode = new UniversalNodeX(balX, atomicFeeXP, atomicFeeXP); + let pNode = new UniversalNodeP(balP, atomicFeeXP, atomicFeeXP); + let cNode = new UniversalNodeC(balC, atomicFeeC, atomicFeeC); + + pNode.addParent(xNode); + pNode.addParent(cNode); + + cNode.setChild(pNode); + xNode.setChild(pNode); + return pNode; +} + +export function createGraphForC(balX: BN, balP: BN, balC: BN, atomicFeeXP: BN, atomicFeeC: BN): UniversalNodeC { + let xNode = new UniversalNodeX(balX, atomicFeeXP, atomicFeeXP); + let pNode = new UniversalNodeP(balP, atomicFeeXP, atomicFeeXP); + let cNode = new UniversalNodeC(balC, atomicFeeC, atomicFeeC); + + cNode.addParent(xNode); + cNode.addParent(pNode); + + pNode.setChild(cNode); + xNode.setChild(cNode); + + return cNode; +} + +export function createGraphForX(balX: BN, balP: BN, balC: BN, atomicFeeXP: BN, atomicFeeC: BN): UniversalNodeX { + let xNode = new UniversalNodeX(balX, atomicFeeXP, atomicFeeXP); + let pNode = new UniversalNodeP(balP, atomicFeeXP, atomicFeeXP); + let cNode = new UniversalNodeC(balC, atomicFeeC, atomicFeeC); + + xNode.addParent(pNode); + xNode.addParent(cNode); + + cNode.setChild(xNode); + pNode.setChild(xNode); + + return xNode; +} + +export function canHaveBalanceOnX( + balX: BN, + balP: BN, + balC: BN, + targetAmount: BN, + atomicFeeXP: BN, + atomicFeeC: BN +): boolean { + let startNode = createGraphForX(balX, balP, balC, atomicFeeXP, atomicFeeC); + return startNode.reduceTotalBalanceFromParents().gte(targetAmount); +} + +export function canHaveBalanceOnP( + balX: BN, + balP: BN, + balC: BN, + targetAmount: BN, + atomicFeeXP: BN, + atomicFeeC: BN +): boolean { + let startNode = createGraphForP(balX, balP, balC, atomicFeeXP, atomicFeeC); + return startNode.reduceTotalBalanceFromParents().gte(targetAmount); +} + +/** + * Will return true if `targetAmount` can exist on C chain + */ +export function canHaveBalanceOnC( + balX: BN, + balP: BN, + balC: BN, + targetAmount: BN, + atomicFeeXP: BN, + atomicFeeC: BN +): boolean { + let startNode = createGraphForC(balX, balP, balC, atomicFeeXP, atomicFeeC); + return startNode.reduceTotalBalanceFromParents().gte(targetAmount); +} + +export function getStepsForBalanceP( + balX: BN, + balP: BN, + balC: BN, + targetAmount: BN, + atomicFeeXP: BN, + atomicFeeC: BN +): UniversalTx[] { + let startNode = createGraphForP(balX, balP, balC, atomicFeeXP, atomicFeeC); + + if (startNode.reduceTotalBalanceFromParents().lt(targetAmount)) { + throw new Error('Insufficient AVAX.'); + } + + return startNode.getStepsForTargetBalance(targetAmount); +} + +export function getStepsForBalanceC( + balX: BN, + balP: BN, + balC: BN, + targetAmount: BN, + atomicFeeXP: BN, + atomicFeeC: BN +): UniversalTx[] { + let startNode = createGraphForC(balX, balP, balC, atomicFeeXP, atomicFeeC); + + if (startNode.reduceTotalBalanceFromParents().lt(targetAmount)) { + throw new Error('Insufficient AVAX.'); + } + + return startNode.getStepsForTargetBalance(targetAmount); +} + +export function getStepsForBalanceX( + balX: BN, + balP: BN, + balC: BN, + targetAmount: BN, + atomicFeeXP: BN, + atomicFeeC: BN +): UniversalTx[] { + let startNode = createGraphForX(balX, balP, balC, atomicFeeXP, atomicFeeC); + + if (startNode.reduceTotalBalanceFromParents().lt(targetAmount)) { + throw new Error('Insufficient AVAX.'); + } + + return startNode.getStepsForTargetBalance(targetAmount); +} diff --git a/src/Wallet/EvmWallet.ts b/src/Wallet/EvmWallet.ts index 168861fa..8b941029 100644 --- a/src/Wallet/EvmWallet.ts +++ b/src/Wallet/EvmWallet.ts @@ -1,6 +1,5 @@ import { Buffer as BufferAvalanche } from 'avalanche'; -import { privateToPublic } from 'ethereumjs-util'; -import { Transaction } from '@ethereumjs/tx'; +import { FeeMarketEIP1559Transaction, Transaction } from '@ethereumjs/tx'; import { avalanche } from '@/Network/network'; import { KeyChain as EVMKeyChain, @@ -8,14 +7,17 @@ import { UnsignedTx as EVMUnsignedTx, Tx as EVMTx, } from 'avalanche/dist/apis/evm'; -import EvmWalletReadonly from '@/Wallet/EvmWalletReadonly'; +import { EvmWalletReadonly } from '@/Wallet/EvmWalletReadonly'; import { bintools } from '@/common'; +import { computePublicKey } from 'ethers/lib/utils'; -export default class EvmWallet extends EvmWalletReadonly { +export class EvmWallet extends EvmWalletReadonly { private privateKey: Buffer; constructor(key: Buffer) { - let pubKey = privateToPublic(key); + // Compute the uncompressed public key from private key + let pubKey = computePublicKey(key); + super(pubKey); this.privateKey = key; @@ -36,7 +38,7 @@ export default class EvmWallet extends EvmWalletReadonly { return keychain.importKey(this.getPrivateKeyBech()); } - signEVM(tx: Transaction) { + signEVM(tx: Transaction | FeeMarketEIP1559Transaction) { return tx.sign(this.privateKey); } diff --git a/src/Wallet/EvmWalletReadonly.ts b/src/Wallet/EvmWalletReadonly.ts index 5fb14617..173d1590 100644 --- a/src/Wallet/EvmWalletReadonly.ts +++ b/src/Wallet/EvmWalletReadonly.ts @@ -1,18 +1,24 @@ import { BN, Buffer as BufferAvalanche } from 'avalanche'; import { avalanche, web3 } from '@/Network/network'; -import { publicToAddress, importPublic } from 'ethereumjs-util'; import { ethers } from 'ethers'; import { KeyPair as EVMKeyPair } from 'avalanche/dist/apis/evm/keychain'; import { bintools } from '@/common'; +import { computePublicKey, computeAddress } from 'ethers/lib/utils'; -export default class EvmWalletReadonly { +export class EvmWalletReadonly { balance = new BN(0); address: string; - publicKey: Buffer; + publicKey: string; + publicKeyBuff: Buffer; - constructor(publicKey: Buffer) { + /** + * + * @param publicKey 64 byte uncompressed public key. Starts with `0x`. + */ + constructor(publicKey: string) { this.publicKey = publicKey; - this.address = '0x' + publicToAddress(publicKey).toString('hex'); + this.publicKeyBuff = Buffer.from(publicKey.substr(2), 'hex'); + this.address = computeAddress(publicKey); } getBalance(): BN { @@ -24,8 +30,9 @@ export default class EvmWalletReadonly { } getAddressBech32(): string { + const compressedKey = computePublicKey(this.publicKey, true); let keypair = new EVMKeyPair(avalanche.getHRP(), 'C'); - let addr = keypair.addressFromPublicKey(BufferAvalanche.from(this.publicKey)); + let addr = keypair.addressFromPublicKey(BufferAvalanche.from(compressedKey.substr(2), 'hex')); return bintools.addressToString(avalanche.getHRP(), 'C', addr); } diff --git a/src/Wallet/HDWalletAbstract.ts b/src/Wallet/HDWalletAbstract.ts index 517c4bae..b4faee34 100644 --- a/src/Wallet/HDWalletAbstract.ts +++ b/src/Wallet/HDWalletAbstract.ts @@ -1,5 +1,5 @@ import { WalletProvider } from '@/Wallet/Wallet'; -import HdScanner from '@/Wallet/HdScanner'; +import { HdScanner } from '@/Wallet/HdScanner'; import { UTXOSet as AVMUTXOSet } from 'avalanche/dist/apis/avm/utxos'; import { avalanche } from '@/Network/network'; import { UTXOSet as PlatformUTXOSet } from 'avalanche/dist/apis/platformvm'; @@ -14,6 +14,11 @@ export abstract class HDWalletAbstract extends WalletProvider { protected accountKey: bip32.BIP32Interface; public isHdReady = false; + /** + * + * @param accountKey The bip32 HD node for path `m/44'/9000'/n'` where n is the desired account index. + * @protected + */ protected constructor(accountKey: bip32.BIP32Interface) { super(); diff --git a/src/Wallet/HdScanner.ts b/src/Wallet/HdScanner.ts index 8da19f3b..fc873bb0 100644 --- a/src/Wallet/HdScanner.ts +++ b/src/Wallet/HdScanner.ts @@ -30,7 +30,7 @@ type KeyCacheP = { }; // Each HD wallet has 2 HdScaners, one for internal chain, one for external -export default class HdScanner { +export class HdScanner { protected index = 0; protected addressCache: AddressCache = {}; protected keyCacheX: KeyCacheX = {}; diff --git a/src/Wallet/LedgerWallet.ts b/src/Wallet/Ledger/LedgerWallet.ts similarity index 70% rename from src/Wallet/LedgerWallet.ts rename to src/Wallet/Ledger/LedgerWallet.ts index 8cd9914e..8af622ce 100644 --- a/src/Wallet/LedgerWallet.ts +++ b/src/Wallet/Ledger/LedgerWallet.ts @@ -1,8 +1,9 @@ +//@ts-ignore import Eth from '@ledgerhq/hw-app-eth'; // @ts-ignore import AppAvax from '@obsidiansystems/hw-app-avalanche'; import EthereumjsCommon from '@ethereumjs/common'; -import { importPublic, publicToAddress, bnToRlp, rlp, BN as EthBN } from 'ethereumjs-util'; +import { importPublic, bnToRlp, rlp, BN as EthBN } from 'ethereumjs-util'; import { AVAX_ACCOUNT_PATH, ETH_ACCOUNT_PATH, @@ -36,119 +37,133 @@ import { UnsignedTx as PlatformUnsignedTx, Tx as PlatformTx, PlatformVMConstants, + ExportTx as PlatformExportTx, ImportTx as PlatformImportTx, SelectCredentialClass as PlatformSelectCredentialClass, } from 'avalanche/dist/apis/platformvm'; -import { HDWalletAbstract } from '@/Wallet/HDWalletAbstract'; -import EvmWalletReadonly from '@/Wallet/EvmWalletReadonly'; -import { KeyPair as EVMKeyPair } from 'avalanche/dist/apis/evm/keychain'; import { activeNetwork, avalanche, web3 } from '@/Network/network'; -import { Buffer, BN } from 'avalanche'; +import { Buffer } from 'avalanche'; import { ChainIdType } from '@/types'; import { ParseableAvmTxEnum, ParseablePlatformEnum, ParseableEvmTxEnum } from '@/helpers/tx_helper'; import createHash from 'create-hash'; //@ts-ignore import bippath from 'bip32-path'; import { bintools } from '@/common'; -import * as bip32 from 'bip32'; - -export default class LedgerWallet extends HDWalletAbstract { - evmWallet: EvmWalletReadonly; - type: WalletNameType = 'ledger'; - evmAccount: HDKey; - config: ILedgerAppConfig; - - appAvax: AppAvax; - ethApp: Eth; - - constructor( - avaxAcct: bip32.BIP32Interface, - evmAcct: HDKey, - avaxApp: AppAvax, - ethApp: Eth, - config: ILedgerAppConfig - ) { - super(avaxAcct); - this.evmAccount = evmAcct; - this.config = config; - this.appAvax = avaxApp; - this.ethApp = ethApp; +import { idToChainAlias } from '@/Network'; +import { getAccountPathAvalanche, getAccountPathEVM } from '@/Wallet/helpers/derivationHelper'; +import { PublicMnemonicWallet } from '@/Wallet/PublicMnemonicWallet'; +import { getAppAvax, getAppEth, getEthAddressKeyFromAccountKey, getLedgerConfigAvax } from '@/Wallet/Ledger/utils'; +import Transport from '@ledgerhq/hw-transport'; +import { ERR_ConfigNotSet, ERR_TransportNotSet } from '@/Wallet/Ledger/errors'; + +export class LedgerWallet extends PublicMnemonicWallet { + type: WalletNameType; + static transport: Transport | undefined; + static config: ILedgerAppConfig | undefined; + accountIndex: number; + + /** + * + * @param xpubAVM of derivation path m/44'/9000'/n' where `n` is the account index + * @param xpubEVM of derivation path m/44'/60'/0'/0/n where `n` is the account index + * @param accountIndex The given xpubs must match this index + * @param config + */ + constructor(xpubAVM: string, xpubEVM: string, accountIndex: number) { + super(xpubAVM, xpubEVM); - this.evmWallet = new EvmWalletReadonly(importPublic(evmAcct.publicKey)); + this.type = 'ledger'; + this.accountIndex = accountIndex; } + static async setTransport(transport: Transport) { + LedgerWallet.transport = transport; + + transport.on('disconnect', () => { + console.log('transport disconnect'); + LedgerWallet.transport = undefined; + }); + + // Update the config + const config = await getLedgerConfigAvax(transport); + LedgerWallet.config = config; + } /** * Create a new ledger wallet instance from the given transport * @param transport + * @param accountIndex */ - static async fromTransport(transport: any) { + static async fromTransport(transport: Transport, accountIndex = 0) { transport.setExchangeTimeout(LEDGER_EXCHANGE_TIMEOUT); - let app, eth; - try { - app = new AppAvax(transport, 'w0w'); - eth = new Eth(transport, 'w0w'); - } catch (e) { - throw new Error('Failed to create ledger instance from the given transport.'); - } + const pubAvax = await LedgerWallet.getExtendedPublicKeyAvaxAccount(transport, accountIndex); + const pubEth = await LedgerWallet.getExtendedPublicKeyEthAddress(transport, accountIndex); - let config = await app.getAppConfiguration(); - - if (!config) { - throw new Error(`Unable to connect ledger. You must use ledger version ${MIN_EVM_SUPPORT_V} or above.`); - } + let config = await getLedgerConfigAvax(transport); if (config.version < MIN_EVM_SUPPORT_V) { throw new Error(`Unable to connect ledger. You must use ledger version ${MIN_EVM_SUPPORT_V} or above.`); } - - return await LedgerWallet.fromApp(app, eth); + // Use this transport for all ledger instances + LedgerWallet.setTransport(transport); + const wallet = new LedgerWallet(pubAvax, pubEth, accountIndex); + return wallet; } - static async getAvaxAccount(app: AppAvax): Promise { - let res = await app.getWalletExtendedPublicKey(AVAX_ACCOUNT_PATH); - - let pubKey = res.public_key; - let chainCode = res.chain_code; - - let hd = bip32.fromPublicKey(pubKey, chainCode); - - return hd; - } - - static async getEvmAccount(eth: Eth): Promise { - let ethRes = await eth.getAddress(LEDGER_ETH_ACCOUNT_PATH, true, true); + /** + * Returns the extended public key used by C chain for address derivation. + * @remarks Returns the extended public key for path `m/44'/60'/0'`. This key can be used to derive C chain addresses. + * @param transport + */ + static async getExtendedPublicKeyEthAccount(transport: Transport): Promise { + const ethApp = getAppEth(transport); + let ethRes = await ethApp.getAddress(ETH_ACCOUNT_PATH, true, true); let hdEth = new HDKey(); // @ts-ignore hdEth.publicKey = Buffer.from(ethRes.publicKey, 'hex'); // @ts-ignore hdEth.chainCode = Buffer.from(ethRes.chainCode, 'hex'); - - return hdEth; + return hdEth.publicExtendedKey; } - static async fromApp(app: AppAvax, eth: Eth): Promise { - try { - let avaxAccount = await LedgerWallet.getAvaxAccount(app); - let evmAccount = await LedgerWallet.getEvmAccount(eth); - let config = await app.getAppConfiguration(); - return new LedgerWallet(avaxAccount, evmAccount, app, eth, config); - } catch (e) { - throw new Error('Unable to create ledger wallet instance from the given apps.'); - } + /** + * Get the extended public key for a specific C chain address. + * @returns The xpub of HD node m/44'/60'/0'/0/n where `n` is `accountIndex` + * @param transport + * @param accountIndex + */ + static async getExtendedPublicKeyEthAddress(transport: Transport, accountIndex: number): Promise { + const accountKey = await LedgerWallet.getExtendedPublicKeyEthAccount(transport); + return getEthAddressKeyFromAccountKey(accountKey, accountIndex); } - getAddressC(): string { - return this.evmWallet.getAddress(); - } + /** + * Returns the extended public key used by X and P chains for address derivation. + * @remarks Returns the extended public key for path `m/44'/90000'/n'` where `n` is the account index. + * @param transport + * @param accountIndex Which account's public key to derive + */ + static async getExtendedPublicKeyAvaxAccount(transport: Transport, accountIndex = 0): Promise { + const app = getAppAvax(transport); + + let res = await app.getWalletExtendedPublicKey(getAccountPathAvalanche(accountIndex)); + + let pubKey = res.public_key; + let chainCode = res.chain_code; + + // Get the base58 publick key from the HDKey instance + let hdKey = new HDKey(); + // @ts-ignore + hdKey.publicKey = pubKey; + // @ts-ignore + hdKey.chainCode = chainCode; - getEvmAddressBech(): string { - let keypair = new EVMKeyPair(avalanche.getHRP(), 'C'); - let addr = keypair.addressFromPublicKey(Buffer.from(this.evmAccount.publicKey)); - return bintools.addressToString(avalanche.getHRP(), 'C', addr); + return hdKey.publicExtendedKey; } async signEvm(tx: Transaction): Promise { + if (!LedgerWallet.transport) throw ERR_TransportNotSet; + const rawUnsignedTx = rlp.encode([ bnToRlp(tx.nonce), bnToRlp(tx.gasPrice), @@ -161,7 +176,11 @@ export default class LedgerWallet extends HDWalletAbstract { Buffer.from([]), ]); - const signature = await this.ethApp.signTransaction(LEDGER_ETH_ACCOUNT_PATH, rawUnsignedTx.toString('hex')); + const ethApp = getAppEth(LedgerWallet.transport); + const signature = await ethApp.signTransaction( + getAccountPathEVM(this.accountIndex), + rawUnsignedTx.toString('hex') + ); const signatureBN = { v: new EthBN(signature.v, 16), @@ -229,8 +248,6 @@ export default class LedgerWallet extends HDWalletAbstract { let item = items[i]; let assetId = bintools.cb58Encode(item.getAssetID()); - // @ts-ignore - // if (assetId !== store.state.Assets.AVA_ASSET_ID) { if (assetId !== activeNetwork.avaxID) { isAvaxOnly = false; } @@ -299,8 +316,10 @@ export default class LedgerWallet extends HDWalletAbstract { let parseableTxs = ParseableAvmTxEnum; let { paths, isAvaxOnly } = await this.getTransactionPaths(unsignedTx, chainId); + if (!LedgerWallet.config) throw ERR_ConfigNotSet; + // If ledger doesnt support parsing, sign hash - let canLedgerParse = this.config.version >= '0.3.1'; + let canLedgerParse = LedgerWallet.config.version >= '0.3.1'; let isParsableType = txType in parseableTxs && isAvaxOnly; let signedTx; @@ -370,6 +389,8 @@ export default class LedgerWallet extends HDWalletAbstract { UnsignedTx extends AVMUnsignedTx | PlatformUnsignedTx | EVMUnsignedTx, SignedTx extends AVMTx | PlatformTx | EVMTx >(unsignedTx: UnsignedTx, paths: string[], chainId: ChainIdType): Promise { + // There must be an active transport connection + if (!LedgerWallet.transport) throw ERR_TransportNotSet; let tx = unsignedTx.getTransaction(); let txType = tx.getTxType(); let parseableTxs = { @@ -378,16 +399,17 @@ export default class LedgerWallet extends HDWalletAbstract { C: ParseableEvmTxEnum, }[chainId]; - let title = `Sign ${parseableTxs[txType]}`; - let bip32Paths = this.pathsToUniqueBipPaths(paths); + const appAvax = getAppAvax(LedgerWallet.transport); const accountPath = - chainId === 'C' ? bippath.fromString(`${ETH_ACCOUNT_PATH}`) : bippath.fromString(`${AVAX_ACCOUNT_PATH}`); + chainId === 'C' + ? bippath.fromString(`${ETH_ACCOUNT_PATH}`) + : bippath.fromString(getAccountPathAvalanche(this.accountIndex)); let txbuff = unsignedTx.toBuffer(); let changePath = this.getChangeBipPath(unsignedTx, chainId); - let ledgerSignedTx = await this.appAvax.signTransaction(accountPath, bip32Paths, txbuff, changePath); + let ledgerSignedTx = await appAvax.signTransaction(accountPath, bip32Paths, txbuff, changePath); let sigMap = ledgerSignedTx.signatures; let creds = this.getCredentials(unsignedTx, paths, sigMap, chainId); @@ -414,14 +436,18 @@ export default class LedgerWallet extends HDWalletAbstract { UnsignedTx extends AVMUnsignedTx | PlatformUnsignedTx | EVMUnsignedTx, SignedTx extends AVMTx | PlatformTx | EVMTx >(unsignedTx: UnsignedTx, paths: string[], chainId: ChainIdType): Promise { + if (!LedgerWallet.transport) throw ERR_TransportNotSet; let txbuff = unsignedTx.toBuffer(); const msg: Buffer = Buffer.from(createHash('sha256').update(txbuff).digest()); let bip32Paths = this.pathsToUniqueBipPaths(paths); + const appAvax = getAppAvax(LedgerWallet.transport); // Sign the msg with ledger - const accountPath = bippath.fromString(`${AVAX_ACCOUNT_PATH}`); - let sigMap = await this.appAvax.signHash(accountPath, bip32Paths, msg); + //TODO: Update when ledger supports Accounts + const accountPathSource = chainId === 'C' ? ETH_ACCOUNT_PATH : getAccountPathAvalanche(this.accountIndex); + const accountPath = bippath.fromString(accountPathSource); + let sigMap = await appAvax.signHash(accountPath, bip32Paths, msg); let creds: Credential[] = this.getCredentials(unsignedTx, paths, sigMap, chainId); @@ -557,14 +583,19 @@ export default class LedgerWallet extends HDWalletAbstract { } async signP(unsignedTx: PlatformUnsignedTx): Promise { + if (!LedgerWallet.transport) throw ERR_TransportNotSet; + let tx = unsignedTx.getTransaction(); let txType = tx.getTxType(); let chainId: ChainIdType = 'P'; let parseableTxs = ParseablePlatformEnum; let { paths, isAvaxOnly } = await this.getTransactionPaths(unsignedTx, chainId); + + if (!LedgerWallet.config) throw ERR_ConfigNotSet; + // If ledger doesnt support parsing, sign hash - let canLedgerParse = this.config.version >= '0.3.1'; + let canLedgerParse = LedgerWallet.config.version >= '0.3.1'; let isParsableType = txType in parseableTxs && isAvaxOnly; // TODO: Remove after ledger is fixed @@ -578,13 +609,33 @@ export default class LedgerWallet extends HDWalletAbstract { } } + // TODO: Remove after ledger update + // Ledger is not able to parse P/C atomic transactions + if (txType === PlatformVMConstants.EXPORTTX) { + const destChainBuff = (tx as PlatformExportTx).getDestinationChain(); + // If destination chain is C chain, sign hash + const destChain = idToChainAlias(bintools.cb58Encode(destChainBuff)); + if (destChain === 'C') { + canLedgerParse = false; + } + } + // TODO: Remove after ledger update + // Ledger is not able to parse P/C atomic transactions + if (txType === PlatformVMConstants.IMPORTTX) { + const sourceChainBuff = (tx as PlatformImportTx).getSourceChain(); + // If destination chain is C chain, sign hash + const sourceChain = idToChainAlias(bintools.cb58Encode(sourceChainBuff)); + if (sourceChain === 'C') { + canLedgerParse = false; + } + } + let signedTx; if (canLedgerParse && isParsableType) { signedTx = await this.signTransactionParsable(unsignedTx, paths, chainId); } else { signedTx = await this.signTransactionHash(unsignedTx, paths, chainId); } - // store.commit('Ledger/closeModal') return signedTx; } @@ -594,17 +645,44 @@ export default class LedgerWallet extends HDWalletAbstract { let tx = unsignedTx.getTransaction(); let typeId = tx.getTxType(); - let paths = ['0/0']; + let paths = [`0/${this.accountIndex}`]; if (typeId === EVMConstants.EXPORTTX) { let ins = (tx as EVMExportTx).getInputs(); - paths = ins.map(() => '0/0'); + paths = ins.map(() => `0/${this.accountIndex}`); } else if (typeId === EVMConstants.IMPORTTX) { let ins = (tx as EVMImportTx).getImportInputs(); - paths = ins.map(() => '0/0'); + paths = ins.map(() => `0/${this.accountIndex}`); + } + + let canLedgerParse = true; + + // TODO: Remove after ledger update + // Ledger is not able to parse P/C atomic transactions + if (typeId === EVMConstants.EXPORTTX) { + const destChainBuff = (tx as EVMExportTx).getDestinationChain(); + // If destination chain is C chain, sign hash + const destChain = idToChainAlias(bintools.cb58Encode(destChainBuff)); + if (destChain === 'P') { + canLedgerParse = false; + } + } + // TODO: Remove after ledger update + if (typeId === EVMConstants.IMPORTTX) { + const sourceChainBuff = (tx as EVMImportTx).getSourceChain(); + // If destination chain is C chain, sign hash + const sourceChain = idToChainAlias(bintools.cb58Encode(sourceChainBuff)); + if (sourceChain === 'P') { + canLedgerParse = false; + } + } + + let txSigned; + if (canLedgerParse) { + txSigned = (await this.signTransactionParsable(unsignedTx, paths, 'C')) as EVMTx; + } else { + txSigned = (await this.signTransactionHash(unsignedTx, paths, 'C')) as EVMTx; } - let txSigned = (await this.signTransactionParsable(unsignedTx, paths, 'C')) as EVMTx; - // store.commit('Ledger/closeModal') return txSigned; } } diff --git a/src/Wallet/Ledger/errors.ts b/src/Wallet/Ledger/errors.ts new file mode 100644 index 00000000..09963268 --- /dev/null +++ b/src/Wallet/Ledger/errors.ts @@ -0,0 +1,2 @@ +export const ERR_TransportNotSet = new Error('Transport is not set.'); +export const ERR_ConfigNotSet = new Error('Ledger configuration is not set.'); diff --git a/src/Wallet/Ledger/index.ts b/src/Wallet/Ledger/index.ts new file mode 100644 index 00000000..c6fe4404 --- /dev/null +++ b/src/Wallet/Ledger/index.ts @@ -0,0 +1,2 @@ +export * from './LedgerWallet'; +export * from './utils'; diff --git a/src/Wallet/Ledger/utils.ts b/src/Wallet/Ledger/utils.ts new file mode 100644 index 00000000..05880757 --- /dev/null +++ b/src/Wallet/Ledger/utils.ts @@ -0,0 +1,36 @@ +import * as bip32 from 'bip32'; +import Eth from '@ledgerhq/hw-app-eth'; +// @ts-ignore +import AppAvax from '@obsidiansystems/hw-app-avalanche'; +import { MIN_EVM_SUPPORT_V } from '@/Wallet/constants'; +import { ILedgerAppConfig } from '@/Wallet/types'; + +/** + * + * @param xpub Extended public key for m/44'/60'/0' + * @param index Index of the Eth address + * @returns Extended public key for m/44'/60'/0'/0/n where `n` is the address index + */ +export function getEthAddressKeyFromAccountKey(xpub: string, index: number) { + const node = bip32.fromBase58(xpub).derivePath(`0/${index}`); + return node.toBase58(); +} + +export function getAppAvax(transport: any): AppAvax { + return new AppAvax(transport, 'w0w'); +} + +export function getAppEth(transport: any): Eth { + return new Eth(transport, 'w0w'); +} + +export async function getLedgerConfigAvax(transport: any): Promise { + const app = getAppAvax(transport); + let config = await app.getAppConfiguration(); + + if (!config) { + throw new Error(`Unable to connect ledger. You must use ledger version ${MIN_EVM_SUPPORT_V} or above.`); + } + + return config; +} diff --git a/src/Wallet/MnemonicWallet.ts b/src/Wallet/MnemonicWallet.ts index d4ac9f5c..b9a21851 100644 --- a/src/Wallet/MnemonicWallet.ts +++ b/src/Wallet/MnemonicWallet.ts @@ -1,21 +1,22 @@ import * as bip39 from 'bip39'; import * as bip32 from 'bip32'; -import EvmWallet from './EvmWallet'; +import { EvmWallet } from './EvmWallet'; import { UnsafeWallet, WalletNameType } from './types'; import { Buffer } from 'avalanche'; -import { Transaction } from '@ethereumjs/tx'; +import { FeeMarketEIP1559Transaction, Transaction } from '@ethereumjs/tx'; import { Tx as AVMTx, UnsignedTx as AVMUnsignedTx } from 'avalanche/dist/apis/avm'; import { Tx as PlatformTx, UnsignedTx as PlatformUnsignedTx } from 'avalanche/dist/apis/platformvm'; import { KeyPair as AVMKeyPair, KeyChain as AVMKeyChain } from 'avalanche/dist/apis/avm/keychain'; import { KeyChain as PlatformKeyChain } from 'avalanche/dist/apis/platformvm'; import { UnsignedTx as EVMUnsignedTx, Tx as EVMTx, KeyPair as EVMKeyPair } from 'avalanche/dist/apis/evm'; -import { avalanche } from '@/Network/network'; import { digestMessage } from '@/utils'; import { HDWalletAbstract } from '@/Wallet/HDWalletAbstract'; import { bintools } from '@/common'; import { getAccountPathAvalanche, getAccountPathEVM } from '@/Wallet/helpers/derivationHelper'; +import { avalanche } from '@/Network/network'; -export default class MnemonicWallet extends HDWalletAbstract implements UnsafeWallet { +//TODO: Should extend public mnemonic wallet +export class MnemonicWallet extends HDWalletAbstract implements UnsafeWallet { evmWallet: EvmWallet; type: WalletNameType; mnemonic: string; @@ -46,17 +47,6 @@ export default class MnemonicWallet extends HDWalletAbstract implements UnsafeWa this.evmWallet = evmWallet; } - /** - * Gets the active address on the C chain in Bech32 encoding - * @return - * Bech32 representation of the EVM address. - */ - public getEvmAddressBech(): string { - let keypair = new EVMKeyPair(avalanche.getHRP(), 'C'); - let addr = keypair.addressFromPublicKey(Buffer.from(this.ethAccountKey.publicKey)); - return bintools.addressToString(avalanche.getHRP(), 'C', addr); - } - /** * Returns the derived private key used by the EVM wallet. */ @@ -88,11 +78,19 @@ export default class MnemonicWallet extends HDWalletAbstract implements UnsafeWa return new MnemonicWallet(mnemonic); } + /** + * Validates the given string is a valid mnemonic. + * @param mnemonic + */ + static validateMnemonic(mnemonic: string): boolean { + return bip39.validateMnemonic(mnemonic); + } + /** * Signs an EVM transaction on the C chain. * @param tx The unsigned transaction */ - async signEvm(tx: Transaction): Promise { + async signEvm(tx: Transaction | FeeMarketEIP1559Transaction): Promise { return this.evmWallet.signEVM(tx); } @@ -140,15 +138,6 @@ export default class MnemonicWallet extends HDWalletAbstract implements UnsafeWa return this.externalScan.getKeyChainP(); } - /** - * Gets the active address on the C chain - * @return - * Hex representation of the EVM address. - */ - public getAddressC(): string { - return this.evmWallet.getAddress(); - } - // TODO: Support internal address as well signMessage(msgStr: string, index: number): string { let key = this.externalScan.getKeyForIndexX(index) as AVMKeyPair; diff --git a/src/Wallet/PublicMnemonicWallet.ts b/src/Wallet/PublicMnemonicWallet.ts index a2d40784..227e8c12 100644 --- a/src/Wallet/PublicMnemonicWallet.ts +++ b/src/Wallet/PublicMnemonicWallet.ts @@ -4,38 +4,30 @@ import { UnsignedTx as PlatformUnsignedTx, Tx as PlatformTx } from 'avalanche/di import { UnsignedTx as AVMUnsignedTx, Tx as AVMTx } from 'avalanche/dist/apis/avm'; import { Transaction } from '@ethereumjs/tx'; import { WalletNameType } from '@/Wallet/types'; -import EvmWallet from '@/Wallet/EvmWallet'; -import EvmWalletReadonly from '@/Wallet/EvmWalletReadonly'; +import { EvmWallet } from '@/Wallet/EvmWallet'; +import { EvmWalletReadonly } from '@/Wallet/EvmWalletReadonly'; import * as bip32 from 'bip32'; import { importPublic } from 'ethereumjs-util'; +import { computePublicKey } from 'ethers/lib/utils'; -export default class PublicMnemonicWallet extends HDWalletAbstract { +export class PublicMnemonicWallet extends HDWalletAbstract { /** * - * @param xpubAVM of derivation path m/44'/9000'/0' - * @param xpubEVM of derivation path m/44'/60'/0' + * @param xpubAVM of derivation path m/44'/9000'/n' where `n` is the account index + * @param xpubEVM of derivation path m/44'/60'/0'/0/n where `n` is the account index */ constructor(xpubAVM: string, xpubEVM: string) { let avmAcct = bip32.fromBase58(xpubAVM); - let evmAcct = bip32.fromBase58(xpubEVM).derivePath('0/0'); + let evmAcct = bip32.fromBase58(xpubEVM); super(avmAcct); - this.type = 'xpub'; - - this.evmWallet = new EvmWalletReadonly(importPublic(evmAcct.publicKey)); + const uncompressedKey = computePublicKey(evmAcct.publicKey); + this.evmWallet = new EvmWalletReadonly(uncompressedKey); } evmWallet: EvmWallet | EvmWalletReadonly; type: WalletNameType; - getAddressC(): string { - return this.evmWallet.getAddress(); - } - - getEvmAddressBech(): string { - return this.evmWallet.getAddressBech32(); - } - //@ts-ignore signC(tx: EVMUnsignedTx): Promise { throw new Error('Not supported.'); diff --git a/src/Wallet/SingletonWallet.ts b/src/Wallet/SingletonWallet.ts index 7ca9fc9d..2274379d 100644 --- a/src/Wallet/SingletonWallet.ts +++ b/src/Wallet/SingletonWallet.ts @@ -9,12 +9,12 @@ import { } from 'avalanche/dist/apis/platformvm'; import { avalanche, pChain, xChain } from '@/Network/network'; import { Buffer as BufferAvalanche } from 'avalanche'; -import EvmWallet from '@/Wallet/EvmWallet'; +import { EvmWallet } from '@/Wallet/EvmWallet'; import { UnsignedTx, Tx, KeyPair as EVMKeyPair } from 'avalanche/dist/apis/evm'; -import { Transaction } from '@ethereumjs/tx'; +import { FeeMarketEIP1559Transaction, Transaction } from '@ethereumjs/tx'; import { bintools } from '@/common'; -export default class SingletonWallet extends WalletProvider implements UnsafeWallet { +export class SingletonWallet extends WalletProvider implements UnsafeWallet { type: WalletNameType = 'singleton'; key = ''; keyBuff: BufferAvalanche; @@ -68,10 +68,6 @@ export default class SingletonWallet extends WalletProvider implements UnsafeWal return this.evmWallet.getPrivateKeyHex(); } - getAddressC(): string { - return this.evmWallet.getAddress(); - } - getAddressP(): string { let keyChain = this.getKeyChainP(); return keyChain.getAddressStrings()[0]; @@ -102,12 +98,6 @@ export default class SingletonWallet extends WalletProvider implements UnsafeWal return this.getAddressX(); } - getEvmAddressBech(): string { - let keypair = new EVMKeyPair(avalanche.getHRP(), 'C'); - keypair.importKey(this.keyBuff); - return keypair.getAddressString(); - } - async getExternalAddressesP(): Promise { return [this.getAddressP()]; } @@ -136,7 +126,7 @@ export default class SingletonWallet extends WalletProvider implements UnsafeWal return this.evmWallet.signC(tx); } - async signEvm(tx: Transaction): Promise { + async signEvm(tx: Transaction | FeeMarketEIP1559Transaction): Promise { return this.evmWallet.signEVM(tx); } diff --git a/src/Wallet/Wallet.ts b/src/Wallet/Wallet.ts index 631f2144..2dbb090a 100644 --- a/src/Wallet/Wallet.ts +++ b/src/Wallet/Wallet.ts @@ -2,9 +2,10 @@ import { AssetBalanceP, AssetBalanceRawX, AssetBalanceX, - AvmExportChainType, - AvmImportChainType, ERC20Balance, + ExportChainsC, + ExportChainsP, + ExportChainsX, iAvaxBalance, WalletBalanceX, WalletEventArgsType, @@ -16,20 +17,23 @@ import { buildCreateNftFamilyTx, buildCustomEvmTx, buildEvmExportTransaction, + buildEvmTransferEIP1559Tx, buildEvmTransferErc20Tx, buildEvmTransferNativeTx, buildMintNftTx, + buildPlatformExportTransaction, estimateAvaxGas, estimateErc20Gas, } from '@/helpers/tx_helper'; import { BN, Buffer } from 'avalanche'; -import { Transaction } from '@ethereumjs/tx'; +import { FeeMarketEIP1559Transaction, Transaction } from '@ethereumjs/tx'; import { activeNetwork, avalanche, cChain, pChain, web3, xChain } from '@/Network/network'; -import EvmWallet from '@/Wallet/EvmWallet'; +import { EvmWallet } from '@/Wallet/EvmWallet'; import { avmGetAllUTXOs, avmGetAtomicUTXOs, + evmGetAtomicUTXOs, getStakeForAddresses, platformGetAllUTXOs, platformGetAtomicUTXOs, @@ -57,8 +61,8 @@ import { PayloadBase, UnixNow } from 'avalanche/dist/utils'; import { getAssetDescription } from '@/Asset/Assets'; import { getErc20Token } from '@/Asset/Erc20'; import { NO_NETWORK } from '@/errors'; -import { avaxCtoX, bnToLocaleString, waitTxC, waitTxEvm, waitTxP, waitTxX } from '@/utils'; -import EvmWalletReadonly from '@/Wallet/EvmWalletReadonly'; +import { avaxCtoX, bnToLocaleString, getTxFeeP, getTxFeeX, waitTxC, waitTxEvm, waitTxP, waitTxX } from '@/utils'; +import { EvmWalletReadonly } from '@/Wallet/EvmWalletReadonly'; import EventEmitter from 'events'; import { filterDuplicateTransactions, @@ -71,7 +75,6 @@ import { HistoryItemType, ITransactionData, } from '@/History'; -import moment from 'moment'; import { bintools } from '@/common'; import { ChainIdType } from '@/types'; import { @@ -82,11 +85,18 @@ import { getStepsForBalanceP, getStepsForBalanceX, UniversalTx, -} from '@/helpers/universal_tx_helper'; -import { UniversalNode } from '@/helpers/UniversalNode'; -import { GetStakeResponse } from 'avalanche/dist/common'; +} from '@/UniversalTx'; +import { UniversalNodeAbstract } from '@/UniversalTx/UniversalNode'; +import { GetStakeResponse } from 'avalanche/dist/apis/platformvm/interfaces'; import { networkEvents } from '@/Network/eventEmitter'; import { NetworkConfig } from '@/Network'; +import { chainIdFromAlias } from '@/Network/helpers/idFromAlias'; +import { + estimateExportGasFee, + estimateExportGasFeeFromMockTx, + estimateImportGasFeeFromMockTx, + getBaseFeeRecommended, +} from '@/helpers/gas_helper'; export abstract class WalletProvider { abstract type: WalletNameType; @@ -104,7 +114,7 @@ export abstract class WalletProvider { public balanceX: WalletBalanceX = {}; - abstract signEvm(tx: Transaction): Promise; + abstract signEvm(tx: Transaction | FeeMarketEIP1559Transaction): Promise; abstract signX(tx: AVMUnsignedTx): Promise; abstract signP(tx: PlatformUnsignedTx): Promise; abstract signC(tx: EVMUnsignedTx): Promise; @@ -112,8 +122,6 @@ export abstract class WalletProvider { abstract getAddressX(): string; abstract getChangeAddressX(): string; abstract getAddressP(): string; - abstract getAddressC(): string; - abstract getEvmAddressBech(): string; abstract getExternalAddressesX(): Promise; abstract getExternalAddressesXSync(): string[]; @@ -188,6 +196,18 @@ export abstract class WalletProvider { this.emit('balanceChangedC', this.getAvaxBalanceC()); } + /** + * Gets the active address on the C chain + * @return Hex representation of the EVM address. + */ + public getAddressC() { + return this.evmWallet.getAddress(); + } + + public getEvmAddressBech() { + return this.evmWallet.getAddressBech32(); + } + /** * * @param to - the address funds are being send to. @@ -223,7 +243,7 @@ export abstract class WalletProvider { } /** - * Sends AVAX to another address on the C chain. + * Sends AVAX to another address on the C chain using legacy transaction format. * @param to Hex address to send AVAX to. * @param amount Amount of AVAX to send, represented in WEI format. * @param gasPrice Gas price in WEI format @@ -344,8 +364,8 @@ export abstract class WalletProvider { * Scans all chains and take cross over fees into account * @param chainType X, P or C */ - public getUsableAvaxBalanceForChain(chainType: ChainIdType): BN { - return this.createUniversalNode(chainType).reduceTotalBalanceFromParents(); + public getUsableAvaxBalanceForChain(chainType: ChainIdType, atomicFeeXP: BN, atomicFeeC: BN): BN { + return this.createUniversalNode(chainType, atomicFeeXP, atomicFeeC).reduceTotalBalanceFromParents(); } /** @@ -353,18 +373,18 @@ export abstract class WalletProvider { * @param chain Chain of the universal node. * @private */ - private createUniversalNode(chain: ChainIdType): UniversalNode { + private createUniversalNode(chain: ChainIdType, atomicFeeXP: BN, atomicFeeC: BN): UniversalNodeAbstract { let xBal = this.getAvaxBalanceX().unlocked; let pBal = this.getAvaxBalanceP().unlocked; let cBal = avaxCtoX(this.getAvaxBalanceC()); // need to use 9 decimal places switch (chain) { case 'X': - return createGraphForX(xBal, pBal, cBal); + return createGraphForX(xBal, pBal, cBal, atomicFeeXP, atomicFeeC); case 'P': - return createGraphForP(xBal, pBal, cBal); + return createGraphForP(xBal, pBal, cBal, atomicFeeXP, atomicFeeC); case 'C': - return createGraphForC(xBal, pBal, cBal); + return createGraphForC(xBal, pBal, cBal, atomicFeeXP, atomicFeeC); } } @@ -373,9 +393,9 @@ export abstract class WalletProvider { * @param chain X/P/C * @param amount The amount to check against */ - public canHaveBalanceOnChain(chain: ChainIdType, amount: BN): boolean { + public canHaveBalanceOnChain(chain: ChainIdType, amount: BN, atomicFeeXP: BN, atomicFeeC: BN): boolean { // The maximum amount of AVAX we can have on this chain - let maxAmt = this.createUniversalNode(chain).reduceTotalBalanceFromParents(); + let maxAmt = this.createUniversalNode(chain, atomicFeeXP, atomicFeeC).reduceTotalBalanceFromParents(); return maxAmt.gte(amount); } @@ -384,18 +404,18 @@ export abstract class WalletProvider { * @param chain The chain (X/P/C) to have the desired amount on * @param amount The desired amount */ - public getTransactionsForBalance(chain: ChainIdType, amount: BN): UniversalTx[] { + public getTransactionsForBalance(chain: ChainIdType, amount: BN, atomicFeeXP: BN, atomicFeeC: BN): UniversalTx[] { let xBal = this.getAvaxBalanceX().unlocked; let pBal = this.getAvaxBalanceP().unlocked; let cBal = avaxCtoX(this.getAvaxBalanceC()); // need to use 9 decimal places switch (chain) { case 'P': - return getStepsForBalanceP(xBal, pBal, cBal, amount); + return getStepsForBalanceP(xBal, pBal, cBal, amount, atomicFeeXP, atomicFeeC); case 'C': - return getStepsForBalanceC(xBal, pBal, cBal, amount); + return getStepsForBalanceC(xBal, pBal, cBal, amount, atomicFeeXP, atomicFeeC); case 'X': - return getStepsForBalanceX(xBal, pBal, cBal, amount); + return getStepsForBalanceX(xBal, pBal, cBal, amount, atomicFeeXP, atomicFeeC); } } @@ -403,7 +423,7 @@ export abstract class WalletProvider { * Given a `Transaction`, it will sign and issue it to the network. * @param tx The unsigned transaction to issue. */ - async issueEvmTx(tx: Transaction): Promise { + async issueEvmTx(tx: Transaction | FeeMarketEIP1559Transaction): Promise { let signedTx = await this.signEvm(tx); let txHex = signedTx.serialize().toString('hex'); let hash = await web3.eth.sendSignedTransaction('0x' + txHex); @@ -670,24 +690,28 @@ export abstract class WalletProvider { /** * Exports AVAX from P chain to X chain * @remarks - * The export transaction will cover the Export + Import Fees + * The export fee is added automatically to the amount. Make sure the exported amount includes the import fee for the destination chain. * - * @param amt amount of nAVAX to transfer + * @param amt amount of nAVAX to transfer. Fees excluded. + * @param destinationChain Either `X` or `C` * @return returns the transaction id. */ - async exportPChain(amt: BN) { - let fee = xChain.getTxFee(); - let amtFee = amt.add(fee); - - let utxoSet = this.utxosP; - let destinationAddr = this.getAddressX(); - + async exportPChain(amt: BN, destinationChain: ExportChainsP) { let pChangeAddr = this.getAddressP(); let fromAddrs = await this.getAllAddressesP(); - let xId = xChain.getBlockchainID(); + const destinationAddr = destinationChain === 'X' ? this.getAddressX() : this.getEvmAddressBech(); - let exportTx = await pChain.buildExportTx(utxoSet, amtFee, xId, [destinationAddr], fromAddrs, [pChangeAddr]); + let utxoSet = this.utxosP; + + const exportTx = await buildPlatformExportTransaction( + utxoSet, + fromAddrs, + destinationAddr, + amt, + pChangeAddr, + destinationChain + ); let tx = await this.signP(exportTx); let txId = await pChain.issueTx(tx); @@ -698,25 +722,53 @@ export abstract class WalletProvider { return txId; } + /*** + * Estimates the required fee for a C chain export transaction + * @param destinationChain Either `X` or `P` + * @param baseFee Current base fee of the network, use a padded amount. + * @return BN C chain atomic export transaction fee in nAVAX. + */ + estimateAtomicFeeExportC(destinationChain: ExportChainsC, baseFee: BN): BN { + let destinationAddr = destinationChain === 'X' ? this.getAddressX() : this.getAddressP(); + const hexAddr = this.getAddressC(); + // The amount does not effect the fee that much + const amt = new BN(0); + const gas = estimateExportGasFeeFromMockTx(destinationChain, amt, hexAddr, destinationAddr); + return avaxCtoX(baseFee.mul(new BN(gas))); + } + /** * Exports AVAX from C chain to X chain * @remarks - * The export transaction will cover the Export + Import Fees + * Make sure the exported `amt` includes the import fee for the destination chain. * * @param amt amount of nAVAX to transfer + * @param destinationChain either `X` or `P` + * @param exportFee Export fee in nAVAX * @return returns the transaction id. */ - async exportCChain(amt: BN): Promise { - let fee = xChain.getTxFee(); - let amtFee = amt.add(fee); - + async exportCChain(amt: BN, destinationChain: ExportChainsC, exportFee?: BN): Promise { let hexAddr = this.getAddressC(); let bechAddr = this.getEvmAddressBech(); let fromAddresses = [hexAddr]; - let destinationAddr = this.getAddressX(); + let destinationAddr = destinationChain === 'X' ? this.getAddressX() : this.getAddressP(); + + // Calculate export fee if it's not given. + if (!exportFee) { + const gas = estimateExportGasFeeFromMockTx(destinationChain, amt, hexAddr, destinationAddr); + const baseFee = await getBaseFeeRecommended(); + exportFee = avaxCtoX(baseFee.mul(new BN(gas))); + } - let exportTx = await buildEvmExportTransaction(fromAddresses, destinationAddr, amtFee, bechAddr); + let exportTx = await buildEvmExportTransaction( + fromAddresses, + destinationAddr, + amt, + bechAddr, + destinationChain, + exportFee + ); let tx = await this.signC(exportTx); @@ -731,35 +783,26 @@ export abstract class WalletProvider { /** * Exports AVAX from X chain to either P or C chain * @remarks - * The export transaction will cover the Export + Import Fees + * The export fee will be added to the amount automatically. Make sure the exported amount has the import fee for the destination chain. * * @param amt amount of nAVAX to transfer * @param destinationChain Which chain to export to. * @return returns the transaction id. */ - async exportXChain(amt: BN, destinationChain: AvmExportChainType) { - let fee = xChain.getTxFee(); - let amtFee = amt.add(fee); - - let destinationAddr; - if (destinationChain === 'P') { - destinationAddr = this.getAddressP(); - } else { - // C Chain - destinationAddr = this.getEvmAddressBech(); - } + async exportXChain(amt: BN, destinationChain: ExportChainsX) { + let destinationAddr = destinationChain === 'P' ? this.getAddressP() : this.getEvmAddressBech(); let fromAddresses = await this.getAllAddressesX(); let changeAddress = this.getChangeAddressX(); let utxos = this.utxosX; - let exportTx = (await buildAvmExportTransaction( + let exportTx = await buildAvmExportTransaction( destinationChain, utxos, fromAddresses, destinationAddr, - amtFee, + amt, changeAddress - )) as AVMUnsignedTx; + ); let tx = await this.signX(exportTx); @@ -772,23 +815,28 @@ export abstract class WalletProvider { return txId; } - async getAtomicUTXOsX(chainID: AvmImportChainType) { + async getAtomicUTXOsX(sourceChain: ExportChainsX) { let addrs = await this.getAllAddressesX(); - let result = await avmGetAtomicUTXOs(addrs, chainID); + let result = await avmGetAtomicUTXOs(addrs, sourceChain); return result; } - async getAtomicUTXOsP(): Promise { + async getAtomicUTXOsP(sourceChain: ExportChainsP): Promise { let addrs = await this.getAllAddressesP(); - return await platformGetAtomicUTXOs(addrs); + return await platformGetAtomicUTXOs(addrs, sourceChain); + } + + async getAtomicUTXOsC(sourceChain: ExportChainsC) { + const bechAddr = this.getEvmAddressBech(); + return await evmGetAtomicUTXOs([bechAddr], sourceChain); } /** - * Imports atomic X chain utxos to the current actie X chain address - * @param chainID The chain ID to import from, either `P` or `C` + * Imports atomic X chain UTXOs to the current active X chain address + * @param sourceChain The chain to import from, either `P` or `C` */ - async importX(chainID: AvmImportChainType) { - const utxoSet = await this.getAtomicUTXOsX(chainID); + async importX(sourceChain: ExportChainsX) { + const utxoSet = await this.getAtomicUTXOsX(sourceChain); if (utxoSet.getAllUTXOs().length === 0) { throw new Error('Nothing to import.'); @@ -802,12 +850,7 @@ export abstract class WalletProvider { let fromAddrs = utxoAddrs; let ownerAddrs = utxoAddrs; - let sourceChainId; - if (chainID === 'P') { - sourceChainId = pChain.getBlockchainID(); - } else { - sourceChainId = cChain.getBlockchainID(); - } + const sourceChainId = chainIdFromAlias(sourceChain); // Owner addresses, the addresses we exported to const unsignedTx = await xChain.buildImportTx(utxoSet, ownerAddrs, sourceChainId, [xToAddr], fromAddrs, [ @@ -825,8 +868,13 @@ export abstract class WalletProvider { return txId; } - async importP(toAddress?: string): Promise { - const utxoSet = await this.getAtomicUTXOsP(); + /** + * Import utxos in atomic memory to the P chain. + * @param sourceChain Either `X` or `C` + * @param [toAddress] The destination P chain address assets will get imported to. Defaults to the P chain address of the wallet. + */ + async importP(sourceChain: ExportChainsP, toAddress?: string): Promise { + const utxoSet = await this.getAtomicUTXOsP(sourceChain); if (utxoSet.getAllUTXOs().length === 0) { throw new Error('Nothing to import.'); @@ -838,17 +886,18 @@ export abstract class WalletProvider { let hrp = avalanche.getHRP(); let utxoAddrs = utxoSet.getAddresses().map((addr) => bintools.addressToString(hrp, 'P', addr)); - // let fromAddrs = utxoAddrs; let ownerAddrs = utxoAddrs; if (!toAddress) { toAddress = walletAddrP; } + const sourceChainId = chainIdFromAlias(sourceChain); + const unsignedTx = await pChain.buildImportTx( utxoSet, ownerAddrs, - xChain.getBlockchainID(), + sourceChainId, [toAddress], ownerAddrs, [walletAddrP], @@ -865,22 +914,50 @@ export abstract class WalletProvider { return txId; } - async importC() { + /** + * + * @param sourceChain Which chain to import from. `X` or `P` + * @param [fee] The import fee to use in the transactions. If omitted the SDK will try to calculate the fee. For deterministic transactions you should always pre calculate and provide this value. + * @param [utxoSet] If omitted imports all atomic UTXOs. + */ + async importC(sourceChain: ExportChainsC, fee?: BN, utxoSet?: EVMUTXOSet) { let bechAddr = this.getEvmAddressBech(); - const utxoResponse = await cChain.getUTXOs(bechAddr, xChain.getBlockchainID()); - const utxoSet: EVMUTXOSet = utxoResponse.utxos; + if (!utxoSet) { + utxoSet = await this.getAtomicUTXOsC(sourceChain); + } - if (utxoSet.getAllUTXOs().length === 0) { + const utxos = utxoSet.getAllUTXOs(); + if (utxos.length === 0) { throw new Error('Nothing to import.'); } let toAddress = this.getAddressC(); let ownerAddresses = [bechAddr]; let fromAddresses = ownerAddresses; - let sourceChain = xChain.getBlockchainID(); + const sourceChainId = chainIdFromAlias(sourceChain); + + // Calculate fee if not provided + if (!fee) { + // Calculate number of signatures + const numSigs = utxos.reduce((acc, utxo) => { + return acc + utxo.getOutput().getAddresses().length; + }, 0); + const numIns = utxos.length; + + const importGas = estimateImportGasFeeFromMockTx(numIns, numSigs); + const baseFee = await getBaseFeeRecommended(); + fee = avaxCtoX(baseFee.mul(new BN(importGas))); + } - const unsignedTx = await cChain.buildImportTx(utxoSet, toAddress, ownerAddresses, sourceChain, fromAddresses); + const unsignedTx = await cChain.buildImportTx( + utxoSet, + toAddress, + ownerAddresses, + sourceChainId, + fromAddresses, + fee + ); let tx = await this.signC(unsignedTx); let id = await cChain.issueTx(tx); @@ -1065,25 +1142,29 @@ export abstract class WalletProvider { public async issueUniversalTx(tx: UniversalTx): Promise { switch (tx.action) { case 'export_x_c': - if (!tx.amount) throw new Error('Universal transaction must specify an amount.'); return await this.exportXChain(tx.amount, 'C'); case 'import_x_c': - return await this.importC(); + return await this.importC('X', tx.fee); case 'export_x_p': - if (!tx.amount) throw new Error('Universal transaction must specify an amount.'); return await this.exportXChain(tx.amount, 'P'); case 'import_x_p': - return await this.importP(); + return await this.importP('X'); case 'export_c_x': - if (!tx.amount) throw new Error('Universal transaction must specify an amount.'); - return await this.exportCChain(tx.amount); + return await this.exportCChain(tx.amount, 'X', tx.fee); case 'import_c_x': return await this.importX('C'); + case 'export_c_p': + return await this.exportCChain(tx.amount, 'P', tx.fee); + case 'import_c_p': + return await this.importP('C'); case 'export_p_x': - if (!tx.amount) throw new Error('Universal transaction must specify an amount.'); - return await this.exportPChain(tx.amount); + return await this.exportPChain(tx.amount, 'X'); case 'import_p_x': return await this.importX('P'); + case 'export_p_c': + return await this.exportPChain(tx.amount, 'C'); + case 'import_p_c': + return await this.importC('P', tx.fee); default: throw new Error('Method not supported.'); } @@ -1144,7 +1225,7 @@ export abstract class WalletProvider { // Sort and join X,P,C transactions let parsedAll = [...parsedXPC, ...parsedEVM]; - let txsSorted = parsedAll.sort((x, y) => (moment(x.timestamp).isBefore(moment(y.timestamp)) ? 1 : -1)); + let txsSorted = parsedAll.sort((x, y) => (x.timestamp.getTime() < y.timestamp.getTime() ? 1 : -1)); // If there is a limit only return that much if (limit > 0) { diff --git a/src/Wallet/index.ts b/src/Wallet/index.ts new file mode 100644 index 00000000..521294b2 --- /dev/null +++ b/src/Wallet/index.ts @@ -0,0 +1,10 @@ +export * from './Ledger'; +export * from './types'; +export * from './MnemonicWallet'; +export * from './SingletonWallet'; +export * from './PublicMnemonicWallet'; +export * from './constants'; +export * from './EvmWallet'; +export * from './EvmWalletReadonly'; +export * from './HdScanner'; +export * from './HDWalletAbstract'; diff --git a/src/Wallet/types.ts b/src/Wallet/types.ts index 74a64d1b..8aa36544 100644 --- a/src/Wallet/types.ts +++ b/src/Wallet/types.ts @@ -2,9 +2,9 @@ import { KeyPair as AVMKeyPair } from 'avalanche/dist/apis/avm'; import { BN } from 'avalanche'; -import MnemonicWallet from '@/Wallet/MnemonicWallet'; -import SingletonWallet from '@/Wallet/SingletonWallet'; -import LedgerWallet from '@/Wallet/LedgerWallet'; +import { MnemonicWallet } from '@/Wallet/MnemonicWallet'; +import { SingletonWallet } from '@/Wallet/SingletonWallet'; +import { LedgerWallet } from '@/Wallet/Ledger'; import { iAssetDescriptionClean } from '@/Asset/types'; @@ -13,8 +13,10 @@ export interface IIndexKeyCache { } export type ChainAlias = 'X' | 'P'; -export type AvmImportChainType = 'P' | 'C'; -export type AvmExportChainType = 'P' | 'C'; +export type ExportChainsX = 'P' | 'C'; +export type ExportChainsP = 'X' | 'C'; +export type ExportChainsC = 'X' | 'P'; + export type HdChainType = 'X' | 'P'; export type WalletNameType = 'mnemonic' | 'ledger' | 'singleton' | 'xpub'; diff --git a/src/helpers/UniversalNode.ts b/src/helpers/UniversalNode.ts deleted file mode 100644 index 7f924baa..00000000 --- a/src/helpers/UniversalNode.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { BN } from 'avalanche'; -import { ChainIdType } from '@/types'; -import { xChain } from '@/Network/network'; -import { UniversalTx, UniversalTxActionType } from '@/helpers/universal_tx_helper'; - -export class UniversalNode { - parents: UniversalNode[]; - child: UniversalNode | null; // can only have 1 child - balance: BN; - chain: ChainIdType; - constructor(balance: BN, chain: ChainIdType, parents: UniversalNode[] = [], child: UniversalNode | null = null) { - this.parents = parents; - this.child = child; - this.balance = balance; - this.chain = chain; - } - - // Sum of the node's balance + all balance of parents minus the transfer fees - reduceTotalBalanceFromParents(): BN { - // If there are no balance return balance of self - if (this.parents.length === 0) { - return this.balance; - } - - let fee = xChain.getTxFee(); - - let parentBals = this.parents.map((node) => { - // Subtract transfer fees from parent balance - // import + export - let parentBalance = node.reduceTotalBalanceFromParents(); - parentBalance = parentBalance.sub(fee).sub(fee); - let zero = new BN(0); - return BN.max(parentBalance, zero); - }); - - let tot = parentBals.reduce((prev, current) => { - return prev.add(current); - }, new BN(0)); - - return tot.add(this.balance); - } - - /** - * Returns the export action type from this node to its child - * @param to - */ - getExportMethod(to?: ChainIdType): UniversalTxActionType { - switch (this.chain) { - case 'X': - if (to === 'P') { - return 'export_x_p'; - } else { - return 'export_x_c'; - } - case 'C': - return 'export_c_x'; - case 'P': - return 'export_p_x'; - } - } - - /** - * Returns the import action type from this node to its child - * @param from Which chain are we importing from - */ - getImportMethod(from?: ChainIdType): UniversalTxActionType { - switch (this.chain) { - case 'X': - if (from === 'P') { - return 'import_p_x'; - } else { - return 'import_c_x'; - } - case 'C': - return 'import_x_c'; - case 'P': - return 'import_x_p'; - } - } - - buildExportTx(amount: BN): UniversalTx { - return { - action: this.getExportMethod(this.child?.chain), - amount: amount, - }; - } - - buildImportTx(from?: ChainIdType): UniversalTx { - return { - action: this.getImportMethod(from), - }; - } - - /*** - * Assumes there is enough balance on node tree - * Returns empty array even if transaction not possible! - * What steps to take to have the target balance on this node. - * @param target Amount of nAVAX needed on this node. - */ - getStepsForTargetBalance(target: BN): UniversalTx[] { - // If the node has enough balance no transaction needed - // If target is negative or zero no transaction needed - if (this.balance.gte(target) || target.lte(new BN(0))) { - return []; - } - - let fee = xChain.getTxFee(); - let feeImportExport = fee.add(fee); - - // If not enough balance and no parents - // return all the balance - if (this.balance.lt(target) && this.parents.length === 0) { - let tx = this.buildExportTx(this.balance.sub(feeImportExport)); - return [tx]; - } - - // If not enough balance - - // Amount needed to collect from parents - let remaining = target.sub(this.balance); - - // Amount the parent must have - - if (this.parents.length === 1) { - // Export from parent to this node - let parent = this.parents[0]; - let parentBalanceNeeded = remaining.add(feeImportExport); - let txs = parent.getStepsForTargetBalance(parentBalanceNeeded); - let tx = parent.buildExportTx(remaining); - let importTx = this.buildImportTx(parent.chain); - return [...txs, tx, importTx]; - } else { - let transactions = []; - for (let i = 0; i < this.parents.length; i++) { - let p = this.parents[i]; - let pBal = p.reduceTotalBalanceFromParents(); - let pBalMax = pBal.sub(feeImportExport); - let parentBalanceNeeded = remaining.add(feeImportExport); - - let exportAmt = BN.min(pBalMax, remaining); // The amount that will cross to the target chain - let target = BN.min(pBalMax, parentBalanceNeeded); - - if (exportAmt.lte(new BN(0))) continue; - - let pTxs = p.getStepsForTargetBalance(target); - let pTx = p.buildExportTx(exportAmt); - let importTx = this.buildImportTx(p.chain); - transactions.push(...pTxs); - transactions.push(pTx); - transactions.push(importTx); - - remaining = remaining.sub(exportAmt); - } - - // If we still have remaining balance, we can not complete this transfer - if (remaining.gt(new BN(0))) { - throw new Error('Insufficient AVAX balances.'); - } - - return transactions; - } - } - - addParent(node: UniversalNode) { - this.parents.push(node); - } - - setChild(node: UniversalNode) { - this.child = node; - } -} diff --git a/src/helpers/gas_helper.ts b/src/helpers/gas_helper.ts index fbd4f1a7..c987f61a 100644 --- a/src/helpers/gas_helper.ts +++ b/src/helpers/gas_helper.ts @@ -1,5 +1,11 @@ -import { web3 } from '@/Network/network'; +import { activeNetwork, cChain, web3 } from '@/Network/network'; import { BN } from 'avalanche'; +import { EVMInput, ExportTx, SECPTransferOutput, TransferableOutput, UnsignedTx } from 'avalanche/dist/apis/evm'; +import { ExportChainsC } from '@/Wallet/types'; +import { bintools } from '@/common'; +import { chainIdFromAlias } from '@/Network'; +import { costExportTx, costImportTx } from 'avalanche/dist/utils'; +import { buildEvmExportTransaction } from '@/helpers/tx_helper'; const MAX_GAS = new BN(1000_000_000_000); @@ -15,7 +21,128 @@ export async function getGasPrice(): Promise { */ export async function getAdjustedGasPrice(): Promise { let gasPrice = await getGasPrice(); - let additionalGas = gasPrice.div(new BN(100)).mul(new BN(25)); - let adjustedGas = gasPrice.add(additionalGas); + let adjustedGas = adjustValue(gasPrice, 25); return BN.min(adjustedGas, MAX_GAS); } + +/** + * + * @param val + * @param perc What percentage to adjust with + */ +export function adjustValue(val: BN, perc: number) { + let padAmt = val.div(new BN(100)).mul(new BN(perc)); + return val.add(padAmt); +} + +/** + * Returns the base fee from the network. + */ +export async function getBaseFee(): Promise { + const rawHex = (await cChain.getBaseFee()).substring(2); + return new BN(rawHex, 'hex'); +} + +/** + * Returns the current base fee + 25% + */ +export async function getBaseFeeRecommended() { + const baseFee = await getBaseFee(); + return adjustValue(baseFee, 25); +} + +/** + * Returns the base max priority fee from the network. + */ +export async function getMaxPriorityFee(): Promise { + const rawHex = (await cChain.getMaxPriorityFeePerGas()).substring(2); + return new BN(rawHex, 'hex'); +} + +/** + * Calculate max fee for EIP 1559 transactions given baseFee and maxPriorityFee. + * According to https://www.blocknative.com/blog/eip-1559-fees + * @param baseFee in WEI + * @param maxPriorityFee in WEI + */ +export function calculateMaxFee(baseFee: BN, maxPriorityFee: BN): BN { + return baseFee.mul(new BN(2)).add(maxPriorityFee); +} + +/** + * Creates a mock import transaction and estimates the gas required for it. Returns fee in units of gas. + * @param numIns Number of inputs for the import transaction. + * @param numSigs Number of signatures used in the import transactions. This value is the sum of owner addresses in every UTXO. + */ +export function estimateImportGasFeeFromMockTx( + numIns = 1, + numSigs: number // number of signatures (sum of owner addresses in each utxo) +): number { + const ATOMIC_TX_COST = 10000; // in gas + const SIG_COST = 1000; // in gas + const BASE_TX_SIZE = 78; + const SINGLE_OWNER_INPUT_SIZE = 90; // in bytes + const OUTPUT_SIZE = 60; // in bytes + + // C chain imports consolidate inputs to one output + const numOutputs = 1; + // Assuming each input has 1 owner + const baseSize = BASE_TX_SIZE + numIns * SINGLE_OWNER_INPUT_SIZE + numOutputs * OUTPUT_SIZE; + const importGas = baseSize + numSigs * SIG_COST + ATOMIC_TX_COST; + + return importGas; +} + +/** + * Estimates the gas fee using a mock ExportTx built from the passed values. + * @param destinationChain `X` or `P` + * @param amount in nAVAX + * @param from The C chain hex address exported from + * @param to The destination X or P address + */ +export function estimateExportGasFeeFromMockTx( + destinationChain: ExportChainsC, + amount: BN, + from: string, + to: string +): number { + const destChainId = chainIdFromAlias(destinationChain); + const destChainIdBuff = bintools.cb58Decode(destChainId); + const toBuff = bintools.stringToAddress(to); + const netID = activeNetwork.networkID; + const chainID = activeNetwork.cChainID; + const AVAX_ID = activeNetwork.avaxID; + const avaxIDBuff = bintools.cb58Decode(AVAX_ID); + + const txIn = new EVMInput(from, amount, avaxIDBuff); + const secpOut = new SECPTransferOutput(amount, [toBuff]); + const txOut = new TransferableOutput(avaxIDBuff, secpOut); + + // Create fake export Tx + const chainIdBuff = bintools.cb58Decode(chainID); + const exportTx = new ExportTx(netID, chainIdBuff, destChainIdBuff, [txIn], [txOut]); + + const unisgnedTx = new UnsignedTx(exportTx); + + return costExportTx(unisgnedTx); +} + +/** + * Returns the estimated gas for the export transaction. + * @param destinationChain Either `X` or `P` + * @param amount The amount to export. In nAVAX. + * @param from The C chain hex address exporting the asset + * @param fromBech The C chain bech32 address exporting the asset + * @param to The destination address on the destination chain + */ +export async function estimateExportGasFee( + destinationChain: ExportChainsC, + from: string, + fromBech: string, + to: string, + amount: BN +): Promise { + let exportTx = await buildEvmExportTransaction([from], to, amount, fromBech, destinationChain, new BN(0)); + + return costExportTx(exportTx); +} diff --git a/src/helpers/index.ts b/src/helpers/index.ts index 38f90658..30a93142 100644 --- a/src/helpers/index.ts +++ b/src/helpers/index.ts @@ -1,7 +1,5 @@ export * as AddressHelper from './address_helper'; export * as TxHelper from './tx_helper'; export * as UtxoHelper from './utxo_helper'; -export * as UniversalHelper from './universal_tx_helper'; export * as NetworkHelper from './network_helper'; export * as GasHelper from './gas_helper'; -export * from './UniversalNode'; diff --git a/src/helpers/tx_helper.ts b/src/helpers/tx_helper.ts index 112f7533..8bf8a725 100644 --- a/src/helpers/tx_helper.ts +++ b/src/helpers/tx_helper.ts @@ -1,30 +1,31 @@ -import { xChain, cChain, pChain, web3 } from '@/Network/network'; +import { cChain, pChain, web3, xChain } from '@/Network/network'; -// import { ITransaction } from '@/components/wallet/transfer/types'; import { BN, Buffer } from 'avalanche'; import { + AVMConstants, MinterSet, NFTMintOutput, UnsignedTx as AVMUnsignedTx, UTXO as AVMUTXO, - UTXOSet, UTXOSet as AVMUTXOSet, - AVMConstants, + UTXOSet, } from 'avalanche/dist/apis/avm'; import { PayloadBase } from 'avalanche/dist/utils'; import { OutputOwners } from 'avalanche/dist/common'; -import { UTXOSet as PlatformUTXOSet, PlatformVMConstants } from 'avalanche/dist/apis/platformvm'; +import { PlatformVMConstants, UTXOSet as PlatformUTXOSet } from 'avalanche/dist/apis/platformvm'; import { EVMConstants } from 'avalanche/dist/apis/evm'; -import { AvmExportChainType } from '../Wallet/types'; -import { Transaction } from '@ethereumjs/tx'; +import { FeeMarketEIP1559Transaction, Transaction } from '@ethereumjs/tx'; import EthereumjsCommon from '@ethereumjs/common'; +import Common, { Chain } from '@ethereumjs/common'; import ERC20Abi from '@openzeppelin/contracts/build/contracts/ERC20.json'; import ERC721Abi from '@openzeppelin/contracts/build/contracts/ERC721.json'; import { bintools } from '@/common'; +import { ExportChainsC, ExportChainsP, ExportChainsX } from '@/Wallet/types'; +import { chainIdFromAlias } from '@/Network/helpers/idFromAlias'; export async function buildCreateNftFamilyTx( name: string, @@ -92,22 +93,14 @@ export async function buildMintNftTx( } export async function buildAvmExportTransaction( - destinationChain: AvmExportChainType, + destinationChain: ExportChainsX, utxoSet: AVMUTXOSet, fromAddresses: string[], toAddress: string, amount: BN, // export amount + fee sourceChangeAddress: string ) { - let destinationChainId; - switch (destinationChain) { - case 'P': - destinationChainId = pChain.getBlockchainID(); - break; - case 'C': - destinationChainId = cChain.getBlockchainID(); - break; - } + let destinationChainId = chainIdFromAlias(destinationChain); return await xChain.buildExportTx(utxoSet as AVMUTXOSet, amount, destinationChainId, [toAddress], fromAddresses, [ sourceChangeAddress, @@ -119,22 +112,34 @@ export async function buildPlatformExportTransaction( fromAddresses: string[], toAddress: string, amount: BN, // export amount + fee - sourceChangeAddress: string + sourceChangeAddress: string, + destinationChain: ExportChainsP ) { - let destinationChainId = xChain.getBlockchainID(); + let destinationChainId = chainIdFromAlias(destinationChain); return await pChain.buildExportTx(utxoSet, amount, destinationChainId, [toAddress], fromAddresses, [ sourceChangeAddress, ]); } +/** + * + * @param fromAddresses + * @param toAddress + * @param amount + * @param fromAddressBech + * @param destinationChain Either `X` or `P` + * @param fee Export fee in nAVAX + */ export async function buildEvmExportTransaction( fromAddresses: string[], toAddress: string, amount: BN, // export amount + fee - fromAddressBech: string + fromAddressBech: string, + destinationChain: ExportChainsC, + fee: BN ) { - let destinationChainId = xChain.getBlockchainID(); + let destinationChainId = chainIdFromAlias(destinationChain); const nonce = await web3.eth.getTransactionCount(fromAddresses[0]); const avaxAssetIDBuf: Buffer = await xChain.getAVAXAssetID(); @@ -149,8 +154,40 @@ export async function buildEvmExportTransaction( fromAddressHex, fromAddressBech, [toAddress], - nonce + nonce, + undefined, + undefined, + fee + ); +} + +export async function buildEvmTransferEIP1559Tx( + from: string, + to: string, + amount: BN, // in wei + priorityFee: BN, + maxFee: BN, + gasLimit: number +) { + const nonce = await web3.eth.getTransactionCount(from); + const chainId = await web3.eth.getChainId(); + const networkId = await web3.eth.net.getId(); + + const common = Common.custom({ networkId, chainId }); + + const tx = FeeMarketEIP1559Transaction.fromTxData( + { + nonce: nonce, + maxFeePerGas: '0x' + maxFee.toString('hex'), + maxPriorityFeePerGas: '0x' + priorityFee.toString('hex'), + gasLimit: gasLimit, + to: to, + value: '0x' + amount.toString('hex'), + data: '0x', + }, + { common } ); + return tx; } export async function buildEvmTransferNativeTx( @@ -163,9 +200,8 @@ export async function buildEvmTransferNativeTx( const nonce = await web3.eth.getTransactionCount(from); const chainId = await web3.eth.getChainId(); const networkId = await web3.eth.net.getId(); - const chainParams = { - common: EthereumjsCommon.forCustomChain('mainnet', { networkId, chainId }, 'istanbul'), - }; + + const common = Common.custom({ networkId, chainId }); const tx = Transaction.fromTxData( { @@ -176,7 +212,7 @@ export async function buildEvmTransferNativeTx( value: '0x' + amount.toString('hex'), data: '0x', }, - chainParams + { common } ); return tx; } diff --git a/src/helpers/universal_tx_helper.ts b/src/helpers/universal_tx_helper.ts deleted file mode 100644 index 2c177caa..00000000 --- a/src/helpers/universal_tx_helper.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { BN } from 'avalanche'; -import { UniversalNode } from '@/helpers/UniversalNode'; - -type UniversalTxActionTypesX = 'send_x' | 'export_x_c' | 'export_x_p' | 'import_p_x' | 'import_c_x'; -type UniversalTxActionTypesC = 'send_c' | 'export_c_x' | 'import_x_c'; -type UniversalTxActionTypesP = 'export_p_x' | 'import_x_p'; - -export type UniversalTxActionType = UniversalTxActionTypesX | UniversalTxActionTypesC | UniversalTxActionTypesP; - -export interface UniversalTx { - action: UniversalTxActionType; - amount?: BN; -} - -export function createGraphForP(balX: BN, balP: BN, balC: BN): UniversalNode { - let xNode = new UniversalNode(balX, 'X'); - let pNode = new UniversalNode(balP, 'P'); - let cNode = new UniversalNode(balC, 'C'); - - pNode.addParent(xNode); - xNode.addParent(cNode); - - cNode.setChild(xNode); - xNode.setChild(pNode); - return pNode; -} - -export function createGraphForC(balX: BN, balP: BN, balC: BN): UniversalNode { - let xNode = new UniversalNode(balX, 'X'); - let pNode = new UniversalNode(balP, 'P'); - let cNode = new UniversalNode(balC, 'C'); - - cNode.addParent(xNode); - xNode.addParent(pNode); - - pNode.setChild(xNode); - xNode.setChild(cNode); - - return cNode; -} - -export function createGraphForX(balX: BN, balP: BN, balC: BN): UniversalNode { - let xNode = new UniversalNode(balX, 'X'); - let pNode = new UniversalNode(balP, 'P'); - let cNode = new UniversalNode(balC, 'C'); - - xNode.addParent(pNode); - xNode.addParent(cNode); - - cNode.setChild(xNode); - pNode.setChild(xNode); - - return xNode; -} - -export function canHaveBalanceOnX(balX: BN, balP: BN, balC: BN, targetAmount: BN): boolean { - let startNode = createGraphForX(balX, balP, balC); - return startNode.reduceTotalBalanceFromParents().gte(targetAmount); -} - -export function canHaveBalanceOnP(balX: BN, balP: BN, balC: BN, targetAmount: BN): boolean { - let startNode = createGraphForP(balX, balP, balC); - return startNode.reduceTotalBalanceFromParents().gte(targetAmount); -} - -/** - * Will return true if `targetAmount` can exist on C chain - */ -export function canHaveBalanceOnC(balX: BN, balP: BN, balC: BN, targetAmount: BN): boolean { - let startNode = createGraphForC(balX, balP, balC); - return startNode.reduceTotalBalanceFromParents().gte(targetAmount); -} - -export function getStepsForBalanceP(balX: BN, balP: BN, balC: BN, targetAmount: BN): UniversalTx[] { - let startNode = createGraphForP(balX, balP, balC); - - if (startNode.reduceTotalBalanceFromParents().lt(targetAmount)) { - throw new Error('Insufficient AVAX.'); - } - - return startNode.getStepsForTargetBalance(targetAmount); -} - -export function getStepsForBalanceC(balX: BN, balP: BN, balC: BN, targetAmount: BN): UniversalTx[] { - let startNode = createGraphForC(balX, balP, balC); - - if (startNode.reduceTotalBalanceFromParents().lt(targetAmount)) { - throw new Error('Insufficient AVAX.'); - } - - return startNode.getStepsForTargetBalance(targetAmount); -} - -export function getStepsForBalanceX(balX: BN, balP: BN, balC: BN, targetAmount: BN): UniversalTx[] { - let startNode = createGraphForX(balX, balP, balC); - - if (startNode.reduceTotalBalanceFromParents().lt(targetAmount)) { - throw new Error('Insufficient AVAX.'); - } - - return startNode.getStepsForTargetBalance(targetAmount); -} diff --git a/src/helpers/utxo_helper.ts b/src/helpers/utxo_helper.ts index 5cbe8382..be1d8101 100644 --- a/src/helpers/utxo_helper.ts +++ b/src/helpers/utxo_helper.ts @@ -2,54 +2,50 @@ import { UTXOSet as AVMUTXOSet } from 'avalanche/dist/apis/avm/utxos'; import { UTXOSet as PlatformUTXOSet } from 'avalanche/dist/apis/platformvm/utxos'; import { UTXOSet as EVMUTXOSet } from 'avalanche/dist/apis/evm/utxos'; import { xChain, cChain, pChain } from '@/Network/network'; -import { AvmImportChainType } from '@/Wallet/types'; -import { GetStakeResponse } from 'avalanche/dist/common'; +import { ExportChainsC, ExportChainsP, ExportChainsX } from '@/Wallet/types'; +import { chainIdFromAlias } from '@/Network/helpers/idFromAlias'; +import { GetStakeResponse } from 'avalanche/dist/apis/platformvm/interfaces'; /** * * @param addrs an array of X chain addresses to get the atomic utxos of - * @param chainID Which chain to check agains, either `P` or `C` + * @param sourceChain Which chain to check against, either `P` or `C` */ -export async function avmGetAtomicUTXOs(addrs: string[], chainID: AvmImportChainType): Promise { +export async function avmGetAtomicUTXOs(addrs: string[], sourceChain: ExportChainsX): Promise { const selection = addrs.slice(0, 1024); const remaining = addrs.slice(1024); - let utxoSet; - if (chainID === 'P') { - utxoSet = (await xChain.getUTXOs(selection, pChain.getBlockchainID())).utxos; - } else { - utxoSet = (await xChain.getUTXOs(selection, cChain.getBlockchainID())).utxos; - } + const sourceChainId = chainIdFromAlias(sourceChain); + let utxoSet = (await xChain.getUTXOs(selection, sourceChainId)).utxos; if (remaining.length > 0) { - const nextSet = await avmGetAtomicUTXOs(remaining, chainID); + const nextSet = await avmGetAtomicUTXOs(remaining, sourceChain); utxoSet = utxoSet.merge(nextSet); } return utxoSet; } // todo: Use end index to get ALL utxos -export async function platformGetAtomicUTXOs(addrs: string[]): Promise { +export async function platformGetAtomicUTXOs(addrs: string[], sourceChain: ExportChainsP): Promise { let selection = addrs.slice(0, 1024); let remaining = addrs.slice(1024); + const sourceChainId = chainIdFromAlias(sourceChain); - let utxoSet = (await pChain.getUTXOs(selection, xChain.getBlockchainID())).utxos; + let utxoSet = (await pChain.getUTXOs(selection, sourceChainId)).utxos; if (remaining.length > 0) { - // @ts-ignore - let nextSet = await platformGetAtomicUTXOs(remaining); - // @ts-ignore + let nextSet = await platformGetAtomicUTXOs(remaining, sourceChain); utxoSet = utxoSet.merge(nextSet); } return utxoSet; } // todo: Use end index to get ALL utxos -export async function evmGetAtomicUTXOs(addrs: string[]): Promise { +export async function evmGetAtomicUTXOs(addrs: string[], sourceChain: ExportChainsC): Promise { if (addrs.length > 1024) { throw new Error('Number of addresses can not be greater than 1024.'); } - - let result: EVMUTXOSet = (await cChain.getUTXOs(addrs, xChain.getBlockchainID())).utxos; + const sourceChainId = chainIdFromAlias(sourceChain); + let result: EVMUTXOSet = (await cChain.getUTXOs(addrs, sourceChainId)).utxos; return result; } diff --git a/src/index.ts b/src/index.ts index c7267233..86bea71f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,21 +3,16 @@ export * as Assets from '@/Asset'; export * as Common from './common'; export * as History from '@/History'; -import MnemonicWallet from '@/Wallet/MnemonicWallet'; -import SingletonWallet from '@/Wallet/SingletonWallet'; -import LedgerWallet from '@/Wallet/LedgerWallet'; -import PublicMnemonicWallet from '@/Wallet/PublicMnemonicWallet'; - -// Type Exports -export * from '@/Wallet/types'; export * from './types'; +export * from './Wallet'; import * as NetworkConstants from '@/Network/constants'; import * as Utils from '@/utils'; import Keystore from '@/Keystore/keystore'; export { BN } from 'avalanche'; -export { Big } from 'big.js'; +import Big from 'big.js'; export * from '@/helpers'; +export * from '@/UniversalTx'; -export { MnemonicWallet, SingletonWallet, NetworkConstants, Utils, Keystore, LedgerWallet, PublicMnemonicWallet }; +export { NetworkConstants, Utils, Keystore, Big }; diff --git a/src/utils/fee_utils.ts b/src/utils/fee_utils.ts index 9ac277ba..d06ee26c 100644 --- a/src/utils/fee_utils.ts +++ b/src/utils/fee_utils.ts @@ -1,15 +1,16 @@ import { pChain, xChain } from '@/Network/network'; +import { BN } from 'avalanche'; /** * Returns the transaction fee for X chain. */ -export function getTxFeeX() { +export function getTxFeeX(): BN { return xChain.getTxFee(); } /** * Returns the transaction fee for P chain. */ -export function getTxFeeP() { +export function getTxFeeP(): BN { return pChain.getTxFee(); } diff --git a/src/utils/number_utils.ts b/src/utils/number_utils.ts index 656dcc68..d2c11cd6 100644 --- a/src/utils/number_utils.ts +++ b/src/utils/number_utils.ts @@ -8,7 +8,7 @@ declare module 'big.js' { } Big.prototype.toLocaleString = function (toFixed: number = 9) { - let fixedStr = this.toFixed(toFixed); + let fixedStr = this.toFixed(toFixed, 0); let split = fixedStr.split('.'); let wholeStr = parseInt(split[0]).toLocaleString('en-US'); @@ -35,7 +35,8 @@ Big.prototype.toLocaleString = function (toFixed: number = 9) { * @param denomination number of decimal places to parse with */ export function bnToBig(val: BN, denomination = 0): Big { - return new Big(val.toString()).div(Math.pow(10, denomination)); + let mult = Big(10).pow(denomination); + return new Big(val.toString()).div(mult); } /** @@ -182,6 +183,15 @@ export function stringToBN(value: string, decimals: number) { let big = Big(value); let tens = Big(10).pow(decimals); let mult = big.times(tens); - let rawStr = mult.toFixed(0); + let rawStr = mult.toFixed(0, 0); return new BN(rawStr); } + +export function bigToBN(val: Big, denom: number): BN { + let denomFlr = Math.floor(denom); + if (denomFlr < 0) throw new Error('Denomination can not be less that 0.'); + + const bnBig = val.mul(Big(10).pow(denomFlr)); + const bnStr = bnBig.toFixed(0, 0); + return new BN(bnStr); +} diff --git a/test/UniversalTx/universal_tx_helper.test.ts b/test/UniversalTx/universal_tx_helper.test.ts new file mode 100644 index 00000000..7192b890 --- /dev/null +++ b/test/UniversalTx/universal_tx_helper.test.ts @@ -0,0 +1,692 @@ +import { createGraphForC, createGraphForP, createGraphForX, UniversalTx } from '@/UniversalTx'; +import { BN } from 'avalanche'; +import { pChain, xChain } from '@/Network/network'; + +jest.mock('@/Network/network', () => { + return { + web3: { + utils: { + isAddress: jest.fn().mockReturnValue(true), + }, + }, + pChain: { + getTxFee: jest.fn(), + }, + xChain: { + getTxFee: jest.fn(), + }, + }; +}); + +// Assume constant import export fee for all chains +const FEE_XP = new BN(1_000_000); +const FEE_C = new BN(100_000); + +function compareSteps(steps: UniversalTx[], expected: UniversalTx[]) { + expect(steps.length).toEqual(expected.length); + + for (let i = 0; i < steps.length; i++) { + let step = steps[i]; + let exp = expected[i]; + expect(step).toEqual(exp); + } +} + +describe('Reduce parent balance of UniversalNode P', () => { + beforeEach(() => { + (pChain.getTxFee as jest.Mock).mockReturnValue(FEE_XP); + (xChain.getTxFee as jest.Mock).mockReturnValue(FEE_XP); + }); + + it('all parents have balance of 1 AVAX', () => { + let balX = new BN(1000000000); + let balP = new BN(1000000000); + let balC = new BN(1000000000); + + let expected = balP.add(balX.sub(FEE_XP.add(FEE_XP)).add(balC.sub(FEE_C.add(FEE_XP)))); + let startNode = createGraphForP(balX, balP, balC, FEE_XP, FEE_C); + let tot = startNode.reduceTotalBalanceFromParents(); + expect(tot).toEqual(expected); + }); + + it('Only self and parent C has balance', () => { + let balP = new BN(1000000000); + let balX = new BN(0); + let balC = new BN(1000000000); + + let expected = balP.add(balC.sub(FEE_C).sub(FEE_XP)); + let startNode = createGraphForP(balX, balP, balC, FEE_XP, FEE_C); + let tot = startNode.reduceTotalBalanceFromParents(); + expect(tot).toEqual(expected); + }); + + it('only parent C has balance', () => { + let balP = new BN(0); + let balX = new BN(0); + let balC = new BN(1000000000); + + let expected = balC.sub(FEE_XP).sub(FEE_C); + let startNode = createGraphForP(balX, balP, balC, FEE_XP, FEE_C); + let tot = startNode.reduceTotalBalanceFromParents(); + expect(tot).toEqual(expected); + }); + + it('starting node has balance', () => { + let balP = new BN(1000000000); + let balX = new BN(0); + let balC = new BN(0); + + let expected = balP; + let startNode = createGraphForP(balX, balP, balC, FEE_XP, FEE_C); + let tot = startNode.reduceTotalBalanceFromParents(); + expect(tot).toEqual(expected); + }); +}); + +describe('Reduce parent balance of UniversalNode X', () => { + beforeEach(() => { + (pChain.getTxFee as jest.Mock).mockReturnValue(FEE_XP); + (xChain.getTxFee as jest.Mock).mockReturnValue(FEE_XP); + }); + + it('all nodes have balance of 1 AVAX', () => { + let balX = new BN(1000000000); + let balP = new BN(1000000000); + let balC = new BN(1000000000); + + let expected = balX.add(balP.sub(FEE_XP).sub(FEE_XP)).add(balC.sub(FEE_C).sub(FEE_XP)); + let startNode = createGraphForX(balX, balP, balC, FEE_XP, FEE_C); + let tot = startNode.reduceTotalBalanceFromParents(); + expect(tot).toEqual(expected); + }); + + it('both parents have balance of 1 AVAX', () => { + let balX = new BN(0); + let balP = new BN(1000000000); + let balC = new BN(1000000000); + + let expected = balP.sub(FEE_XP).sub(FEE_XP).add(balC.sub(FEE_C).sub(FEE_XP)); + let startNode = createGraphForX(balX, balP, balC, FEE_XP, FEE_C); + let tot = startNode.reduceTotalBalanceFromParents(); + expect(tot).toEqual(expected); + }); + + it('parent P has balance of 1 AVAX', () => { + let balX = new BN(0); + let balP = new BN(1000000000); + let balC = new BN(0); + + let expected = balP.sub(FEE_XP).sub(FEE_XP); + let startNode = createGraphForX(balX, balP, balC, FEE_XP, FEE_C); + let tot = startNode.reduceTotalBalanceFromParents(); + expect(tot).toEqual(expected); + }); + + it('parent C has balance of 1 AVAX', () => { + let balX = new BN(0); + let balP = new BN(0); + let balC = new BN(1000000000); + + let expected = balC.sub(FEE_C).sub(FEE_XP); + let startNode = createGraphForX(balX, balP, balC, FEE_XP, FEE_C); + let tot = startNode.reduceTotalBalanceFromParents(); + expect(tot).toEqual(expected); + }); + + it('no balance', () => { + let balX = new BN(0); + let balP = new BN(0); + let balC = new BN(0); + + let expected = new BN(0); + let startNode = createGraphForX(balX, balP, balC, FEE_XP, FEE_C); + let tot = startNode.reduceTotalBalanceFromParents(); + expect(tot).toEqual(expected); + }); + + it('starting node has 1 AVAX', () => { + let balX = new BN(1000000000); + let balP = new BN(0); + let balC = new BN(0); + + let expected = balX; + let startNode = createGraphForX(balX, balP, balC, FEE_XP, FEE_C); + let tot = startNode.reduceTotalBalanceFromParents(); + expect(tot).toEqual(expected); + }); +}); + +describe('Reduce parent balance of UniversalNode C', () => { + beforeEach(() => { + (pChain.getTxFee as jest.Mock).mockReturnValue(FEE_XP); + (xChain.getTxFee as jest.Mock).mockReturnValue(FEE_XP); + }); + + it('all nodes have balance of 1 AVAX', () => { + let balX = new BN(1000000000); + let balP = new BN(1000000000); + let balC = new BN(1000000000); + + let expected = balC.add(balX.sub(FEE_XP).sub(FEE_C)).add(balP.sub(FEE_XP).sub(FEE_C)); + let startNode = createGraphForC(balX, balP, balC, FEE_XP, FEE_C); + let tot = startNode.reduceTotalBalanceFromParents(); + expect(tot).toEqual(expected); + }); + + it('both parents have balance of 1 AVAX', () => { + let balX = new BN(1000000000); + let balP = new BN(1000000000); + let balC = new BN(0); + + let expected = balX.sub(FEE_XP).sub(FEE_C).add(balP.sub(FEE_XP).sub(FEE_C)); + let startNode = createGraphForC(balX, balP, balC, FEE_XP, FEE_C); + let tot = startNode.reduceTotalBalanceFromParents(); + expect(tot).toEqual(expected); + }); + + it('parent P has balance of 1 AVAX', () => { + let balX = new BN(0); + let balP = new BN(1000000000); + let balC = new BN(0); + + let expected = balP.sub(FEE_XP).sub(FEE_C); + let startNode = createGraphForC(balX, balP, balC, FEE_XP, FEE_C); + let tot = startNode.reduceTotalBalanceFromParents(); + expect(tot).toEqual(expected); + }); + + it('parent X has balance of 1 AVAX', () => { + let balX = new BN(1000000000); + let balP = new BN(0); + let balC = new BN(0); + + let expected = balX.sub(FEE_XP).sub(FEE_C); + let startNode = createGraphForC(balX, balP, balC, FEE_XP, FEE_C); + let tot = startNode.reduceTotalBalanceFromParents(); + expect(tot).toEqual(expected); + }); + + it('no balance', () => { + let balX = new BN(0); + let balP = new BN(0); + let balC = new BN(0); + + let expected = new BN(0); + let startNode = createGraphForC(balX, balP, balC, FEE_XP, FEE_C); + let tot = startNode.reduceTotalBalanceFromParents(); + expect(tot).toEqual(expected); + }); + + it('starting node has 1 AVAX', () => { + let balX = new BN(0); + let balP = new BN(0); + let balC = new BN(1000000000); + + let expected = balC; + let startNode = createGraphForC(balX, balP, balC, FEE_XP, FEE_C); + let tot = startNode.reduceTotalBalanceFromParents(); + expect(tot).toEqual(expected); + }); +}); + +describe('Get transactions for balance on UniversalNode P', () => { + beforeEach(() => { + (pChain.getTxFee as jest.Mock).mockReturnValue(FEE_XP); + (xChain.getTxFee as jest.Mock).mockReturnValue(FEE_XP); + }); + + it('node has enough balance, return empty array', () => { + let balP = new BN(1_000_000_000); + let balX = new BN(0); + let balC = new BN(0); + + let nodeP = createGraphForP(balX, balP, balC, FEE_XP, FEE_C); + let target = new BN(1_000_000_000); + + let steps = nodeP.getStepsForTargetBalance(target); + + expect(steps.length).toEqual(0); + }); + + it('node needs balance from parent X', () => { + let balP = new BN(1_000_000_000); + let balX = new BN(2_000_000_000); + let balC = new BN(0); + + let nodeP = createGraphForP(balX, balP, balC, FEE_XP, FEE_C); + let target = new BN(2_000_000_000); + + let stepsExpected: UniversalTx[] = [ + { + action: 'export_x_p', + amount: target.sub(balP).add(FEE_XP), + fee: FEE_XP, + }, + { + action: 'import_x_p', + fee: FEE_XP, + }, + ]; + + let steps = nodeP.getStepsForTargetBalance(target); + + compareSteps(steps, stepsExpected); + }); + + it('node needs balance from 2nd parent', () => { + let balP = new BN(1_000_000_000); + let balX = new BN(0); + let balC = new BN(2_000_000_000); + + let nodeP = createGraphForP(balX, balP, balC, FEE_XP, FEE_C); + let target = new BN(2_000_000_000); + + let stepsExpected: UniversalTx[] = [ + { + action: 'export_c_p', + amount: target.sub(balP).add(FEE_XP), + fee: FEE_C, + }, + { + action: 'import_c_p', + fee: FEE_XP, + }, + ]; + + let steps = nodeP.getStepsForTargetBalance(target); + + compareSteps(steps, stepsExpected); + }); + + it('node needs balance from both parents and self', () => { + let balP = new BN(1_000_000_000); // 1 AVAX + let balX = new BN(500_000_000); // 0.5 AVAX + let balC = new BN(2_000_000_000); // 2 AVAX + + let nodeP = createGraphForP(balX, balP, balC, FEE_XP, FEE_C); + let target = new BN(2_000_000_000); // 2 AVAX + + let stepsExpected: UniversalTx[] = [ + { + action: 'export_x_p', + amount: balX.sub(FEE_XP), + fee: FEE_XP, + }, + { + action: 'import_x_p', + fee: FEE_XP, + }, + { + action: 'export_c_p', + amount: target.sub(balP).sub(balX.sub(FEE_XP).sub(FEE_XP)).add(FEE_XP), + fee: FEE_C, + }, + { + action: 'import_c_p', + fee: FEE_XP, + }, + ]; + + let steps = nodeP.getStepsForTargetBalance(target); + + compareSteps(steps, stepsExpected); + }); + + it('node needs balance from both parents', () => { + let balP = new BN(0); // 0 AVAX + let balX = new BN(1_000_000_000); // 1 AVAX + let balC = new BN(2_000_000_000); // 2 AVAX + + let nodeP = createGraphForP(balX, balP, balC, FEE_XP, FEE_C); + let target = new BN(2_000_000_000); // 2 AVAX + + let stepsExpected: UniversalTx[] = [ + { + action: 'export_x_p', + amount: balX.sub(FEE_XP), // All of the balance minus export fee + fee: FEE_XP, + }, + { + action: 'import_x_p', + fee: FEE_XP, + }, + { + action: 'export_c_p', + amount: target.sub(balX.sub(FEE_XP).sub(FEE_XP)).add(FEE_XP), + fee: FEE_C, + }, + { + action: 'import_c_p', + fee: FEE_XP, + }, + ]; + + let steps = nodeP.getStepsForTargetBalance(target); + + compareSteps(steps, stepsExpected); + }); + + it('not enough balance', () => { + let balP = new BN(0); // 0 AVAX + let balX = new BN(1_000_000_000); // 1 AVAX + let balC = new BN(2_000_000_000); // 2 AVAX + + let nodeP = createGraphForP(balX, balP, balC, FEE_XP, FEE_C); + let target = new BN(20_000_000_000); // 2 AVAX + + expect(() => { + nodeP.getStepsForTargetBalance(target); + }).toThrow(); + }); +}); + +describe('Get transactions for balance on UniversalNode X', () => { + it('node has enough balance return empty array', () => { + let balX = new BN(1_000_000_000); + let balP = new BN(0); + let balC = new BN(0); + + let nodeX = createGraphForX(balX, balP, balC, FEE_XP, FEE_C); + let target = new BN(1_000_000_000); + + let steps = nodeX.getStepsForTargetBalance(target); + + compareSteps(steps, []); + }); + + it('node needs balance from parent P', () => { + let balX = new BN(0); + let balP = new BN(5_000_000_000); // 5 AVAX + let balC = new BN(0); + + let nodeX = createGraphForX(balX, balP, balC, FEE_XP, FEE_C); + let target = new BN(2_000_000_000); // 2 AVAX + + let stepsExpected: UniversalTx[] = [ + { + action: 'export_p_x', + amount: target.add(FEE_XP), + fee: FEE_XP, + }, + { + action: 'import_p_x', + fee: FEE_XP, + }, + ]; + + let steps = nodeX.getStepsForTargetBalance(target); + + compareSteps(steps, stepsExpected); + }); + + it('node has partial balance, needs rest from parent P', () => { + let balX = new BN(1_000_000_000); + let balP = new BN(5_000_000_000); // 5 AVAX + let balC = new BN(0); + + let nodeX = createGraphForX(balX, balP, balC, FEE_XP, FEE_C); + let target = new BN(2_000_000_000); // 2 AVAX + + let stepsExpected: UniversalTx[] = [ + { + action: 'export_p_x', + amount: target.sub(balX).add(FEE_XP), + fee: FEE_XP, + }, + { + action: 'import_p_x', + fee: FEE_XP, + }, + ]; + + let steps = nodeX.getStepsForTargetBalance(target); + + compareSteps(steps, stepsExpected); + }); + + it('node needs balance from P, both parent have balance', () => { + let balX = new BN(0); + let balP = new BN(5_000_000_000); // 5 AVAX + let balC = new BN(5_000_000_000); // 5 AVAX + + let nodeX = createGraphForX(balX, balP, balC, FEE_XP, FEE_C); + let target = new BN(2_000_000_000); // 2 AVAX + + let stepsExpected: UniversalTx[] = [ + { + action: 'export_p_x', + amount: target.add(FEE_XP), + fee: FEE_XP, + }, + { + action: 'import_p_x', + fee: FEE_XP, + }, + ]; + + let steps = nodeX.getStepsForTargetBalance(target); + + compareSteps(steps, stepsExpected); + }); + + it('node needs balance from C', () => { + let balX = new BN(0); + let balP = new BN(0); + let balC = new BN(5_000_000_000); // 5 AVAX + + let nodeX = createGraphForX(balX, balP, balC, FEE_XP, FEE_C); + let target = new BN(2_000_000_000); // 2 AVAX + + let stepsExpected: UniversalTx[] = [ + { + action: 'export_c_x', + amount: target.add(FEE_XP), + fee: FEE_C, + }, + { + action: 'import_c_x', + fee: FEE_XP, + }, + ]; + + let steps = nodeX.getStepsForTargetBalance(target); + + compareSteps(steps, stepsExpected); + }); + + it('node needs balance from both parents', () => { + let balX = new BN(0); + let balP = new BN(700_000_000); + let balC = new BN(700_000_000); + + let nodeX = createGraphForX(balX, balP, balC, FEE_XP, FEE_C); + let target = new BN(1_000_000_000); // 1 AVAX + + let stepsExpected: UniversalTx[] = [ + { + action: 'export_p_x', + amount: balP.sub(FEE_XP), + fee: FEE_XP, + }, + { + action: 'import_p_x', + fee: FEE_XP, + }, + { + action: 'export_c_x', + amount: target.sub(balP.sub(FEE_XP).sub(FEE_XP)).add(FEE_XP), + fee: FEE_C, + }, + { + action: 'import_c_x', + fee: FEE_XP, + }, + ]; + + let steps = nodeX.getStepsForTargetBalance(target); + + compareSteps(steps, stepsExpected); + }); + + it('not enough balance', () => { + let balP = new BN(1_000_000_000); // 0 AVAX + let balX = new BN(1_000_000); // 1 AVAX + let balC = new BN(2_000_000_000); // 2 AVAX + + let nodeX = createGraphForX(balX, balP, balC, FEE_XP, FEE_C); + let target = new BN(20_000_000_000); // 2 AVAX + + expect(() => { + nodeX.getStepsForTargetBalance(target); + }).toThrow(); + }); +}); + +describe('Get transactions for balance on UniversalNode C', () => { + it('node has enough balance return empty array', () => { + let balX = new BN(0); + let balP = new BN(0); + let balC = new BN(1_000_000_000); + + let nodeC = createGraphForC(balX, balP, balC, FEE_XP, FEE_C); + let target = new BN(1_000_000_000); + + let steps = nodeC.getStepsForTargetBalance(target); + + compareSteps(steps, []); + }); + + it('node needs balance from parent P', () => { + let balX = new BN(0); + let balP = new BN(5_000_000_000); // 5 AVAX + let balC = new BN(0); + + let nodeC = createGraphForC(balX, balP, balC, FEE_XP, FEE_C); + let target = new BN(2_000_000_000); // 2 AVAX + + let stepsExpected: UniversalTx[] = [ + { + action: 'export_p_c', + amount: target.add(FEE_C), + fee: FEE_XP, + }, + { + action: 'import_p_c', + fee: FEE_C, + }, + ]; + + let steps = nodeC.getStepsForTargetBalance(target); + + compareSteps(steps, stepsExpected); + }); + + it('node has partial balance, needs rest from parent P', () => { + let balX = new BN(0); + let balP = new BN(5_000_000_000); // 5 AVAX + let balC = new BN(1_000_000_000); + + let nodeC = createGraphForC(balX, balP, balC, FEE_XP, FEE_C); + let target = new BN(2_000_000_000); // 2 AVAX + + let stepsExpected: UniversalTx[] = [ + { + action: 'export_p_c', + amount: target.sub(balC).add(FEE_C), + fee: FEE_XP, + }, + { + action: 'import_p_c', + fee: FEE_C, + }, + ]; + + let steps = nodeC.getStepsForTargetBalance(target); + + compareSteps(steps, stepsExpected); + }); + + it('node needs balance from X, both parent have balance', () => { + let balX = new BN(5_000_000_000); + let balP = new BN(5_000_000_000); + let balC = new BN(0); + + let nodeC = createGraphForC(balX, balP, balC, FEE_XP, FEE_C); + let target = new BN(2_000_000_000); // 2 AVAX + + let stepsExpected: UniversalTx[] = [ + { + action: 'export_x_c', + amount: target.add(FEE_C), + fee: FEE_XP, + }, + { + action: 'import_x_c', + fee: FEE_C, + }, + ]; + + let steps = nodeC.getStepsForTargetBalance(target); + + compareSteps(steps, stepsExpected); + }); + + it('node needs balance from P', () => { + let balX = new BN(0); + let balP = new BN(5_000_000_000); + let balC = new BN(0); + + let nodeC = createGraphForC(balX, balP, balC, FEE_XP, FEE_C); + let target = new BN(2_000_000_000); // 2 AVAX + + let stepsExpected: UniversalTx[] = [ + { + action: 'export_p_c', + amount: target.add(FEE_C), + fee: FEE_XP, + }, + { + action: 'import_p_c', + fee: FEE_C, + }, + ]; + + let steps = nodeC.getStepsForTargetBalance(target); + + compareSteps(steps, stepsExpected); + }); + + it('node needs balance from both parents', () => { + let balX = new BN(700_000_000); + let balP = new BN(700_000_000); + let balC = new BN(0); + + let nodeC = createGraphForC(balX, balP, balC, FEE_XP, FEE_C); + let target = new BN(1_000_000_000); + + let stepsExpected: UniversalTx[] = [ + { + action: 'export_x_c', + amount: balX.sub(FEE_XP), + fee: FEE_XP, + }, + { + action: 'import_x_c', + fee: FEE_C, + }, + { + action: 'export_p_c', + amount: target.sub(balX.sub(FEE_XP).sub(FEE_C)).add(FEE_C), + fee: FEE_XP, + }, + { + action: 'import_p_c', + fee: FEE_C, + }, + ]; + + let steps = nodeC.getStepsForTargetBalance(target); + + compareSteps(steps, stepsExpected); + }); +}); diff --git a/test/Wallet/EvmWallet.test.ts b/test/Wallet/EvmWallet.test.ts index a4739f0a..cdb702b4 100644 --- a/test/Wallet/EvmWallet.test.ts +++ b/test/Wallet/EvmWallet.test.ts @@ -1,4 +1,4 @@ -import EvmWallet from '@/Wallet/EvmWallet'; +import { EvmWallet } from '@/Wallet/EvmWallet'; let PK_HEX = `8985df5f35f11ad2b2f5e8bebd28e738fd731949ce43fde88634704b4026366e`; let keyBuf = Buffer.from(PK_HEX, 'hex'); diff --git a/test/Wallet/EvmWalletReadonly.ts b/test/Wallet/EvmWalletReadonly.ts index b611316e..6c7b7e61 100644 --- a/test/Wallet/EvmWalletReadonly.ts +++ b/test/Wallet/EvmWalletReadonly.ts @@ -1,4 +1,4 @@ -import EvmWalletReadonly from '@/Wallet/EvmWalletReadonly'; +import { EvmWalletReadonly } from '@/Wallet/EvmWalletReadonly'; describe('EVM Wallet Readonly', () => { // let publicKey; diff --git a/test/Wallet/HdScanner.test.ts b/test/Wallet/HdScanner.test.ts index 2450619c..5e05c178 100644 --- a/test/Wallet/HdScanner.test.ts +++ b/test/Wallet/HdScanner.test.ts @@ -2,7 +2,7 @@ import * as bip39 from 'bip39'; import * as bip32 from 'bip32'; import { getAccountPathAvalanche } from '@/Wallet/helpers/derivationHelper'; import { TEST_MNEMONIC, TEST_MNEMONIC_ADDRS_EXT, TEST_MNEMONIC_ADDRS_INT } from './constants'; -import HdScanner from '@/Wallet/HdScanner'; +import { HdScanner } from '@/Wallet/HdScanner'; import { activeNetwork, avalanche, explorer_api } from '@/Network/network'; import { getAddressChains } from '@/Explorer'; import { HD_SCAN_GAP_SIZE } from '@/Wallet/constants'; diff --git a/test/Wallet/MnemonicWallet.test.ts b/test/Wallet/MnemonicWallet.test.ts index 0ba9978d..b95877e9 100644 --- a/test/Wallet/MnemonicWallet.test.ts +++ b/test/Wallet/MnemonicWallet.test.ts @@ -1,4 +1,4 @@ -import MnemonicWallet from '@/Wallet/MnemonicWallet'; +import { MnemonicWallet } from '@/Wallet/MnemonicWallet'; import { TEST_MNEMONIC } from './constants'; jest.mock('web3', () => { @@ -54,4 +54,8 @@ describe('Mnemonic Wallet', () => { it('can return initial C address', () => { expect(wallet.getAddressC()).toEqual('0x6a23c16777a3A194b2773df90FEB8753A8e619Ee'); }); + + it('can return C chain bech32 address', () => { + expect(wallet.getEvmAddressBech()).toEqual('C-avax1t5dhkc4myzvyqsct3dmaue2hc43na8qh3v6xx4'); + }); }); diff --git a/test/Wallet/PublicMnemonicWallet.test.ts b/test/Wallet/PublicMnemonicWallet.test.ts index f7f70527..cbba573a 100644 --- a/test/Wallet/PublicMnemonicWallet.test.ts +++ b/test/Wallet/PublicMnemonicWallet.test.ts @@ -1,5 +1,4 @@ -// Source mnemonic -// chimney noodle canyon tunnel sample stuff scan symbol sight club net own arrive cause suffer purity manage squirrel boost diesel bring cement father slide +import { XPUB_AVAX, XPUB_ETH_ADDR } from './constants'; jest.mock('@/Network', () => { return { @@ -9,21 +8,19 @@ jest.mock('@/Network', () => { }; }); -import PublicMnemonicWallet from '@/Wallet/PublicMnemonicWallet'; - -const XPUB_AVM = `xpub6CvdTKLRh3ehvVLR2f3M1GUTFesrz5zoYFbw32iZqRShmoDnxtfSaF7mdCvXwNRfTwce5RYEADGb6YAzhqEAujEkvjTod6s2WEkpUBJZwqf`; -const XPUB_EVM = `xpub6CQ5fy7iAochmG1tL2ww2P4BviDRRrcEjG3u1uM6GcyGwzihscWoX9RwiCrZDcpAbYK8reYcy7cT8ZgZWVbReZ44ehVYqi5jZD9NknLx4TS`; +import { PublicMnemonicWallet } from '@/Wallet/PublicMnemonicWallet'; describe('Public Mnemonic Wallet', () => { it('can init', () => { - let wallet = new PublicMnemonicWallet(XPUB_AVM, XPUB_EVM); + let wallet = new PublicMnemonicWallet(XPUB_AVAX, XPUB_ETH_ADDR); }); it('can get correct addresses', () => { - let wallet = new PublicMnemonicWallet(XPUB_AVM, XPUB_EVM); + let wallet = new PublicMnemonicWallet(XPUB_AVAX, XPUB_ETH_ADDR); expect(wallet.getAddressX()).toEqual(`X-avax19v8flm9qt2gv2tctztjjerlgs4k3vgjsfw8udh`); expect(wallet.getAddressP()).toEqual(`P-avax19v8flm9qt2gv2tctztjjerlgs4k3vgjsfw8udh`); expect(wallet.getChangeAddressX()).toEqual(`X-avax1fp5jw95s3s0sgylt5yvegpu03k5aggtypgpe02`); expect(wallet.getAddressC()).toEqual(`0x6a23c16777a3A194b2773df90FEB8753A8e619Ee`); + expect(wallet.getEvmAddressBech()).toEqual(`C-avax1t5dhkc4myzvyqsct3dmaue2hc43na8qh3v6xx4`); }); }); diff --git a/test/Wallet/constants.ts b/test/Wallet/constants.ts index d4450682..0f6e4e24 100644 --- a/test/Wallet/constants.ts +++ b/test/Wallet/constants.ts @@ -49,3 +49,9 @@ export const TEST_MNEMONIC_ADDRS_INT = [ 'X-avax16cxcg2kdvajvg49mf646u5u00487tgpv4cwjq5', 'X-avax16xzgjae27pqhye5jxyrake5yv7cj4yawa6g706', ]; + +// m/44'/9000'/0' +export const XPUB_AVAX = `xpub6CvdTKLRh3ehvVLR2f3M1GUTFesrz5zoYFbw32iZqRShmoDnxtfSaF7mdCvXwNRfTwce5RYEADGb6YAzhqEAujEkvjTod6s2WEkpUBJZwqf`; +// m/44'/60'/0' +export const XPUB_ETH_ACCT = `xpub6CQ5fy7iAochmG1tL2ww2P4BviDRRrcEjG3u1uM6GcyGwzihscWoX9RwiCrZDcpAbYK8reYcy7cT8ZgZWVbReZ44ehVYqi5jZD9NknLx4TS`; +export const XPUB_ETH_ADDR = `xpub6H6BqGq4LFAeEyDn4VspySZerHZCGFUAe5Y21UQnyd6VdyZmUX6nzjp9FyuyEtPVCfhK7yKy2Yan9S7wziMQxvb2PHHx6kZ4ByaFD76qJ3j`; diff --git a/test/helpers/gas_helper.test.ts b/test/helpers/gas_helper.test.ts new file mode 100644 index 00000000..23307d0a --- /dev/null +++ b/test/helpers/gas_helper.test.ts @@ -0,0 +1,69 @@ +import { adjustValue, getBaseFee, getGasPrice, getMaxPriorityFee } from '@/helpers/gas_helper'; +import { cChain, setRpcNetwork, web3 } from '@/Network/network'; +import BN from 'bn.js'; + +jest.mock('@/Network/network', () => { + return { + cChain: { + getBaseFee: jest.fn(), + getMaxPriorityFeePerGas: jest.fn(), + }, + web3: { + eth: { + getGasPrice: jest.fn(), + }, + }, + setRpcNetwork: jest.fn(), + }; +}); + +describe('getGasPrice', () => { + it('getGasPrice', async () => { + web3.eth.getGasPrice.mockReturnValueOnce('1'); + let gasPrice = await getGasPrice(); + expect(gasPrice).toEqual(new BN(1)); + }); +}); + +describe('getBaseFee', () => { + it('0 base fee', async () => { + cChain.getBaseFee.mockReturnValueOnce('0x0'); + let baseFee = await getBaseFee(); + expect(baseFee.toString()).toEqual('0'); + }); + + it('1 gwei', async () => { + cChain.getBaseFee.mockReturnValueOnce('0x3B9ACA00'); + let baseFee = await getBaseFee(); + expect(baseFee).toEqual(new BN(1_000_000_000)); + }); +}); + +describe('getMaxPriorityFee', () => { + it('0 fee', async () => { + cChain.getMaxPriorityFeePerGas.mockReturnValueOnce('0x0'); + let fee = await getMaxPriorityFee(); + expect(fee.toString()).toEqual('0'); + }); + + it('1 gwei', async () => { + cChain.getMaxPriorityFeePerGas.mockReturnValueOnce('0x3B9ACA00'); + let fee = await getMaxPriorityFee(); + expect(fee.toString()).toEqual('1000000000'); + }); +}); + +describe('get adjusted values', () => { + it('add 20%', () => { + const val = new BN(100); + let res = adjustValue(val, 20); + expect(res).toEqual(new BN(120)); + }); + + it('add 20% to 101', () => { + const val = new BN(101); + let res = adjustValue(val, 20); + // The real value is 121.2, but the decimals are dropped on BN calculations + expect(res).toEqual(new BN(121)); + }); +}); diff --git a/test/helpers/universal_tx_helper.test.ts b/test/helpers/universal_tx_helper.test.ts deleted file mode 100644 index ea4a0c36..00000000 --- a/test/helpers/universal_tx_helper.test.ts +++ /dev/null @@ -1,407 +0,0 @@ -import { createGraphForP, createGraphForX, UniversalTx } from '@/helpers/universal_tx_helper'; -import { BN } from 'avalanche'; -import { pChain, xChain } from '@/Network/network'; - -jest.mock('@/Network/network', () => { - return { - web3: { - utils: { - isAddress: jest.fn().mockReturnValue(true), - }, - }, - pChain: { - getTxFee: jest.fn(), - }, - xChain: { - getTxFee: jest.fn(), - }, - }; -}); - -const FEE = new BN(1000000); - -function compareSteps(steps: UniversalTx[], expected: UniversalTx[]) { - expect(steps.length).toEqual(expected.length); - - for (let i = 0; i < steps.length; i++) { - let step = steps[i]; - let exp = expected[i]; - expect(step).toEqual(exp); - } -} - -describe('Reduce parent balance of UniversalNode P', () => { - beforeEach(() => { - (pChain.getTxFee as jest.Mock).mockReturnValue(FEE); - (xChain.getTxFee as jest.Mock).mockReturnValue(FEE); - }); - - it('all parents have balance of 1 AVAX', () => { - let balX = new BN(1000000000); - let balP = new BN(1000000000); - let balC = new BN(1000000000); - - let expected = new BN(2996000000); - let startNode = createGraphForP(balX, balP, balC); - let tot = startNode.reduceTotalBalanceFromParents(); - expect(tot).toEqual(expected); - }); - - it('middle child empty', () => { - let balP = new BN(1000000000); - let balX = new BN(0); - let balC = new BN(1000000000); - - let expected = new BN(1996000000); - let startNode = createGraphForP(balX, balP, balC); - let tot = startNode.reduceTotalBalanceFromParents(); - expect(tot).toEqual(expected); - }); - - it('only top parent has balance', () => { - let balP = new BN(0); - let balX = new BN(0); - let balC = new BN(1000000000); - - let expected = new BN(996000000); - let startNode = createGraphForP(balX, balP, balC); - let tot = startNode.reduceTotalBalanceFromParents(); - expect(tot).toEqual(expected); - }); - - it('starting node has balance', () => { - let balP = new BN(1000000000); - let balX = new BN(0); - let balC = new BN(0); - - let expected = new BN(1000000000); - let startNode = createGraphForP(balX, balP, balC); - let tot = startNode.reduceTotalBalanceFromParents(); - expect(tot).toEqual(expected); - }); -}); - -describe('Reduce parent balance of UniversalNode X', () => { - beforeEach(() => { - (pChain.getTxFee as jest.Mock).mockReturnValue(FEE); - (xChain.getTxFee as jest.Mock).mockReturnValue(FEE); - }); - - it('all nodes have balance of 1 AVAX', () => { - let balX = new BN(1000000000); - let balP = new BN(1000000000); - let balC = new BN(1000000000); - - let expected = new BN(2996000000); - let startNode = createGraphForX(balX, balP, balC); - let tot = startNode.reduceTotalBalanceFromParents(); - expect(tot).toEqual(expected); - }); - - it('both parents have balance of 1 AVAX', () => { - let balX = new BN(0); - let balP = new BN(1000000000); - let balC = new BN(1000000000); - - let expected = new BN(1996000000); - let startNode = createGraphForX(balX, balP, balC); - let tot = startNode.reduceTotalBalanceFromParents(); - expect(tot).toEqual(expected); - }); - - it('one parent has balance of 1 AVAX', () => { - let balX = new BN(0); - let balP = new BN(1000000000); - let balC = new BN(0); - - let expected = new BN(998000000); - let startNode = createGraphForX(balX, balP, balC); - let tot = startNode.reduceTotalBalanceFromParents(); - expect(tot).toEqual(expected); - }); - - it('other parent has balance of 1 AVAX', () => { - let balX = new BN(0); - let balP = new BN(0); - let balC = new BN(1000000000); - - let expected = new BN(998000000); - let startNode = createGraphForX(balX, balP, balC); - let tot = startNode.reduceTotalBalanceFromParents(); - expect(tot).toEqual(expected); - }); - - it('no balance', () => { - let balX = new BN(0); - let balP = new BN(0); - let balC = new BN(0); - - let expected = new BN(0); - let startNode = createGraphForX(balX, balP, balC); - let tot = startNode.reduceTotalBalanceFromParents(); - expect(tot).toEqual(expected); - }); - - it('starting node has 1 AVAX', () => { - let balX = new BN(1000000000); - let balP = new BN(0); - let balC = new BN(0); - - let expected = new BN(1000000000); - let startNode = createGraphForX(balX, balP, balC); - let tot = startNode.reduceTotalBalanceFromParents(); - expect(tot).toEqual(expected); - }); -}); - -describe('Get transactions for balance on UniversalNode P', () => { - beforeEach(() => { - (pChain.getTxFee as jest.Mock).mockReturnValue(FEE); - (xChain.getTxFee as jest.Mock).mockReturnValue(FEE); - }); - - it('node has enough balance, return empty array', () => { - let balP = new BN(1000000000); - let balX = new BN(0); - let balC = new BN(0); - - let nodeP = createGraphForP(balX, balP, balC); - let target = new BN(1000000000); - - let steps = nodeP.getStepsForTargetBalance(target); - - expect(steps.length).toEqual(0); - }); - - it('node needs balance from parent', () => { - let balP = new BN(1000000000); - let balX = new BN(2000000000); - let balC = new BN(0); - - let nodeP = createGraphForP(balX, balP, balC); - let target = new BN(2000000000); - - let stepsExpected: UniversalTx[] = [ - { - action: 'export_x_p', - amount: new BN(1000000000), - }, - { - action: 'import_x_p', - }, - ]; - - let steps = nodeP.getStepsForTargetBalance(target); - - compareSteps(steps, stepsExpected); - }); - - it('node needs balance from top parent', () => { - let balP = new BN(1000000000); - let balX = new BN(0); - let balC = new BN(2000000000); - - let nodeP = createGraphForP(balX, balP, balC); - let target = new BN(2000000000); - - let stepsExpected: UniversalTx[] = [ - { - action: 'export_c_x', - amount: new BN(1002000000), - }, - { - action: 'import_c_x', - }, - { - action: 'export_x_p', - amount: new BN(1000000000), - }, - { - action: 'import_x_p', - }, - ]; - - let steps = nodeP.getStepsForTargetBalance(target); - - compareSteps(steps, stepsExpected); - }); - - it('node needs balance from both parents and self', () => { - let balP = new BN(1000000000); // 1 AVAX - let balX = new BN(500000000); // 0.5 AVAX - let balC = new BN(2000000000); // 2 AVAX - - let nodeP = createGraphForP(balX, balP, balC); - let target = new BN(2000000000); // 2 AVAX - - let stepsExpected: UniversalTx[] = [ - { - action: 'export_c_x', - amount: new BN(502000000), - }, - { - action: 'import_c_x', - }, - { - action: 'export_x_p', - amount: new BN(1000000000), - }, - { - action: 'import_x_p', - }, - ]; - - let steps = nodeP.getStepsForTargetBalance(target); - - compareSteps(steps, stepsExpected); - }); - - it('node needs balance from both parents', () => { - let balP = new BN(0); // 0 AVAX - let balX = new BN(1000000000); // 1 AVAX - let balC = new BN(2000000000); // 2 AVAX - - let nodeP = createGraphForP(balX, balP, balC); - let target = new BN(2000000000); // 2 AVAX - - let stepsExpected: UniversalTx[] = [ - { - action: 'export_c_x', - amount: new BN(1002000000), - }, - { - action: 'import_c_x', - }, - { - action: 'export_x_p', - amount: new BN(2000000000), - }, - { - action: 'import_x_p', - }, - ]; - - let steps = nodeP.getStepsForTargetBalance(target); - - compareSteps(steps, stepsExpected); - }); -}); - -describe('Get transactions for balance on UniversalNode X', () => { - beforeEach(() => { - (pChain.getTxFee as jest.Mock).mockReturnValue(FEE); - (xChain.getTxFee as jest.Mock).mockReturnValue(FEE); - }); - - it('node has enough balance return empty array', () => { - let balX = new BN(1000000000); - let balP = new BN(0); - let balC = new BN(0); - - let nodeP = createGraphForX(balX, balP, balC); - let target = new BN(1000000000); - - let steps = nodeP.getStepsForTargetBalance(target); - - compareSteps(steps, []); - }); - - it('node needs balance from P', () => { - let balX = new BN(0); - let balP = new BN(5000000000); // 5 AVAX - let balC = new BN(0); - - let nodeX = createGraphForX(balX, balP, balC); - let target = new BN(2000000000); // 2 AVAX - - let stepsExpected: UniversalTx[] = [ - { - action: 'export_p_x', - amount: new BN(2000000000), - }, - { - action: 'import_p_x', - }, - ]; - - let steps = nodeX.getStepsForTargetBalance(target); - - compareSteps(steps, stepsExpected); - }); - - it('node needs balance from P, both parent have balance', () => { - let balX = new BN(0); - let balP = new BN(5000000000); // 5 AVAX - let balC = new BN(5000000000); // 5 AVAX - - let nodeX = createGraphForX(balX, balP, balC); - let target = new BN(2000000000); // 2 AVAX - - let stepsExpected: UniversalTx[] = [ - { - action: 'export_p_x', - amount: new BN(2000000000), - }, - { - action: 'import_p_x', - }, - ]; - - let steps = nodeX.getStepsForTargetBalance(target); - - compareSteps(steps, stepsExpected); - }); - - it('node needs balance from C', () => { - let balX = new BN(0); - let balP = new BN(0); - let balC = new BN(5000000000); // 5 AVAX - - let nodeX = createGraphForX(balX, balP, balC); - let target = new BN(2000000000); // 2 AVAX - - let stepsExpected: UniversalTx[] = [ - { - action: 'export_c_x', - amount: new BN(2000000000), - }, - { - action: 'import_c_x', - }, - ]; - - let steps = nodeX.getStepsForTargetBalance(target); - - compareSteps(steps, stepsExpected); - }); - - it('node needs balance from both parents', () => { - let balX = new BN(0); - let balP = new BN(700000000); - let balC = new BN(700000000); - - let nodeX = createGraphForX(balX, balP, balC); - let target = new BN(1000000000); // 1 AVAX - - let stepsExpected: UniversalTx[] = [ - { - action: 'export_p_x', - amount: new BN(698000000), - }, - { - action: 'import_p_x', - }, - { - action: 'export_c_x', - amount: new BN(302000000), - }, - { - action: 'import_c_x', - }, - ]; - - let steps = nodeX.getStepsForTargetBalance(target); - - compareSteps(steps, stepsExpected); - }); -}); diff --git a/yarn.lock b/yarn.lock index 80c46161..3c697ad3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -942,7 +942,23 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" -"@ethereumjs/common@2.4.0", "@ethereumjs/common@^2.4.0": +"@ethereumjs/common@2.6.0", "@ethereumjs/common@^2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.6.0.tgz#feb96fb154da41ee2cc2c5df667621a440f36348" + integrity sha512-Cq2qS0FTu6O2VU1sgg+WyU9Ps0M6j/BEMHN+hRaECXCV/r0aI78u4N6p52QW/BDVhwWZpCdrvG8X7NJdzlpNUA== + dependencies: + crc-32 "^1.2.0" + ethereumjs-util "^7.1.3" + +"@ethereumjs/common@^2.3.0", "@ethereumjs/common@^2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.5.0.tgz#ec61551b31bef7a69d1dc634d8932468866a4268" + integrity sha512-DEHjW6e38o+JmB/NO3GZBpW4lpaiBpkFgXF6jLcJ6gETBYpEyaA5nTimsWBUJR3Vmtm/didUEbNjajskugZORg== + dependencies: + crc-32 "^1.2.0" + ethereumjs-util "^7.1.1" + +"@ethereumjs/common@^2.4.0": version "2.4.0" resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.4.0.tgz#2d67f6e6ba22246c5c89104e6b9a119fb3039766" integrity sha512-UdkhFWzWcJCZVsj1O/H8/oqj/0RVYjLc1OhPjBrQdALAkQHpCp8xXI4WLnuGTADqTdJZww0NtgwG+TRPkXt27w== @@ -950,13 +966,21 @@ crc-32 "^1.2.0" ethereumjs-util "^7.1.0" -"@ethereumjs/tx@3.3.0": - version "3.3.0" - resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.3.0.tgz#14ed1b7fa0f28e1cd61e3ecbdab824205f6a4378" - integrity sha512-yTwEj2lVzSMgE6Hjw9Oa1DZks/nKTWM8Wn4ykDNapBPua2f4nXO3qKnni86O6lgDj5fVNRqbDsD0yy7/XNGDEA== +"@ethereumjs/tx@3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.4.0.tgz#7eb1947eefa55eb9cf05b3ca116fb7a3dbd0bce7" + integrity sha512-WWUwg1PdjHKZZxPPo274ZuPsJCWV3SqATrEKQP1n2DrVYVP1aZIYpo/mFaA0BDoE0tIQmBeimRCEA0Lgil+yYw== dependencies: - "@ethereumjs/common" "^2.4.0" - ethereumjs-util "^7.1.0" + "@ethereumjs/common" "^2.6.0" + ethereumjs-util "^7.1.3" + +"@ethereumjs/tx@^3.2.1": + version "3.3.2" + resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.3.2.tgz#348d4624bf248aaab6c44fec2ae67265efe3db00" + integrity sha512-6AaJhwg4ucmwTvw/1qLaZUX5miWrwZ4nLOUsKyb/HtzS3BMw/CasKhdi1ims9mBKeK9sOJCH4qGKOBGyJCeeog== + dependencies: + "@ethereumjs/common" "^2.5.0" + ethereumjs-util "^7.1.2" "@ethersproject/abi@5.0.7": version "5.0.7" @@ -1866,6 +1890,16 @@ rxjs "6" semver "^7.3.5" +"@ledgerhq/devices@^6.19.0": + version "6.19.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-6.19.0.tgz#dfda26bdc1e75e4ede2eac5fcef79807ffc57afa" + integrity sha512-xk/6JGrFP/c8aMK4O2fKZFJGH3STynwnIRy6si/400r5p3kJmoyR6h16U954EYcCbyScrVdtDYnZKLTUCbtAIQ== + dependencies: + "@ledgerhq/errors" "^6.10.0" + "@ledgerhq/logs" "^6.10.0" + rxjs "6" + semver "^7.3.5" + "@ledgerhq/errors@^5.50.0": version "5.50.0" resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-5.50.0.tgz#e3a6834cb8c19346efca214c1af84ed28e69dad9" @@ -1907,6 +1941,15 @@ "@ledgerhq/errors" "^6.10.0" events "^3.3.0" +"@ledgerhq/hw-transport@^6.19.0": + version "6.19.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-6.19.0.tgz#416744f584287d1b0efe445fc9d8e9b4d6a91b78" + integrity sha512-B16iNtLb3BS+PlqKU1b6eLzOa8Os03SdeUQUYJrqc8XCqNMHJvpQxSvWVbqZFvRS5Cu991usVsCTFrPtOqaCeQ== + dependencies: + "@ledgerhq/devices" "^6.19.0" + "@ledgerhq/errors" "^6.10.0" + events "^3.3.0" + "@ledgerhq/logs@^5.50.0": version "5.50.0" resolved "https://registry.yarnpkg.com/@ledgerhq/logs/-/logs-5.50.0.tgz#29c6419e8379d496ab6d0426eadf3c4d100cd186" @@ -1948,10 +1991,23 @@ create-hash "1.2.0" jest "^26.4.1" -"@openzeppelin/contracts@4.3.3": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.3.3.tgz#ff6ee919fc2a1abaf72b22814bfb72ed129ec137" - integrity sha512-tDBopO1c98Yk7Cv/PZlHqrvtVjlgK5R4J6jxLwoO7qxK4xqOiZG+zSkIvGFpPZ0ikc3QOED3plgdqjgNTnBc7g== +"@openzeppelin/contracts@4.4.1": + version "4.4.1" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.4.1.tgz#3382db2cd83ab565ed9626765e7da92944b45de8" + integrity sha512-o+pHCf/yMLSlV5MkDQEzEQL402i6SoRnktru+0rdSxVEFZcTzzGhZCAtZjUFyKGazMSv1TilzMg+RbED1N8XHQ== + +"@rollup/plugin-commonjs@^21.0.1": + version "21.0.1" + resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.1.tgz#1e57c81ae1518e4df0954d681c642e7d94588fee" + integrity sha512-EA+g22lbNJ8p5kuZJUYyhhDK7WgJckW5g4pNN7n4mAFUM96VuwUnNT3xr2Db2iCZPI1pJPbGyfT5mS9T1dHfMg== + dependencies: + "@rollup/pluginutils" "^3.1.0" + commondir "^1.0.1" + estree-walker "^2.0.1" + glob "^7.1.6" + is-reference "^1.2.1" + magic-string "^0.25.7" + resolve "^1.17.0" "@rollup/plugin-json@^4.1.0": version "4.1.0" @@ -2016,6 +2072,11 @@ resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== +"@tootallnate/once@2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" + integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== + "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": version "7.1.14" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.14.tgz#faaeefc4185ec71c389f4501ee5ec84b170cc402" @@ -2054,7 +2115,7 @@ resolved "https://registry.yarnpkg.com/@types/big.js/-/big.js-6.1.1.tgz#c2be5e81e0cf0c1c31704e3b12f750712f647414" integrity sha512-Zns+nT0hj96ie+GDbL5NeHxhL4wNz8QMxCHqBvxgc4x0hhgQ/o92rPwqxvPBhY3ZYnH8TJGw/8oCkjhOy2Rfzw== -"@types/bn.js@4.11.6", "@types/bn.js@^4.11.3", "@types/bn.js@^4.11.5": +"@types/bn.js@4.11.6", "@types/bn.js@^4.11.5": version "4.11.6" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== @@ -2075,10 +2136,17 @@ dependencies: "@types/node" "*" +"@types/dompurify@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-2.3.1.tgz#2934adcd31c4e6b02676f9c22f9756e5091c04dd" + integrity sha512-YJth9qa0V/E6/XPH1Jq4BC8uCMmO8V1fKWn8PCvuZcAhMn7q0ez9LW6naQT04UZzjFfAPhyRMZmI2a2rbMlEFA== + dependencies: + "@types/trusted-types" "*" + "@types/estree@*": - version "0.0.48" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.48.tgz#18dc8091b285df90db2f25aa7d906cfc394b7f74" - integrity sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew== + version "0.0.50" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" + integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== "@types/estree@0.0.39": version "0.0.39" @@ -2198,6 +2266,11 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff" integrity sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw== +"@types/trusted-types@*": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.2.tgz#fc25ad9943bcac11cceb8168db4f275e0e72e756" + integrity sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg== + "@types/yargs-parser@*": version "20.2.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.0.tgz#dd3e6699ba3237f0348cd085e4698780204842f9" @@ -2334,6 +2407,11 @@ acorn@^8.2.4: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.4.1.tgz#56c36251fc7cabc7096adc18f05afe814321a28c" integrity sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA== +acorn@^8.5.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.6.0.tgz#e3692ba0eb1a0c83eaa4f37f5fa7368dd7142895" + integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw== + aes-js@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" @@ -2485,6 +2563,16 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= +assert@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-2.0.0.tgz#95fc1c616d48713510680f2eaf2d10dd22e02d32" + integrity sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A== + dependencies: + es6-object-assign "^1.1.0" + is-nan "^1.2.1" + object-is "^1.0.1" + util "^0.12.0" + assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" @@ -2515,23 +2603,27 @@ available-typed-arrays@^1.0.2: resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.4.tgz#9e0ae84ecff20caae6a94a1c3bc39b955649b7a9" integrity sha512-SA5mXJWrId1TaQjfxUYghbqQ/hYioKmLJvPJyDuYRtXXenFNMjj4hSSt1Cf1xsuXSXrtxrVC5Ot4eU6cOtBDdA== -avalanche@3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/avalanche/-/avalanche-3.8.1.tgz#56eac5487a736415536f2dcd1bfc5aaa5195bd64" - integrity sha512-p+bqjsbKynN+oUpi7Eoddavxfbx5wISzv3zXG/8/YUB0kbMnzScO8A5Dfv2Kz1BIQxu6sCb8u6UhJdGId9ElGw== - dependencies: - axios "0.21.1" - bech32 "1.1.4" - bip39 "^3.0.4" - bn.js "4.11.8" - buffer "5.5.0" +avalanche@3.10.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/avalanche/-/avalanche-3.10.1.tgz#68a628abd4fb12fde52447731a662b1be3c1864e" + integrity sha512-A+cd8Bm7F2XvUZ1yM1JESw7sN4TcOtrby0cF+baLv6KCMUT7mGm0wv/UAmlo5ElHY2dwDXHPa9OyOUAKl/wliA== + dependencies: + assert "2.0.0" + axios "0.24.0" + bech32 "2.0.0" + bip39 "3.0.4" + bn.js "5.2.0" + buffer "6.0.3" create-hash "1.2.0" + crypto-browserify "3.12.0" elliptic "6.5.4" - ethers "^5.3.0" + ethers "5.5.1" hdkey "2.0.1" - isomorphic-ws "^4.0.1" - store2 "2.11.0" - ws "^7.4.6" + isomorphic-dompurify "^0.16.0" + isomorphic-ws "4.0.1" + store2 "2.12.0" + stream-browserify "3.0.0" + ws "8.2.3" aws-sign2@~0.7.0: version "0.7.0" @@ -2543,12 +2635,12 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== -axios@0.21.1: - version "0.21.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" - integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== +axios@0.24.0: + version "0.24.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.24.0.tgz#804e6fa1e4b9c5288501dd9dff56a7a0940d20d6" + integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA== dependencies: - follow-redirects "^1.10.0" + follow-redirects "^1.14.4" axios@^0.23.0: version "0.23.0" @@ -2672,7 +2764,7 @@ base-x@^3.0.2, base-x@^3.0.8: dependencies: safe-buffer "^5.0.1" -base64-js@^1.0.2, base64-js@^1.3.1: +base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -2702,6 +2794,11 @@ bech32@1.1.4: resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== +bech32@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/bech32/-/bech32-2.0.0.tgz#078d3686535075c8c79709f054b1b226a133b355" + integrity sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg== + big.js@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/big.js/-/big.js-6.1.1.tgz#63b35b19dc9775c94991ee5db7694880655d5537" @@ -2737,7 +2834,7 @@ bip32@^2.0.6: typeforce "^1.11.5" wif "^2.0.6" -bip39@^3.0.4: +bip39@3.0.4, bip39@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/bip39/-/bip39-3.0.4.tgz#5b11fed966840b5e1b8539f0f54ab6392969b2a0" integrity sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw== @@ -2762,26 +2859,21 @@ bn.js@4.11.6: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" integrity sha1-UzRK2xRhehP26N0s4okF0cC6MhU= -bn.js@4.11.8: - version "4.11.8" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" - integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== - bn.js@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.1.tgz#48efc4031a9c4041b9c99c6941d903463ab62eb5" integrity sha512-IUTD/REb78Z2eodka1QZyyEk66pciRcP6Sroka0aI3tG/iwIdYLrBD62RsubR7vqdt3WyX8p4jxeatzmRSphtA== -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.0, bn.js@^4.11.1, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.1.2: +bn.js@5.2.0, bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.1.2: version "5.2.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.1, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + body-parser@1.19.0, body-parser@^1.16.0: version "1.19.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" @@ -2942,13 +3034,13 @@ buffer-xor@^1.0.3: resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= -buffer@5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.5.0.tgz#9c3caa3d623c33dd1c7ef584b89b88bf9c9bc1ce" - integrity sha512-9FTEDjLjwoAkEwyMGDjYJQN2gfRgOKBKRfiglhvibGbpeeU/pQn1bJxQqm32OD/AIeEuHxU9roxXxg34Byp/Ww== +buffer@6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" + base64-js "^1.3.1" + ieee754 "^1.2.1" buffer@^5.0.5, buffer@^5.5.0, buffer@^5.6.0: version "5.7.1" @@ -3060,7 +3152,7 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== -chownr@^1.1.1: +chownr@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== @@ -3395,6 +3487,11 @@ cssom@^0.4.4: resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== +cssom@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.5.0.tgz#d254fa92cd8b6fbd83811b9fbaed34663cc17c36" + integrity sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw== + cssom@~0.3.6: version "0.3.8" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" @@ -3431,6 +3528,15 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" +data-urls@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-3.0.1.tgz#597fc2ae30f8bc4dbcf731fcd1b1954353afc6f8" + integrity sha512-Ds554NeT5Gennfoo9KN50Vh6tpgtvYEwraYjejXnyTpu1C7oXKxdFk75REooENHE8ndTVOJuv+BEs4/J/xcozw== + dependencies: + abab "^2.0.3" + whatwg-mimetype "^3.0.0" + whatwg-url "^10.0.0" + debug@2.6.9, debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -3450,7 +3556,7 @@ decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= -decimal.js@^10.2.1: +decimal.js@^10.2.1, decimal.js@^10.3.1: version "10.3.1" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== @@ -3603,6 +3709,18 @@ domexception@^2.0.1: dependencies: webidl-conversions "^5.0.0" +domexception@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-4.0.0.tgz#4ad1be56ccadc86fc76d033353999a8037d03673" + integrity sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw== + dependencies: + webidl-conversions "^7.0.0" + +dompurify@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.3.tgz#c1af3eb88be47324432964d8abc75cf4b98d634c" + integrity sha512-dqnqRkPMAjOZE0FogZ+ceJNM2dZ3V/yNOuFB7+39qpO93hHhfRpHw3heYQC7DPK9FqbQTfBKUJhiSfz4MvXYwg== + duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" @@ -3724,6 +3842,11 @@ es6-iterator@~2.0.3: es5-ext "^0.10.35" es6-symbol "^3.1.1" +es6-object-assign@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" + integrity sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw= + es6-symbol@^3.1.1, es6-symbol@~3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" @@ -3889,11 +4012,6 @@ estraverse@^5.1.0, estraverse@^5.2.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== -estree-walker@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362" - integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w== - estree-walker@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" @@ -3971,31 +4089,16 @@ ethereum-cryptography@^0.1.3: secp256k1 "^4.0.1" setimmediate "^1.0.5" -ethereumjs-common@^1.3.2, ethereumjs-common@^1.5.0: - version "1.5.2" - resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.5.2.tgz#2065dbe9214e850f2e955a80e650cb6999066979" - integrity sha512-hTfZjwGX52GS2jcVO6E2sx4YuFnf0Fhp5ylo4pEPhEffNln7vS59Hr5sLnp3/QCazFLluuBZ+FZ6J5HTp0EqCA== - -ethereumjs-tx@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz#5dfe7688bf177b45c9a23f86cf9104d47ea35fed" - integrity sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw== - dependencies: - ethereumjs-common "^1.5.0" - ethereumjs-util "^6.0.0" - -ethereumjs-util@^6.0.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz#fcb4e4dd5ceacb9d2305426ab1a5cd93e3163b69" - integrity sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw== +ethereumjs-util@^7.0.10, ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.2, ethereumjs-util@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.3.tgz#b55d7b64dde3e3e45749e4c41288238edec32d23" + integrity sha512-y+82tEbyASO0K0X1/SRhbJJoAlfcvq8JbrG4a5cjrOks7HS/36efU/0j2flxCPOUM++HFahk33kr/ZxyC4vNuw== dependencies: - "@types/bn.js" "^4.11.3" - bn.js "^4.11.0" + "@types/bn.js" "^5.1.0" + bn.js "^5.1.2" create-hash "^1.1.2" - elliptic "^6.5.2" ethereum-cryptography "^0.1.3" - ethjs-util "0.1.6" - rlp "^2.2.3" + rlp "^2.2.4" ethereumjs-util@^7.0.7: version "7.0.10" @@ -4021,43 +4124,7 @@ ethereumjs-util@^7.1.0: ethjs-util "0.1.6" rlp "^2.2.4" -ethers@^5.1.4, ethers@^5.3.0: - version "5.4.0" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.4.0.tgz#e9fe4b39350bcce5edd410c70bd57ba328ecf474" - integrity sha512-hqN1x0CV8VMpQ25WnNEjaMqtB3nA4DRAb2FSmmNaUbD1dF6kWbHs8YaXbVvD37FCg3GTEyc4rV9Pxafk1ByHKw== - dependencies: - "@ethersproject/abi" "5.4.0" - "@ethersproject/abstract-provider" "5.4.0" - "@ethersproject/abstract-signer" "5.4.0" - "@ethersproject/address" "5.4.0" - "@ethersproject/base64" "5.4.0" - "@ethersproject/basex" "5.4.0" - "@ethersproject/bignumber" "5.4.0" - "@ethersproject/bytes" "5.4.0" - "@ethersproject/constants" "5.4.0" - "@ethersproject/contracts" "5.4.0" - "@ethersproject/hash" "5.4.0" - "@ethersproject/hdnode" "5.4.0" - "@ethersproject/json-wallets" "5.4.0" - "@ethersproject/keccak256" "5.4.0" - "@ethersproject/logger" "5.4.0" - "@ethersproject/networks" "5.4.0" - "@ethersproject/pbkdf2" "5.4.0" - "@ethersproject/properties" "5.4.0" - "@ethersproject/providers" "5.4.0" - "@ethersproject/random" "5.4.0" - "@ethersproject/rlp" "5.4.0" - "@ethersproject/sha2" "5.4.0" - "@ethersproject/signing-key" "5.4.0" - "@ethersproject/solidity" "5.4.0" - "@ethersproject/strings" "5.4.0" - "@ethersproject/transactions" "5.4.0" - "@ethersproject/units" "5.4.0" - "@ethersproject/wallet" "5.4.0" - "@ethersproject/web" "5.4.0" - "@ethersproject/wordlists" "5.4.0" - -ethers@^5.5.1: +ethers@5.5.1, ethers@^5.5.1: version "5.5.1" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.5.1.tgz#d3259a95a42557844aa543906c537106c0406fbf" integrity sha512-RodEvUFZI+EmFcE6bwkuJqpCYHazdzeR1nMzg+YWQSmQEsNtfl1KHGfp/FWZYl48bI/g7cgBeP2IlPthjiVngw== @@ -4093,6 +4160,42 @@ ethers@^5.5.1: "@ethersproject/web" "5.5.0" "@ethersproject/wordlists" "5.5.0" +ethers@^5.1.4: + version "5.4.0" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.4.0.tgz#e9fe4b39350bcce5edd410c70bd57ba328ecf474" + integrity sha512-hqN1x0CV8VMpQ25WnNEjaMqtB3nA4DRAb2FSmmNaUbD1dF6kWbHs8YaXbVvD37FCg3GTEyc4rV9Pxafk1ByHKw== + dependencies: + "@ethersproject/abi" "5.4.0" + "@ethersproject/abstract-provider" "5.4.0" + "@ethersproject/abstract-signer" "5.4.0" + "@ethersproject/address" "5.4.0" + "@ethersproject/base64" "5.4.0" + "@ethersproject/basex" "5.4.0" + "@ethersproject/bignumber" "5.4.0" + "@ethersproject/bytes" "5.4.0" + "@ethersproject/constants" "5.4.0" + "@ethersproject/contracts" "5.4.0" + "@ethersproject/hash" "5.4.0" + "@ethersproject/hdnode" "5.4.0" + "@ethersproject/json-wallets" "5.4.0" + "@ethersproject/keccak256" "5.4.0" + "@ethersproject/logger" "5.4.0" + "@ethersproject/networks" "5.4.0" + "@ethersproject/pbkdf2" "5.4.0" + "@ethersproject/properties" "5.4.0" + "@ethersproject/providers" "5.4.0" + "@ethersproject/random" "5.4.0" + "@ethersproject/rlp" "5.4.0" + "@ethersproject/sha2" "5.4.0" + "@ethersproject/signing-key" "5.4.0" + "@ethersproject/solidity" "5.4.0" + "@ethersproject/strings" "5.4.0" + "@ethersproject/transactions" "5.4.0" + "@ethersproject/units" "5.4.0" + "@ethersproject/wallet" "5.4.0" + "@ethersproject/web" "5.4.0" + "@ethersproject/wordlists" "5.4.0" + ethjs-unit@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" @@ -4409,11 +4512,6 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469" integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA== -follow-redirects@^1.10.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43" - integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg== - follow-redirects@^1.14.4: version "1.14.5" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.5.tgz#f09a5848981d3c772b5392309778523f8d85c381" @@ -4443,6 +4541,15 @@ form-data@^3.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + form-data@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" @@ -4487,7 +4594,7 @@ fs-extra@^4.0.2: jsonfile "^4.0.0" universalify "^0.1.0" -fs-minipass@^1.2.5: +fs-minipass@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== @@ -4828,6 +4935,13 @@ html-encoding-sniffer@^2.0.1: dependencies: whatwg-encoding "^1.0.5" +html-encoding-sniffer@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz#2cb1a8cf0db52414776e5b2a7a04d5dd98158de9" + integrity sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA== + dependencies: + whatwg-encoding "^2.0.0" + html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" @@ -4874,6 +4988,15 @@ http-proxy-agent@^4.0.1: agent-base "6" debug "4" +http-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" + integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== + dependencies: + "@tootallnate/once" "2" + agent-base "6" + debug "4" + http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -4908,6 +5031,13 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + idna-uts46-hx@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz#a1dc5c4df37eee522bf66d969cc980e00e8711f9" @@ -4915,7 +5045,7 @@ idna-uts46-hx@^2.3.1: dependencies: punycode "2.1.0" -ieee754@^1.1.13, ieee754@^1.1.4: +ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -4964,7 +5094,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -5139,6 +5269,14 @@ is-hex-prefixed@1.0.0: resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" integrity sha1-fY035q135dEnFIkTxXPggtd39VQ= +is-nan@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" + integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + is-negative-zero@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" @@ -5198,7 +5336,7 @@ is-potential-custom-element-name@^1.0.1: resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== -is-reference@^1.1.2: +is-reference@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== @@ -5300,7 +5438,16 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= -isomorphic-ws@^4.0.1: +isomorphic-dompurify@^0.16.0: + version "0.16.0" + resolved "https://registry.yarnpkg.com/isomorphic-dompurify/-/isomorphic-dompurify-0.16.0.tgz#4c8dd90f033538e8278ebb9ed7aac765f81e7d6a" + integrity sha512-o598ifhryrDU6sZCAz6EAQfb+GJcJqBcST23OHCD57jS8kO+OAAVC7XuLbQqbHgU2qcogFxnZwa7QhasQXEqkw== + dependencies: + "@types/dompurify" "^2.3.1" + dompurify "^2.3.3" + jsdom "^18.0.0" + +isomorphic-ws@4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== @@ -5793,6 +5940,39 @@ jsdom@^16.4.0: ws "^7.4.5" xml-name-validator "^3.0.0" +jsdom@^18.0.0: + version "18.1.1" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-18.1.1.tgz#15ec896f5ab7df9669a62375606f47c8c09551aa" + integrity sha512-NmJQbjQ/gpS/1at/ce3nCx89HbXL/f5OcenBe8wU1Eik0ROhyUc3LtmG3567dEHAGXkN8rmILW/qtCOPxPHQJw== + dependencies: + abab "^2.0.5" + acorn "^8.5.0" + acorn-globals "^6.0.0" + cssom "^0.5.0" + cssstyle "^2.3.0" + data-urls "^3.0.1" + decimal.js "^10.3.1" + domexception "^4.0.0" + escodegen "^2.0.0" + form-data "^4.0.0" + html-encoding-sniffer "^3.0.0" + http-proxy-agent "^5.0.0" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^3.0.0" + webidl-conversions "^7.0.0" + whatwg-encoding "^2.0.0" + whatwg-mimetype "^3.0.0" + whatwg-url "^10.0.0" + ws "^8.2.3" + xml-name-validator "^4.0.0" + jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" @@ -6065,7 +6245,7 @@ lunr@^2.3.9: resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow== -magic-string@^0.25.2: +magic-string@^0.25.7: version "0.25.7" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== @@ -6233,7 +6413,7 @@ minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== -minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: +minipass@^2.6.0, minipass@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== @@ -6241,7 +6421,7 @@ minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: safe-buffer "^5.1.2" yallist "^3.0.0" -minizlib@^1.2.1: +minizlib@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== @@ -6268,7 +6448,7 @@ mkdirp@*: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mkdirp@^0.5.0: +mkdirp@^0.5.5: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== @@ -6280,11 +6460,6 @@ mock-fs@^4.1.0: resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" integrity sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw== -moment@^2.29.1: - version "2.29.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" - integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -6507,6 +6682,14 @@ object-inspect@^1.10.3: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369" integrity sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw== +object-is@^1.0.1: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -6993,7 +7176,7 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -readable-stream@^3.6.0: +readable-stream@^3.5.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -7146,7 +7329,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@1.20.0, resolve@>=1.9.0, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.18.1: +resolve@1.20.0, resolve@>=1.9.0, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.18.1: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== @@ -7194,24 +7377,13 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" -rlp@^2.2.3, rlp@^2.2.4: +rlp@^2.2.4: version "2.2.6" resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.6.tgz#c80ba6266ac7a483ef1e69e8e2f056656de2fb2c" integrity sha512-HAfAmL6SDYNWPUOJNrM500x4Thn4PZsEy5pijPh40U9WfNk0z15hUYzO9xVIMAdIHdFtD8CBDHd75Td1g36Mjg== dependencies: bn.js "^4.11.1" -rollup-plugin-commonjs@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz#417af3b54503878e084d127adf4d1caf8beb86fb" - integrity sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q== - dependencies: - estree-walker "^0.6.1" - is-reference "^1.1.2" - magic-string "^0.25.2" - resolve "^1.11.0" - rollup-pluginutils "^2.8.1" - rollup-plugin-delete@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/rollup-plugin-delete/-/rollup-plugin-delete-2.0.0.tgz#262acf80660d48c3b167fb0baabd0c3ab985c153" @@ -7230,13 +7402,6 @@ rollup-plugin-typescript2@^0.30.0: resolve "1.20.0" tslib "2.1.0" -rollup-pluginutils@^2.8.1: - version "2.8.2" - resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" - integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ== - dependencies: - estree-walker "^0.6.1" - rollup@^2.47.0: version "2.52.3" resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.52.3.tgz#062fc3c85f67736d6758749310cfee64836c4e2a" @@ -7268,7 +7433,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -7280,7 +7445,7 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -7658,10 +7823,18 @@ static-extend@^0.1.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= -store2@2.11.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/store2/-/store2-2.11.0.tgz#307636a239014ef4d8f1c8b47afe903509484fc8" - integrity sha512-WeIZ5+c/KzBSutSqOjUCAkk1qTLVBcYUuvrhNx8ndjLZKdZRfP6Vv7AOxlynuL6tVU/6zt6e2CTHwWI5KE+fKg== +store2@2.12.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/store2/-/store2-2.12.0.tgz#e1f1b7e1a59b6083b2596a8d067f6ee88fd4d3cf" + integrity sha512-7t+/wpKLanLzSnQPX8WAcuLCCeuSHoWdQuh9SB3xD0kNOM38DNf+0Oa+wmvxmYueRzkmh6IcdKFtvTa+ecgPDw== + +stream-browserify@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" + integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA== + dependencies: + inherits "~2.0.4" + readable-stream "^3.5.0" strict-uri-encode@^1.0.0: version "1.1.0" @@ -7813,17 +7986,17 @@ table@^6.0.9: strip-ansi "^6.0.0" tar@^4.0.2: - version "4.4.13" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" - integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== - dependencies: - chownr "^1.1.1" - fs-minipass "^1.2.5" - minipass "^2.8.6" - minizlib "^1.2.1" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.3" + version "4.4.19" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3" + integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA== + dependencies: + chownr "^1.1.4" + fs-minipass "^1.2.7" + minipass "^2.9.0" + minizlib "^1.3.3" + mkdirp "^0.5.5" + safe-buffer "^5.2.1" + yallist "^3.1.1" terminal-link@^2.0.0: version "2.1.1" @@ -7949,6 +8122,13 @@ tr46@^2.1.0: dependencies: punycode "^2.1.1" +tr46@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" + integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== + dependencies: + punycode "^2.1.1" + ts-node@^9.1.1: version "9.1.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d" @@ -8130,11 +8310,6 @@ unbox-primitive@^1.0.1: has-symbols "^1.0.2" which-boxed-primitive "^1.0.2" -underscore@1.12.1: - version "1.12.1" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.12.1.tgz#7bb8cc9b3d397e201cf8553336d262544ead829e" - integrity sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw== - unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" @@ -8344,6 +8519,13 @@ w3c-xmlserializer@^2.0.0: dependencies: xml-name-validator "^3.0.0" +w3c-xmlserializer@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz#06cdc3eefb7e4d0b20a560a5a3aeb0d2d9a65923" + integrity sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg== + dependencies: + xml-name-validator "^4.0.0" + walker@^1.0.7, walker@~1.0.5: version "1.0.7" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" @@ -8351,245 +8533,234 @@ walker@^1.0.7, walker@~1.0.5: dependencies: makeerror "1.0.x" -web3-bzz@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.3.6.tgz#95f370aecc3ff6ad07f057e6c0c916ef09b04dde" - integrity sha512-ibHdx1wkseujFejrtY7ZyC0QxQ4ATXjzcNUpaLrvM6AEae8prUiyT/OloG9FWDgFD2CPLwzKwfSQezYQlANNlw== +web3-bzz@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.6.0.tgz#584b51339f21eedff159abc9239b4b7ef6ded840" + integrity sha512-ugYV6BsinwhIi0CsLWINBz4mqN9wR9vNG0WmyEbdECjxcPyr6vkaWt4qi0zqlUxEnYAwGj4EJXNrbjPILntQTQ== dependencies: "@types/node" "^12.12.6" got "9.6.0" swarm-js "^0.1.40" - underscore "1.12.1" -web3-core-helpers@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.3.6.tgz#c478246a9abe4e5456acf42657dac2f7c330be74" - integrity sha512-nhtjA2ZbkppjlxTSwG0Ttu6FcPkVu1rCN5IFAOVpF/L0SEt+jy+O5l90+cjDq0jAYvlBwUwnbh2mR9hwDEJCNA== +web3-core-helpers@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.6.0.tgz#77e161b6ba930a4008a0df804ab379e0aa7e1e7f" + integrity sha512-H/IAH/0mrgvad/oxVKiAMC7qDzMrPPe/nRKmJOoIsupRg9/frvL62kZZiHhqVD1HMyyswbQFC69QRl7JqWzvxg== dependencies: - underscore "1.12.1" - web3-eth-iban "1.3.6" - web3-utils "1.3.6" + web3-eth-iban "1.6.0" + web3-utils "1.6.0" -web3-core-method@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.3.6.tgz#4b0334edd94b03dfec729d113c69a4eb6ebc68ae" - integrity sha512-RyegqVGxn0cyYW5yzAwkPlsSEynkdPiegd7RxgB4ak1eKk2Cv1q2x4C7D2sZjeeCEF+q6fOkVmo2OZNqS2iQxg== +web3-core-method@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.6.0.tgz#ebe4ea51f5a4fa809bb68185576186359d3982e9" + integrity sha512-cHekyEil4mtcCOk6Q1Zh4y+2o5pTwsLIxP6Bpt4BRtZgdsyPiadYJpkLAVT/quch5xN7Qs5ZwG5AvRCS3VwD2g== dependencies: + "@ethereumjs/common" "^2.4.0" "@ethersproject/transactions" "^5.0.0-beta.135" - underscore "1.12.1" - web3-core-helpers "1.3.6" - web3-core-promievent "1.3.6" - web3-core-subscriptions "1.3.6" - web3-utils "1.3.6" + web3-core-helpers "1.6.0" + web3-core-promievent "1.6.0" + web3-core-subscriptions "1.6.0" + web3-utils "1.6.0" -web3-core-promievent@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.3.6.tgz#6c27dc79de8f71b74f5d17acaf9aaf593d3cb0c9" - integrity sha512-Z+QzfyYDTXD5wJmZO5wwnRO8bAAHEItT1XNSPVb4J1CToV/I/SbF7CuF8Uzh2jns0Cm1109o666H7StFFvzVKw== +web3-core-promievent@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.6.0.tgz#8b6053ae83cb47164540167fc361469fc604d2dd" + integrity sha512-ZzsevjMXWkhqW9dnVfTfb1OUcK7jKcKPvPIbQ4boJccNgvNZPZKlo8xB4pkAX38n4c59O5mC7Lt/z2QL/M5CeQ== dependencies: eventemitter3 "4.0.4" -web3-core-requestmanager@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.3.6.tgz#4fea269fe913fd4fca464b4f7c65cb94857b5b2a" - integrity sha512-2rIaeuqeo7QN1Eex7aXP0ZqeteJEPWXYFS/M3r3LXMiV8R4STQBKE+//dnHJXoo2ctzEB5cgd+7NaJM8S3gPyA== +web3-core-requestmanager@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.6.0.tgz#8ef3a3b89cd08983bd94574f9c5893f70a8a6aea" + integrity sha512-CY5paPdiDXKTXPWaEUZekDfUXSuoE2vPxolwqzsvKwFWH5+H1NaXgrc+D5HpufgSvTXawTw0fy7IAicg8+PWqA== dependencies: - underscore "1.12.1" util "^0.12.0" - web3-core-helpers "1.3.6" - web3-providers-http "1.3.6" - web3-providers-ipc "1.3.6" - web3-providers-ws "1.3.6" + web3-core-helpers "1.6.0" + web3-providers-http "1.6.0" + web3-providers-ipc "1.6.0" + web3-providers-ws "1.6.0" -web3-core-subscriptions@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.3.6.tgz#ee24e7974d1d72ff6c992c599deba4ef9b308415" - integrity sha512-wi9Z9X5X75OKvxAg42GGIf81ttbNR2TxzkAsp1g+nnp5K8mBwgZvXrIsDuj7Z7gx72Y45mWJADCWjk/2vqNu8g== +web3-core-subscriptions@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.6.0.tgz#8c23b15b434a7c9f937652ecca45d7108e2c54df" + integrity sha512-kY9WZUY/m1URSOv3uTLshoZD9ZDiFKReIzHuPUkxFpD5oYNmr1/aPQNPCrrMxKODR7UVX/D90FxWwCYqHhLaxQ== dependencies: eventemitter3 "4.0.4" - underscore "1.12.1" - web3-core-helpers "1.3.6" + web3-core-helpers "1.6.0" -web3-core@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.3.6.tgz#a6a761d1ff2f3ee462b8dab679229d2f8e267504" - integrity sha512-gkLDM4T1Sc0T+HZIwxrNrwPg0IfWI0oABSglP2X5ZbBAYVUeEATA0o92LWV8BeF+okvKXLK1Fek/p6axwM/h3Q== +web3-core@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.6.0.tgz#144eb00f651c9812faf7176abd7ee99d5f45e212" + integrity sha512-o0WsLrJ2yD+HAAc29lGMWJef/MutTyuzpJC0UzLJtIAQJqtpDalzWINEu4j8XYXGk34N/V6vudtzRPo23QEE6g== dependencies: "@types/bn.js" "^4.11.5" "@types/node" "^12.12.6" bignumber.js "^9.0.0" - web3-core-helpers "1.3.6" - web3-core-method "1.3.6" - web3-core-requestmanager "1.3.6" - web3-utils "1.3.6" + web3-core-helpers "1.6.0" + web3-core-method "1.6.0" + web3-core-requestmanager "1.6.0" + web3-utils "1.6.0" -web3-eth-abi@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.3.6.tgz#4272ca48d817aa651bbf97b269f5ff10abc2b8a9" - integrity sha512-Or5cRnZu6WzgScpmbkvC6bfNxR26hqiKK4i8sMPFeTUABQcb/FU3pBj7huBLYbp9dH+P5W79D2MqwbWwjj9DoQ== +web3-eth-abi@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.6.0.tgz#4225608f61ebb0607d80849bb2b20f910780253d" + integrity sha512-fImomGE9McuTMJLwK8Tp0lTUzXqCkWeMm00qPVIwpJ/h7lCw9UFYV9+4m29wSqW6FF+FIZKwc6UBEf9dlx3orA== dependencies: "@ethersproject/abi" "5.0.7" - underscore "1.12.1" - web3-utils "1.3.6" + web3-utils "1.6.0" -web3-eth-accounts@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.3.6.tgz#f9fcb50b28ee58090ab292a10d996155caa2b474" - integrity sha512-Ilr0hG6ONbCdSlVKffasCmNwftD5HsNpwyQASevocIQwHdTlvlwO0tb3oGYuajbKOaDzNTwXfz25bttAEoFCGA== +web3-eth-accounts@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.6.0.tgz#530927f4c5b78df93b3ea1203abbb467de29cd04" + integrity sha512-2f6HS4KIH4laAsNCOfbNX3dRiQosqSY2TRK86C8jtAA/QKGdx+5qlPfYzbI2RjG81iayb2+mVbHIaEaBGZ8sGw== dependencies: + "@ethereumjs/common" "^2.3.0" + "@ethereumjs/tx" "^3.2.1" crypto-browserify "3.12.0" eth-lib "0.2.8" - ethereumjs-common "^1.3.2" - ethereumjs-tx "^2.1.1" + ethereumjs-util "^7.0.10" scrypt-js "^3.0.1" - underscore "1.12.1" uuid "3.3.2" - web3-core "1.3.6" - web3-core-helpers "1.3.6" - web3-core-method "1.3.6" - web3-utils "1.3.6" + web3-core "1.6.0" + web3-core-helpers "1.6.0" + web3-core-method "1.6.0" + web3-utils "1.6.0" -web3-eth-contract@1.3.6, web3-eth-contract@^1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.3.6.tgz#cccf4d32dc56917fb6923e778498a9ba2a5ba866" - integrity sha512-8gDaRrLF2HCg+YEZN1ov0zN35vmtPnGf3h1DxmJQK5Wm2lRMLomz9rsWsuvig3UJMHqZAQKD7tOl3ocJocQsmA== +web3-eth-contract@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.6.0.tgz#deb946867ad86d32bcbba899d733b681b25ea674" + integrity sha512-ZUtO77zFnxuFtrc+D+iJ3AzNgFXAVcKnhEYN7f1PNz/mFjbtE6dJ+ujO0mvMbxIZF02t9IZv0CIXRpK0rDvZAw== dependencies: "@types/bn.js" "^4.11.5" - underscore "1.12.1" - web3-core "1.3.6" - web3-core-helpers "1.3.6" - web3-core-method "1.3.6" - web3-core-promievent "1.3.6" - web3-core-subscriptions "1.3.6" - web3-eth-abi "1.3.6" - web3-utils "1.3.6" - -web3-eth-ens@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.3.6.tgz#0d28c5d4ea7b4462ef6c077545a77956a6cdf175" - integrity sha512-n27HNj7lpSkRxTgSx+Zo7cmKAgyg2ElFilaFlUu/X2CNH23lXfcPm2bWssivH9z0ndhg0OyR4AYFZqPaqDHkJA== + web3-core "1.6.0" + web3-core-helpers "1.6.0" + web3-core-method "1.6.0" + web3-core-promievent "1.6.0" + web3-core-subscriptions "1.6.0" + web3-eth-abi "1.6.0" + web3-utils "1.6.0" + +web3-eth-ens@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.6.0.tgz#af13852168d56fa71b9198eb097e96fb93831c2a" + integrity sha512-AG24PNv9qbYHSpjHcU2pViOII0jvIR7TeojJ2bxXSDqfcgHuRp3NZGKv6xFvT4uNI4LEQHUhSC7bzHoNF5t8CA== dependencies: content-hash "^2.5.2" eth-ens-namehash "2.0.8" - underscore "1.12.1" - web3-core "1.3.6" - web3-core-helpers "1.3.6" - web3-core-promievent "1.3.6" - web3-eth-abi "1.3.6" - web3-eth-contract "1.3.6" - web3-utils "1.3.6" - -web3-eth-iban@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.3.6.tgz#0d6ba21fe78f190af8919e9cd5453882457209e0" - integrity sha512-nfMQaaLA/zsg5W4Oy/EJQbs8rSs1vBAX6b/35xzjYoutXlpHMQadujDx2RerTKhSHqFXSJeQAfE+2f6mdhYkRQ== + web3-core "1.6.0" + web3-core-helpers "1.6.0" + web3-core-promievent "1.6.0" + web3-eth-abi "1.6.0" + web3-eth-contract "1.6.0" + web3-utils "1.6.0" + +web3-eth-iban@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.6.0.tgz#edbe46cedc5b148d53fa455edea6b4eef53b2be7" + integrity sha512-HM/bKBS/e8qg0+Eh7B8C/JVG+GkR4AJty17DKRuwMtrh78YsonPj7GKt99zS4n5sDLFww1Imu/ZIk3+K5uJCjw== dependencies: bn.js "^4.11.9" - web3-utils "1.3.6" + web3-utils "1.6.0" -web3-eth-personal@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.3.6.tgz#226137916754c498f0284f22c55924c87a2efcf0" - integrity sha512-pOHU0+/h1RFRYoh1ehYBehRbcKWP4OSzd4F7mDljhHngv6W8ewMHrAN8O1ol9uysN2MuCdRE19qkRg5eNgvzFQ== +web3-eth-personal@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.6.0.tgz#b75a61c0737b8b8bcc11d05db2ed7bfce7e4b262" + integrity sha512-8ohf4qAwbShf4RwES2tLHVqa+pHZnS5Q6tV80sU//bivmlZeyO1W4UWyNn59vu9KPpEYvLseOOC6Muxuvr8mFQ== dependencies: "@types/node" "^12.12.6" - web3-core "1.3.6" - web3-core-helpers "1.3.6" - web3-core-method "1.3.6" - web3-net "1.3.6" - web3-utils "1.3.6" + web3-core "1.6.0" + web3-core-helpers "1.6.0" + web3-core-method "1.6.0" + web3-net "1.6.0" + web3-utils "1.6.0" -web3-eth@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.3.6.tgz#2c650893d540a7a0eb1365dd5b2dca24ac919b7c" - integrity sha512-9+rnywRRpyX3C4hfsAQXPQh6vHh9XzQkgLxo3gyeXfbhbShUoq2gFVuy42vsRs//6JlsKdyZS7Z3hHPHz2wreA== - dependencies: - underscore "1.12.1" - web3-core "1.3.6" - web3-core-helpers "1.3.6" - web3-core-method "1.3.6" - web3-core-subscriptions "1.3.6" - web3-eth-abi "1.3.6" - web3-eth-accounts "1.3.6" - web3-eth-contract "1.3.6" - web3-eth-ens "1.3.6" - web3-eth-iban "1.3.6" - web3-eth-personal "1.3.6" - web3-net "1.3.6" - web3-utils "1.3.6" - -web3-net@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.3.6.tgz#a56492e2227475e38db29394f8bac305a2446e41" - integrity sha512-KhzU3wMQY/YYjyMiQzbaLPt2kut88Ncx2iqjy3nw28vRux3gVX0WOCk9EL/KVJBiAA/fK7VklTXvgy9dZnnipw== +web3-eth@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.6.0.tgz#4c9d5fb4eccf9f8744828281757e6ea76af58cbd" + integrity sha512-qJMvai//r0be6I9ghU24/152f0zgJfYC23TMszN3Y6jse1JtjCBP2TlTibFcvkUN1RRdIUY5giqO7ZqAYAmp7w== + dependencies: + web3-core "1.6.0" + web3-core-helpers "1.6.0" + web3-core-method "1.6.0" + web3-core-subscriptions "1.6.0" + web3-eth-abi "1.6.0" + web3-eth-accounts "1.6.0" + web3-eth-contract "1.6.0" + web3-eth-ens "1.6.0" + web3-eth-iban "1.6.0" + web3-eth-personal "1.6.0" + web3-net "1.6.0" + web3-utils "1.6.0" + +web3-net@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.6.0.tgz#2c28f8787073110a7c2310336889d2dad647e500" + integrity sha512-LFfG95ovTT2sNHkO1TEfsaKpYcxOSUtbuwHQ0K3G0e5nevKDJkPEFIqIcob40yiwcWoqEjENJP9Bjk8CRrZ99Q== dependencies: - web3-core "1.3.6" - web3-core-method "1.3.6" - web3-utils "1.3.6" + web3-core "1.6.0" + web3-core-method "1.6.0" + web3-utils "1.6.0" -web3-providers-http@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.3.6.tgz#36e8724a7424d52827819d53fd75dbf31f5422c2" - integrity sha512-OQkT32O1A06dISIdazpGLveZcOXhEo5cEX6QyiSQkiPk/cjzDrXMw4SKZOGQbbS1+0Vjizm1Hrp7O8Vp2D1M5Q== +web3-providers-http@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.6.0.tgz#8db4e589abf7197f5d65b12af1bf9726c45f4160" + integrity sha512-sNxHFNv3lnxpmULt34AS6M36IYB/Hzm2Et4yPNzdP1XE644D8sQBZQZaJQdTaza5HfrlwoqU6AOK935armqGuA== dependencies: - web3-core-helpers "1.3.6" + web3-core-helpers "1.6.0" xhr2-cookies "1.1.0" -web3-providers-ipc@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.3.6.tgz#cef8d12c1ebb47adce5ebf597f553c623362cb4a" - integrity sha512-+TVsSd2sSVvVgHG4s6FXwwYPPT91boKKcRuEFXqEfAbUC5t52XOgmyc2LNiD9LzPhed65FbV4LqICpeYGUvSwA== +web3-providers-ipc@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.6.0.tgz#6a3410fd47a67c4a36719fb97f99534ae12aac98" + integrity sha512-ETYdfhpGiGoWpmmSJnONvnPfd3TPivHEGjXyuX+L5FUsbMOVZj9MFLNIS19Cx/YGL8UWJ/8alLJoTcWSIdz/aA== dependencies: oboe "2.1.5" - underscore "1.12.1" - web3-core-helpers "1.3.6" + web3-core-helpers "1.6.0" -web3-providers-ws@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.3.6.tgz#e1df617bc89d66165abdf2191da0014c505bfaac" - integrity sha512-bk7MnJf5or0Re2zKyhR3L3CjGululLCHXx4vlbc/drnaTARUVvi559OI5uLytc/1k5HKUUyENAxLvetz2G1dnQ== +web3-providers-ws@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.6.0.tgz#dc15dc18c30089efda992015fd5254bd2b77af5f" + integrity sha512-eNRmlhOPCpuVYwBrKBBQRLGPFb4U1Uo44r9EWV69Cpo4gP6XeBTl6nkawhLz6DS0fq79apyPfItJVuSfAy77pA== dependencies: eventemitter3 "4.0.4" - underscore "1.12.1" - web3-core-helpers "1.3.6" + web3-core-helpers "1.6.0" websocket "^1.0.32" -web3-shh@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.3.6.tgz#4e3486c7eca5cbdb87f88910948223a5b7ea6c20" - integrity sha512-9zRo415O0iBslxBnmu9OzYjNErzLnzOsy+IOvSpIreLYbbAw0XkDWxv3SfcpKnTIWIACBR4AYMIxmmyi5iB3jw== +web3-shh@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.6.0.tgz#838a3435dce1039f669a48e53e948062de197931" + integrity sha512-ymN0OFL81WtEeSyb+PFpuUv39fR3frGwsZnIg5EVPZvrOIdaDSFcGSLDmafUt0vKSubvLMVYIBOCskRD6YdtEQ== dependencies: - web3-core "1.3.6" - web3-core-method "1.3.6" - web3-core-subscriptions "1.3.6" - web3-net "1.3.6" + web3-core "1.6.0" + web3-core-method "1.6.0" + web3-core-subscriptions "1.6.0" + web3-net "1.6.0" -web3-utils@1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.3.6.tgz#390bc9fa3a7179746963cfaca55bb80ac4d8dc10" - integrity sha512-hHatFaQpkQgjGVER17gNx8u1qMyaXFZtM0y0XLGH1bzsjMPlkMPLRcYOrZ00rOPfTEuYFOdrpGOqZXVmGrMZRg== +web3-utils@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.6.0.tgz#1975c5ee5b7db8a0836eb7004848a7cd962d1ddc" + integrity sha512-bgCAWAeQnJF035YTFxrcHJ5mGEfTi/McsjqldZiXRwlHK7L1PyOqvXiQLE053dlzvy1kdAxWl/sSSfLMyNUAXg== dependencies: bn.js "^4.11.9" - eth-lib "0.2.8" ethereum-bloom-filters "^1.0.6" + ethereumjs-util "^7.1.0" ethjs-unit "0.1.6" number-to-bn "1.7.0" randombytes "^2.1.0" - underscore "1.12.1" utf8 "3.0.0" -web3@^1.3.5: - version "1.3.6" - resolved "https://registry.yarnpkg.com/web3/-/web3-1.3.6.tgz#599425461c3f9a8cbbefa70616438995f4a064cc" - integrity sha512-jEpPhnL6GDteifdVh7ulzlPrtVQeA30V9vnki9liYlUvLV82ZM7BNOQJiuzlDePuE+jZETZSP/0G/JlUVt6pOA== +web3@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/web3/-/web3-1.6.0.tgz#d8fa0cd9e7bf252f9fe43bb77dc42bc6671affde" + integrity sha512-rWpXnO88MiVX5yTRqMBCVKASxc7QDkXZZUl1D48sKlbX4dt3BAV+nVMVUKCBKiluZ5Bp8pDrVCUdPx/jIYai5Q== dependencies: - web3-bzz "1.3.6" - web3-core "1.3.6" - web3-eth "1.3.6" - web3-eth-personal "1.3.6" - web3-net "1.3.6" - web3-shh "1.3.6" - web3-utils "1.3.6" + web3-bzz "1.6.0" + web3-core "1.6.0" + web3-eth "1.6.0" + web3-eth-personal "1.6.0" + web3-net "1.6.0" + web3-shh "1.6.0" + web3-utils "1.6.0" webidl-conversions@^5.0.0: version "5.0.0" @@ -8601,6 +8772,11 @@ webidl-conversions@^6.1.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + websocket@^1.0.32: version "1.0.34" resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.34.tgz#2bdc2602c08bf2c82253b730655c0ef7dcab3111" @@ -8620,11 +8796,31 @@ whatwg-encoding@^1.0.5: dependencies: iconv-lite "0.4.24" +whatwg-encoding@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz#e7635f597fd87020858626805a2729fa7698ac53" + integrity sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg== + dependencies: + iconv-lite "0.6.3" + whatwg-mimetype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== +whatwg-mimetype@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7" + integrity sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q== + +whatwg-url@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-10.0.0.tgz#37264f720b575b4a311bd4094ed8c760caaa05da" + integrity sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w== + dependencies: + tr46 "^3.0.0" + webidl-conversions "^7.0.0" + whatwg-url@^8.0.0, whatwg-url@^8.5.0: version "8.7.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" @@ -8732,6 +8928,11 @@ ws@7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== +ws@8.2.3: + version "8.2.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" + integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA== + ws@^3.0.0: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" @@ -8741,11 +8942,16 @@ ws@^3.0.0: safe-buffer "~5.1.0" ultron "~1.1.0" -ws@^7.4.5, ws@^7.4.6: +ws@^7.4.5: version "7.5.1" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.1.tgz#44fc000d87edb1d9c53e51fbc69a0ac1f6871d66" integrity sha512-2c6faOUH/nhoQN6abwMloF7Iyl0ZS2E9HGtsiLrWn0zOOMWlhtDmdf/uihDt6jnuCxgtwGBNy6Onsoy2s2O2Ow== +ws@^8.2.3: + version "8.3.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.3.0.tgz#7185e252c8973a60d57170175ff55fdbd116070d" + integrity sha512-Gs5EZtpqZzLvmIM59w4igITU57lrtYVFneaa434VROv4thzJyV6UjIL3D42lslWlI+D4KzLYnxSwtfuiO79sNw== + xhr-request-promise@^0.1.2: version "0.1.3" resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz#2d5f4b16d8c6c893be97f1a62b0ed4cf3ca5f96c" @@ -8788,6 +8994,11 @@ xml-name-validator@^3.0.0: resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== +xml-name-validator@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835" + integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw== + xmlchars@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" @@ -8816,7 +9027,7 @@ yaeti@^0.0.6: resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" integrity sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc= -yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: +yallist@^3.0.0, yallist@^3.0.2, yallist@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==