@uswap/toolboxes 4.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/cardano/index.cjs +4 -0
- package/dist/src/cardano/index.cjs.map +11 -0
- package/dist/src/cardano/index.js +4 -0
- package/dist/src/cardano/index.js.map +11 -0
- package/dist/src/cosmos/index.cjs +4 -0
- package/dist/src/cosmos/index.cjs.map +20 -0
- package/dist/src/cosmos/index.js +4 -0
- package/dist/src/cosmos/index.js.map +20 -0
- package/dist/src/evm/index.cjs +4 -0
- package/dist/src/evm/index.cjs.map +20 -0
- package/dist/src/evm/index.js +4 -0
- package/dist/src/evm/index.js.map +20 -0
- package/dist/src/index.cjs +5 -0
- package/dist/src/index.cjs.map +67 -0
- package/dist/src/index.js +5 -0
- package/dist/src/index.js.map +67 -0
- package/dist/src/near/index.cjs +4 -0
- package/dist/src/near/index.cjs.map +16 -0
- package/dist/src/near/index.js +4 -0
- package/dist/src/near/index.js.map +16 -0
- package/dist/src/radix/index.cjs +4 -0
- package/dist/src/radix/index.cjs.map +10 -0
- package/dist/src/radix/index.js +4 -0
- package/dist/src/radix/index.js.map +10 -0
- package/dist/src/ripple/index.cjs +4 -0
- package/dist/src/ripple/index.cjs.map +10 -0
- package/dist/src/ripple/index.js +4 -0
- package/dist/src/ripple/index.js.map +10 -0
- package/dist/src/solana/index.cjs +4 -0
- package/dist/src/solana/index.cjs.map +11 -0
- package/dist/src/solana/index.js +4 -0
- package/dist/src/solana/index.js.map +11 -0
- package/dist/src/substrate/index.cjs +4 -0
- package/dist/src/substrate/index.cjs.map +13 -0
- package/dist/src/substrate/index.js +4 -0
- package/dist/src/substrate/index.js.map +13 -0
- package/dist/src/sui/index.cjs +4 -0
- package/dist/src/sui/index.cjs.map +11 -0
- package/dist/src/sui/index.js +4 -0
- package/dist/src/sui/index.js.map +11 -0
- package/dist/src/ton/index.cjs +4 -0
- package/dist/src/ton/index.cjs.map +11 -0
- package/dist/src/ton/index.js +4 -0
- package/dist/src/ton/index.js.map +11 -0
- package/dist/src/tron/index.cjs +4 -0
- package/dist/src/tron/index.cjs.map +13 -0
- package/dist/src/tron/index.js +4 -0
- package/dist/src/tron/index.js.map +13 -0
- package/dist/src/utxo/index.cjs +5 -0
- package/dist/src/utxo/index.cjs.map +21 -0
- package/dist/src/utxo/index.js +5 -0
- package/dist/src/utxo/index.js.map +21 -0
- package/dist/types/cardano/index.d.ts +3 -0
- package/dist/types/cardano/index.d.ts.map +1 -0
- package/dist/types/cardano/toolbox.d.ts +34 -0
- package/dist/types/cardano/toolbox.d.ts.map +1 -0
- package/dist/types/cardano/types.d.ts +11 -0
- package/dist/types/cardano/types.d.ts.map +1 -0
- package/dist/types/cosmos/index.d.ts +5 -0
- package/dist/types/cosmos/index.d.ts.map +1 -0
- package/dist/types/cosmos/thorchainUtils/addressFormat.d.ts +5 -0
- package/dist/types/cosmos/thorchainUtils/addressFormat.d.ts.map +1 -0
- package/dist/types/cosmos/thorchainUtils/index.d.ts +5 -0
- package/dist/types/cosmos/thorchainUtils/index.d.ts.map +1 -0
- package/dist/types/cosmos/thorchainUtils/messages.d.ts +208 -0
- package/dist/types/cosmos/thorchainUtils/messages.d.ts.map +1 -0
- package/dist/types/cosmos/thorchainUtils/registry.d.ts +4 -0
- package/dist/types/cosmos/thorchainUtils/registry.d.ts.map +1 -0
- package/dist/types/cosmos/thorchainUtils/types/MsgCompiled.d.ts +2 -0
- package/dist/types/cosmos/thorchainUtils/types/MsgCompiled.d.ts.map +1 -0
- package/dist/types/cosmos/thorchainUtils/types/client-types.d.ts +63 -0
- package/dist/types/cosmos/thorchainUtils/types/client-types.d.ts.map +1 -0
- package/dist/types/cosmos/thorchainUtils/types/index.d.ts +2 -0
- package/dist/types/cosmos/thorchainUtils/types/index.d.ts.map +1 -0
- package/dist/types/cosmos/toolbox/cosmos.d.ts +62 -0
- package/dist/types/cosmos/toolbox/cosmos.d.ts.map +1 -0
- package/dist/types/cosmos/toolbox/index.d.ts +15 -0
- package/dist/types/cosmos/toolbox/index.d.ts.map +1 -0
- package/dist/types/cosmos/toolbox/thorchain.d.ts +158 -0
- package/dist/types/cosmos/toolbox/thorchain.d.ts.map +1 -0
- package/dist/types/cosmos/types.d.ts +49 -0
- package/dist/types/cosmos/types.d.ts.map +1 -0
- package/dist/types/cosmos/util.d.ts +74 -0
- package/dist/types/cosmos/util.d.ts.map +1 -0
- package/dist/types/evm/api.d.ts +8 -0
- package/dist/types/evm/api.d.ts.map +1 -0
- package/dist/types/evm/contracts/eth/multicall.d.ts +36 -0
- package/dist/types/evm/contracts/eth/multicall.d.ts.map +1 -0
- package/dist/types/evm/contracts/op/gasOracle.d.ts +40 -0
- package/dist/types/evm/contracts/op/gasOracle.d.ts.map +1 -0
- package/dist/types/evm/helpers.d.ts +6 -0
- package/dist/types/evm/helpers.d.ts.map +1 -0
- package/dist/types/evm/index.d.ts +5 -0
- package/dist/types/evm/index.d.ts.map +1 -0
- package/dist/types/evm/toolbox/baseEVMToolbox.d.ts +83 -0
- package/dist/types/evm/toolbox/baseEVMToolbox.d.ts.map +1 -0
- package/dist/types/evm/toolbox/evm.d.ts +767 -0
- package/dist/types/evm/toolbox/evm.d.ts.map +1 -0
- package/dist/types/evm/toolbox/index.d.ts +7 -0
- package/dist/types/evm/toolbox/index.d.ts.map +1 -0
- package/dist/types/evm/toolbox/op.d.ts +76 -0
- package/dist/types/evm/toolbox/op.d.ts.map +1 -0
- package/dist/types/evm/types.d.ts +108 -0
- package/dist/types/evm/types.d.ts.map +1 -0
- package/dist/types/index.d.ts +75 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/near/helpers/core.d.ts +15 -0
- package/dist/types/near/helpers/core.d.ts.map +1 -0
- package/dist/types/near/helpers/gasEstimation.d.ts +41 -0
- package/dist/types/near/helpers/gasEstimation.d.ts.map +1 -0
- package/dist/types/near/helpers/nep141.d.ts +36 -0
- package/dist/types/near/helpers/nep141.d.ts.map +1 -0
- package/dist/types/near/index.d.ts +10 -0
- package/dist/types/near/index.d.ts.map +1 -0
- package/dist/types/near/toolbox.d.ts +32 -0
- package/dist/types/near/toolbox.d.ts.map +1 -0
- package/dist/types/near/types/contract.d.ts +38 -0
- package/dist/types/near/types/contract.d.ts.map +1 -0
- package/dist/types/near/types/nep141.d.ts +29 -0
- package/dist/types/near/types/nep141.d.ts.map +1 -0
- package/dist/types/near/types/toolbox.d.ts +51 -0
- package/dist/types/near/types/toolbox.d.ts.map +1 -0
- package/dist/types/near/types.d.ts +47 -0
- package/dist/types/near/types.d.ts.map +1 -0
- package/dist/types/radix/index.d.ts +14 -0
- package/dist/types/radix/index.d.ts.map +1 -0
- package/dist/types/ripple/index.d.ts +46 -0
- package/dist/types/ripple/index.d.ts.map +1 -0
- package/dist/types/solana/index.d.ts +23 -0
- package/dist/types/solana/index.d.ts.map +1 -0
- package/dist/types/solana/toolbox.d.ts +51 -0
- package/dist/types/solana/toolbox.d.ts.map +1 -0
- package/dist/types/substrate/balance.d.ts +17 -0
- package/dist/types/substrate/balance.d.ts.map +1 -0
- package/dist/types/substrate/index.d.ts +3 -0
- package/dist/types/substrate/index.d.ts.map +1 -0
- package/dist/types/substrate/substrate.d.ts +148 -0
- package/dist/types/substrate/substrate.d.ts.map +1 -0
- package/dist/types/substrate/types.d.ts +100 -0
- package/dist/types/substrate/types.d.ts.map +1 -0
- package/dist/types/sui/index.d.ts +3 -0
- package/dist/types/sui/index.d.ts.map +1 -0
- package/dist/types/sui/toolbox.d.ts +19 -0
- package/dist/types/sui/toolbox.d.ts.map +1 -0
- package/dist/types/sui/types.d.ts +16 -0
- package/dist/types/sui/types.d.ts.map +1 -0
- package/dist/types/ton/index.d.ts +3 -0
- package/dist/types/ton/index.d.ts.map +1 -0
- package/dist/types/ton/toolbox.d.ts +14 -0
- package/dist/types/ton/toolbox.d.ts.map +1 -0
- package/dist/types/ton/types.d.ts +22 -0
- package/dist/types/ton/types.d.ts.map +1 -0
- package/dist/types/tron/helpers/trc20.abi.d.ts +156 -0
- package/dist/types/tron/helpers/trc20.abi.d.ts.map +1 -0
- package/dist/types/tron/helpers/trongrid.d.ts +8 -0
- package/dist/types/tron/helpers/trongrid.d.ts.map +1 -0
- package/dist/types/tron/index.d.ts +6 -0
- package/dist/types/tron/index.d.ts.map +1 -0
- package/dist/types/tron/toolbox.d.ts +26 -0
- package/dist/types/tron/toolbox.d.ts.map +1 -0
- package/dist/types/tron/types.d.ts +103 -0
- package/dist/types/tron/types.d.ts.map +1 -0
- package/dist/types/types.d.ts +26 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/utils.d.ts +4 -0
- package/dist/types/utils.d.ts.map +1 -0
- package/dist/types/utxo/helpers/api.d.ts +101 -0
- package/dist/types/utxo/helpers/api.d.ts.map +1 -0
- package/dist/types/utxo/helpers/bchaddrjs.d.ts +10 -0
- package/dist/types/utxo/helpers/bchaddrjs.d.ts.map +1 -0
- package/dist/types/utxo/helpers/coinselect.d.ts +17 -0
- package/dist/types/utxo/helpers/coinselect.d.ts.map +1 -0
- package/dist/types/utxo/helpers/index.d.ts +5 -0
- package/dist/types/utxo/helpers/index.d.ts.map +1 -0
- package/dist/types/utxo/helpers/txSize.d.ts +21 -0
- package/dist/types/utxo/helpers/txSize.d.ts.map +1 -0
- package/dist/types/utxo/index.d.ts +7 -0
- package/dist/types/utxo/index.d.ts.map +1 -0
- package/dist/types/utxo/toolbox/bitcoinCash.d.ts +93 -0
- package/dist/types/utxo/toolbox/bitcoinCash.d.ts.map +1 -0
- package/dist/types/utxo/toolbox/index.d.ts +28 -0
- package/dist/types/utxo/toolbox/index.d.ts.map +1 -0
- package/dist/types/utxo/toolbox/params.d.ts +32 -0
- package/dist/types/utxo/toolbox/params.d.ts.map +1 -0
- package/dist/types/utxo/toolbox/utxo.d.ts +103 -0
- package/dist/types/utxo/toolbox/utxo.d.ts.map +1 -0
- package/dist/types/utxo/toolbox/validators.d.ts +4 -0
- package/dist/types/utxo/toolbox/validators.d.ts.map +1 -0
- package/dist/types/utxo/toolbox/zcash.d.ts +72 -0
- package/dist/types/utxo/toolbox/zcash.d.ts.map +1 -0
- package/dist/types/utxo/types.d.ts +46 -0
- package/dist/types/utxo/types.d.ts.map +1 -0
- package/package.json +205 -0
- package/src/__tests__/address-validation-all-chains.test.ts +162 -0
- package/src/__tests__/addressValidator.test.ts +162 -0
- package/src/cardano/__tests__/toolbox.test.ts +48 -0
- package/src/cardano/index.ts +2 -0
- package/src/cardano/toolbox.ts +168 -0
- package/src/cardano/types.ts +10 -0
- package/src/cosmos/__tests__/toolbox.test.ts +91 -0
- package/src/cosmos/index.ts +4 -0
- package/src/cosmos/thorchainUtils/addressFormat.ts +22 -0
- package/src/cosmos/thorchainUtils/index.ts +4 -0
- package/src/cosmos/thorchainUtils/messages.ts +212 -0
- package/src/cosmos/thorchainUtils/registry.ts +43 -0
- package/src/cosmos/thorchainUtils/types/MsgCompiled.ts +2800 -0
- package/src/cosmos/thorchainUtils/types/client-types.ts +54 -0
- package/src/cosmos/thorchainUtils/types/index.ts +1 -0
- package/src/cosmos/toolbox/cosmos.ts +345 -0
- package/src/cosmos/toolbox/index.ts +35 -0
- package/src/cosmos/toolbox/thorchain.ts +249 -0
- package/src/cosmos/types.ts +48 -0
- package/src/cosmos/util.ts +214 -0
- package/src/evm/__tests__/address-validation.test.ts +84 -0
- package/src/evm/__tests__/ethereum.test.ts +137 -0
- package/src/evm/__tests__/signMessage.test.ts +60 -0
- package/src/evm/api.ts +10 -0
- package/src/evm/contracts/eth/multicall.ts +165 -0
- package/src/evm/contracts/op/gasOracle.ts +145 -0
- package/src/evm/helpers.ts +73 -0
- package/src/evm/index.ts +4 -0
- package/src/evm/toolbox/baseEVMToolbox.ts +695 -0
- package/src/evm/toolbox/evm.ts +67 -0
- package/src/evm/toolbox/index.ts +44 -0
- package/src/evm/toolbox/op.ts +156 -0
- package/src/evm/types.ts +146 -0
- package/src/index.ts +260 -0
- package/src/near/__tests__/core.test.ts +70 -0
- package/src/near/helpers/core.ts +85 -0
- package/src/near/helpers/gasEstimation.ts +96 -0
- package/src/near/helpers/nep141.ts +50 -0
- package/src/near/index.ts +21 -0
- package/src/near/toolbox.ts +421 -0
- package/src/near/types/contract.ts +32 -0
- package/src/near/types/nep141.ts +34 -0
- package/src/near/types/toolbox.ts +55 -0
- package/src/near/types.ts +44 -0
- package/src/radix/index.ts +132 -0
- package/src/ripple/index.ts +179 -0
- package/src/solana/index.ts +36 -0
- package/src/solana/toolbox.ts +415 -0
- package/src/substrate/balance.ts +88 -0
- package/src/substrate/index.ts +2 -0
- package/src/substrate/substrate.ts +281 -0
- package/src/substrate/types.ts +115 -0
- package/src/sui/__tests__/toolbox.test.ts +82 -0
- package/src/sui/index.ts +2 -0
- package/src/sui/toolbox.ts +165 -0
- package/src/sui/types.ts +11 -0
- package/src/ton/__tests__/toolbox.test.ts +63 -0
- package/src/ton/index.ts +2 -0
- package/src/ton/toolbox.ts +136 -0
- package/src/ton/types.ts +13 -0
- package/src/tron/__tests__/toolbox.test.ts +221 -0
- package/src/tron/helpers/trc20.abi.ts +107 -0
- package/src/tron/helpers/trongrid.ts +53 -0
- package/src/tron/index.ts +21 -0
- package/src/tron/toolbox.ts +585 -0
- package/src/tron/types.ts +83 -0
- package/src/types.ts +28 -0
- package/src/utils.ts +27 -0
- package/src/utxo/__tests__/zcash-integration.test.ts +97 -0
- package/src/utxo/helpers/api.ts +471 -0
- package/src/utxo/helpers/bchaddrjs.ts +166 -0
- package/src/utxo/helpers/coinselect.ts +92 -0
- package/src/utxo/helpers/index.ts +4 -0
- package/src/utxo/helpers/txSize.ts +137 -0
- package/src/utxo/index.ts +6 -0
- package/src/utxo/toolbox/bitcoinCash.ts +243 -0
- package/src/utxo/toolbox/index.ts +59 -0
- package/src/utxo/toolbox/params.ts +18 -0
- package/src/utxo/toolbox/utxo.ts +439 -0
- package/src/utxo/toolbox/validators.ts +36 -0
- package/src/utxo/toolbox/zcash.ts +245 -0
- package/src/utxo/types.ts +39 -0
|
@@ -0,0 +1,695 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Asset,
|
|
3
|
+
AssetValue,
|
|
4
|
+
applyFeeMultiplierToBigInt,
|
|
5
|
+
Chain,
|
|
6
|
+
type ChainSigner,
|
|
7
|
+
type EVMChain,
|
|
8
|
+
EVMChains,
|
|
9
|
+
FeeOption,
|
|
10
|
+
isGasAsset,
|
|
11
|
+
SwapKitError,
|
|
12
|
+
SwapKitNumber,
|
|
13
|
+
} from "@uswap/helpers";
|
|
14
|
+
import { erc20ABI } from "@uswap/helpers/contracts";
|
|
15
|
+
import {
|
|
16
|
+
BrowserProvider,
|
|
17
|
+
Contract,
|
|
18
|
+
type ContractTransaction,
|
|
19
|
+
type Fragment,
|
|
20
|
+
getAddress,
|
|
21
|
+
type HDNodeWallet,
|
|
22
|
+
Interface,
|
|
23
|
+
type JsonFragment,
|
|
24
|
+
type JsonRpcSigner,
|
|
25
|
+
type Provider,
|
|
26
|
+
type Signer,
|
|
27
|
+
} from "ethers";
|
|
28
|
+
import { match } from "ts-pattern";
|
|
29
|
+
import { toHexString } from "../helpers";
|
|
30
|
+
import type {
|
|
31
|
+
ApproveParams,
|
|
32
|
+
CallParams,
|
|
33
|
+
EIP1559TxParams,
|
|
34
|
+
EstimateCallParams,
|
|
35
|
+
EVMCreateTransactionParams,
|
|
36
|
+
EVMTransferParams,
|
|
37
|
+
EVMTxParams,
|
|
38
|
+
IsApprovedParams,
|
|
39
|
+
LegacyEVMTxParams,
|
|
40
|
+
} from "../types";
|
|
41
|
+
|
|
42
|
+
type ToolboxWrapParams<P = Provider | BrowserProvider, T = {}> = T & {
|
|
43
|
+
isEIP1559Compatible?: boolean;
|
|
44
|
+
provider: P;
|
|
45
|
+
signer?: Signer;
|
|
46
|
+
chain: EVMChain;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const MAX_APPROVAL = BigInt("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
|
50
|
+
|
|
51
|
+
export function BaseEVMToolbox<
|
|
52
|
+
P extends Provider | BrowserProvider,
|
|
53
|
+
S extends (ChainSigner<EVMTransferParams, string> & Signer) | JsonRpcSigner | HDNodeWallet | undefined,
|
|
54
|
+
>({
|
|
55
|
+
chain = Chain.Ethereum,
|
|
56
|
+
provider,
|
|
57
|
+
signer,
|
|
58
|
+
isEIP1559Compatible = true,
|
|
59
|
+
}: {
|
|
60
|
+
signer: S;
|
|
61
|
+
provider: P;
|
|
62
|
+
isEIP1559Compatible?: boolean;
|
|
63
|
+
chain?: EVMChain;
|
|
64
|
+
}) {
|
|
65
|
+
return {
|
|
66
|
+
approve: getApprove({ chain, isEIP1559Compatible, provider, signer }),
|
|
67
|
+
approvedAmount: getApprovedAmount({ chain, provider }),
|
|
68
|
+
broadcastTransaction: provider.broadcastTransaction,
|
|
69
|
+
call: getCall({ chain, isEIP1559Compatible, provider, signer }),
|
|
70
|
+
createApprovalTx: getCreateApprovalTx({ chain, provider, signer }),
|
|
71
|
+
createContract: getCreateContract({ chain, provider }),
|
|
72
|
+
createContractTxObject: getCreateContractTxObject({ chain, provider }),
|
|
73
|
+
createTransaction: getCreateTransferTx({ chain, provider, signer }),
|
|
74
|
+
createTransferTx: getCreateTransferTx({ chain, provider, signer }),
|
|
75
|
+
EIP1193SendTransaction: getEIP1193SendTransaction(provider),
|
|
76
|
+
estimateCall: getEstimateCall({ provider, signer }),
|
|
77
|
+
estimateGasLimit: getEstimateGasLimit({ chain, provider, signer }),
|
|
78
|
+
estimateGasPrices: getEstimateGasPrices({ chain, isEIP1559Compatible, provider }),
|
|
79
|
+
estimateTransactionFee: getEstimateTransactionFee({ chain, isEIP1559Compatible, provider }),
|
|
80
|
+
getAddress: () => {
|
|
81
|
+
return signer ? signer.getAddress() : undefined;
|
|
82
|
+
},
|
|
83
|
+
isApproved: getIsApproved({ chain, provider }),
|
|
84
|
+
sendTransaction: getSendTransaction({ chain, isEIP1559Compatible, provider, signer }),
|
|
85
|
+
signMessage: signer ? (message: string | Uint8Array) => signer.signMessage(message) : undefined,
|
|
86
|
+
transfer: getTransfer({ chain, isEIP1559Compatible, provider, signer }),
|
|
87
|
+
validateAddress: (address: string) => evmValidateAddress({ address }),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function evmValidateAddress({ address }: { address: string }) {
|
|
92
|
+
try {
|
|
93
|
+
getAddress(address);
|
|
94
|
+
return true;
|
|
95
|
+
} catch {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function isBrowserProvider(provider: any) {
|
|
101
|
+
return provider instanceof BrowserProvider;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function createContract(address: string, abi: readonly (JsonFragment | Fragment)[], provider: Provider) {
|
|
105
|
+
return new Contract(address, Interface.from(abi), provider);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function getCreateContract({ provider }: ToolboxWrapParams) {
|
|
109
|
+
return function createContract(address: string, abi: readonly (JsonFragment | Fragment)[]) {
|
|
110
|
+
return new Contract(address, Interface.from(abi), provider);
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const stateMutable = ["payable", "nonpayable"];
|
|
115
|
+
// const nonStateMutable = ['view', 'pure'];
|
|
116
|
+
export function isStateChangingCall({ abi, funcName }: { abi: readonly JsonFragment[]; funcName: string }) {
|
|
117
|
+
const abiFragment = abi.find((fragment: any) => fragment.name === funcName) as any;
|
|
118
|
+
if (!abiFragment) throw new SwapKitError("toolbox_evm_no_abi_fragment", { funcName });
|
|
119
|
+
return abiFragment.stateMutability && stateMutable.includes(abiFragment.stateMutability);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function toChecksumAddress(address: string) {
|
|
123
|
+
return getAddress(address);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function getEIP1193SendTransaction(provider: Provider | BrowserProvider) {
|
|
127
|
+
return function EIP1193SendTransaction({ value, ...params }: EVMTxParams | ContractTransaction): Promise<string> {
|
|
128
|
+
if (!isBrowserProvider(provider)) {
|
|
129
|
+
throw new SwapKitError("toolbox_evm_provider_not_eip1193_compatible");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Remove gas-related parameters to let the wallet estimate them
|
|
133
|
+
// EIP-1193 providers (MetaMask, etc.) will estimate these automatically
|
|
134
|
+
const {
|
|
135
|
+
gasLimit: _gasLimit,
|
|
136
|
+
gasPrice: _gasPrice,
|
|
137
|
+
maxFeePerGas: _maxFeePerGas,
|
|
138
|
+
maxPriorityFeePerGas: _maxPriorityFeePerGas,
|
|
139
|
+
...cleanParams
|
|
140
|
+
} = params as any;
|
|
141
|
+
|
|
142
|
+
return (provider as BrowserProvider).send("eth_sendTransaction", [
|
|
143
|
+
{ ...cleanParams, value: toHexString(BigInt(value || 0)) } as any,
|
|
144
|
+
]);
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function getChecksumAddressFromAsset(asset: Asset, chain: EVMChain) {
|
|
149
|
+
const assetAddress = getTokenAddress(asset, chain);
|
|
150
|
+
|
|
151
|
+
if (assetAddress) {
|
|
152
|
+
return getAddress(assetAddress.toLowerCase());
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
throw new SwapKitError("toolbox_evm_invalid_gas_asset_address");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const baseContractAddresses = EVMChains.reduce(
|
|
159
|
+
(acc, chain) => {
|
|
160
|
+
acc[chain] = "0x0000000000000000000000000000000000000000";
|
|
161
|
+
return acc;
|
|
162
|
+
},
|
|
163
|
+
{} as Record<EVMChain, string>,
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
export const ContractAddress: Record<EVMChain, string> = {
|
|
167
|
+
...baseContractAddresses,
|
|
168
|
+
[Chain.Optimism]: "0x4200000000000000000000000000000000000042",
|
|
169
|
+
[Chain.Polygon]: "0x0000000000000000000000000000000000001010",
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const ethGasChains = [Chain.Arbitrum, Chain.Aurora, Chain.Base, Chain.Optimism] as string[];
|
|
173
|
+
|
|
174
|
+
export function getTokenAddress({ chain, symbol, ticker }: Asset, baseAssetChain: EVMChain) {
|
|
175
|
+
try {
|
|
176
|
+
const isBSCBNB = chain === Chain.BinanceSmartChain && symbol === "BNB" && ticker === "BNB";
|
|
177
|
+
const isBaseAsset = chain === baseAssetChain && symbol === baseAssetChain && ticker === baseAssetChain;
|
|
178
|
+
const isEVMAsset = ethGasChains.includes(chain) && symbol === "ETH" && ticker === "ETH";
|
|
179
|
+
|
|
180
|
+
if (isBaseAsset || isBSCBNB || isEVMAsset) {
|
|
181
|
+
return ContractAddress[baseAssetChain];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// strip 0X only - 0x is still valid
|
|
185
|
+
return getAddress(symbol.slice(ticker.length + 1).replace(/^0X/, ""));
|
|
186
|
+
} catch {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function getCreateContractTxObject({ provider }: ToolboxWrapParams) {
|
|
192
|
+
return async ({ contractAddress, abi, funcName, funcParams = [], txOverrides }: CallParams) =>
|
|
193
|
+
createContract(contractAddress, abi, provider)
|
|
194
|
+
.getFunction(funcName)
|
|
195
|
+
.populateTransaction(...funcParams.concat(txOverrides).filter((p) => typeof p !== "undefined"));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export function getEstimateGasPrices({
|
|
199
|
+
chain,
|
|
200
|
+
provider,
|
|
201
|
+
isEIP1559Compatible = true,
|
|
202
|
+
}: {
|
|
203
|
+
provider: Provider;
|
|
204
|
+
isEIP1559Compatible?: boolean;
|
|
205
|
+
chain: EVMChain;
|
|
206
|
+
}): () => Promise<{
|
|
207
|
+
[key in FeeOption]: { l1GasPrice?: bigint; gasPrice?: bigint; maxFeePerGas?: bigint; maxPriorityFeePerGas?: bigint };
|
|
208
|
+
}> {
|
|
209
|
+
return match(chain)
|
|
210
|
+
.with(Chain.Gnosis, () => {
|
|
211
|
+
return async function estimateGasPrices() {
|
|
212
|
+
try {
|
|
213
|
+
const { gasPrice, maxPriorityFeePerGas } = await provider.getFeeData();
|
|
214
|
+
if (!gasPrice || maxPriorityFeePerGas === null) throw new SwapKitError("toolbox_evm_no_fee_data");
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
[FeeOption.Average]: {
|
|
218
|
+
maxFeePerGas: applyFeeMultiplierToBigInt(gasPrice, FeeOption.Average),
|
|
219
|
+
maxPriorityFeePerGas: applyFeeMultiplierToBigInt(maxPriorityFeePerGas, FeeOption.Average),
|
|
220
|
+
},
|
|
221
|
+
[FeeOption.Fast]: {
|
|
222
|
+
maxFeePerGas: applyFeeMultiplierToBigInt(gasPrice, FeeOption.Fast),
|
|
223
|
+
maxPriorityFeePerGas: applyFeeMultiplierToBigInt(maxPriorityFeePerGas, FeeOption.Fast),
|
|
224
|
+
},
|
|
225
|
+
[FeeOption.Fastest]: {
|
|
226
|
+
maxFeePerGas: applyFeeMultiplierToBigInt(gasPrice, FeeOption.Fastest),
|
|
227
|
+
maxPriorityFeePerGas: applyFeeMultiplierToBigInt(maxPriorityFeePerGas, FeeOption.Fastest),
|
|
228
|
+
},
|
|
229
|
+
};
|
|
230
|
+
} catch (error) {
|
|
231
|
+
throw new SwapKitError("toolbox_evm_gas_estimation_error", {
|
|
232
|
+
error: (error as any).msg ?? (error as any).toString(),
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
})
|
|
237
|
+
.with(Chain.Arbitrum, () => {
|
|
238
|
+
return async function estimateGasPrices() {
|
|
239
|
+
try {
|
|
240
|
+
const { gasPrice } = await provider.getFeeData();
|
|
241
|
+
if (!gasPrice) throw new SwapKitError("toolbox_evm_no_fee_data");
|
|
242
|
+
|
|
243
|
+
return {
|
|
244
|
+
[FeeOption.Average]: { gasPrice },
|
|
245
|
+
[FeeOption.Fast]: { gasPrice },
|
|
246
|
+
[FeeOption.Fastest]: { gasPrice },
|
|
247
|
+
};
|
|
248
|
+
} catch (error) {
|
|
249
|
+
throw new SwapKitError("toolbox_evm_gas_estimation_error", {
|
|
250
|
+
error: (error as any).msg ?? (error as any).toString(),
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
})
|
|
255
|
+
.otherwise(() => {
|
|
256
|
+
return async function estimateGasPrices() {
|
|
257
|
+
try {
|
|
258
|
+
const { maxFeePerGas, maxPriorityFeePerGas, gasPrice } = await provider.getFeeData();
|
|
259
|
+
|
|
260
|
+
if (isEIP1559Compatible) {
|
|
261
|
+
if (maxFeePerGas === null || maxPriorityFeePerGas === null)
|
|
262
|
+
throw new SwapKitError("toolbox_evm_no_fee_data");
|
|
263
|
+
|
|
264
|
+
return {
|
|
265
|
+
[FeeOption.Average]: { maxFeePerGas, maxPriorityFeePerGas },
|
|
266
|
+
[FeeOption.Fast]: {
|
|
267
|
+
maxFeePerGas: applyFeeMultiplierToBigInt(maxFeePerGas, FeeOption.Fast),
|
|
268
|
+
maxPriorityFeePerGas: applyFeeMultiplierToBigInt(maxPriorityFeePerGas, FeeOption.Fast),
|
|
269
|
+
},
|
|
270
|
+
[FeeOption.Fastest]: {
|
|
271
|
+
maxFeePerGas: applyFeeMultiplierToBigInt(maxFeePerGas, FeeOption.Fastest),
|
|
272
|
+
maxPriorityFeePerGas: applyFeeMultiplierToBigInt(maxPriorityFeePerGas, FeeOption.Fastest),
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
if (!gasPrice) throw new SwapKitError("toolbox_evm_no_gas_price");
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
[FeeOption.Average]: { gasPrice },
|
|
280
|
+
[FeeOption.Fast]: { gasPrice: applyFeeMultiplierToBigInt(gasPrice, FeeOption.Fast) },
|
|
281
|
+
[FeeOption.Fastest]: { gasPrice: applyFeeMultiplierToBigInt(gasPrice, FeeOption.Fastest) },
|
|
282
|
+
};
|
|
283
|
+
} catch (error) {
|
|
284
|
+
throw new SwapKitError("toolbox_evm_gas_estimation_error", {
|
|
285
|
+
error: (error as any).msg ?? (error as any).toString(),
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function getCall({ provider, isEIP1559Compatible, signer, chain }: ToolboxWrapParams) {
|
|
293
|
+
/**
|
|
294
|
+
* @info call contract function
|
|
295
|
+
* When using this method to make a non state changing call to the blockchain, like a isApproved call,
|
|
296
|
+
* the signer needs to be set to undefined
|
|
297
|
+
*/
|
|
298
|
+
return async function call<T>({
|
|
299
|
+
callProvider,
|
|
300
|
+
contractAddress,
|
|
301
|
+
abi,
|
|
302
|
+
funcName,
|
|
303
|
+
funcParams = [],
|
|
304
|
+
txOverrides = {},
|
|
305
|
+
feeOption = FeeOption.Fast,
|
|
306
|
+
}: CallParams): Promise<T> {
|
|
307
|
+
const contractProvider = callProvider || provider;
|
|
308
|
+
if (!contractAddress)
|
|
309
|
+
throw new SwapKitError("toolbox_evm_invalid_params", { error: "contractAddress must be provided" });
|
|
310
|
+
|
|
311
|
+
const isStateChanging = isStateChangingCall({ abi, funcName });
|
|
312
|
+
|
|
313
|
+
if (isStateChanging && isBrowserProvider(contractProvider) && signer) {
|
|
314
|
+
const createTx = getCreateContractTxObject({ chain, provider: contractProvider });
|
|
315
|
+
const from = txOverrides?.from || (await signer?.getAddress());
|
|
316
|
+
const txObject = await createTx({
|
|
317
|
+
abi,
|
|
318
|
+
contractAddress,
|
|
319
|
+
funcName,
|
|
320
|
+
funcParams,
|
|
321
|
+
txOverrides: { ...txOverrides, from },
|
|
322
|
+
});
|
|
323
|
+
const sendTx = getEIP1193SendTransaction(contractProvider);
|
|
324
|
+
|
|
325
|
+
return sendTx(txObject) as Promise<T>;
|
|
326
|
+
}
|
|
327
|
+
const contract = createContract(contractAddress, abi, contractProvider);
|
|
328
|
+
|
|
329
|
+
// only use signer if the contract function is state changing
|
|
330
|
+
if (isStateChanging) {
|
|
331
|
+
if (!signer) throw new SwapKitError("toolbox_evm_no_signer");
|
|
332
|
+
|
|
333
|
+
const from = txOverrides?.from || (await signer.getAddress());
|
|
334
|
+
if (!from) throw new SwapKitError("toolbox_evm_no_signer_address");
|
|
335
|
+
|
|
336
|
+
const connectedContract = contract.connect(signer);
|
|
337
|
+
const estimateGasPrices = getEstimateGasPrices({ chain, isEIP1559Compatible, provider });
|
|
338
|
+
const { maxFeePerGas, maxPriorityFeePerGas, gasPrice } = (await estimateGasPrices())[feeOption];
|
|
339
|
+
|
|
340
|
+
const gasLimit = await contract.getFunction(funcName).estimateGas(...funcParams, txOverrides);
|
|
341
|
+
|
|
342
|
+
// @ts-expect-error
|
|
343
|
+
const result = await connectedContract[funcName](...funcParams, {
|
|
344
|
+
...txOverrides,
|
|
345
|
+
gasLimit,
|
|
346
|
+
gasPrice,
|
|
347
|
+
maxFeePerGas,
|
|
348
|
+
maxPriorityFeePerGas,
|
|
349
|
+
/**
|
|
350
|
+
* nonce must be set due to a possible bug with ethers.js,
|
|
351
|
+
* expecting a synchronous nonce while the JsonRpcProvider delivers Promise
|
|
352
|
+
*/
|
|
353
|
+
nonce: txOverrides?.nonce || (await contractProvider.getTransactionCount(from)),
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
return typeof result?.hash === "string" ? result?.hash : result;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const result = await contract[funcName]?.(...funcParams);
|
|
360
|
+
|
|
361
|
+
return typeof result?.hash === "string" ? result?.hash : result;
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function getApprovedAmount({ provider, chain }: ToolboxWrapParams) {
|
|
366
|
+
return function approveAmount({ assetAddress, spenderAddress, from }: IsApprovedParams) {
|
|
367
|
+
const call = getCall({ chain, isEIP1559Compatible: true, provider });
|
|
368
|
+
|
|
369
|
+
return call<bigint>({
|
|
370
|
+
abi: erc20ABI,
|
|
371
|
+
contractAddress: assetAddress,
|
|
372
|
+
funcName: "allowance",
|
|
373
|
+
funcParams: [from, spenderAddress],
|
|
374
|
+
});
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function getIsApproved({ provider, chain }: ToolboxWrapParams) {
|
|
379
|
+
return async function isApproved({ assetAddress, spenderAddress, from, amount = MAX_APPROVAL }: IsApprovedParams) {
|
|
380
|
+
const approvedAmount = await getApprovedAmount({ chain, provider })({ assetAddress, from, spenderAddress });
|
|
381
|
+
|
|
382
|
+
return SwapKitNumber.fromBigInt(approvedAmount).gte(SwapKitNumber.fromBigInt(BigInt(amount)));
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function getApprove({ signer, isEIP1559Compatible = true, provider, chain }: ToolboxWrapParams) {
|
|
387
|
+
return async function approve({
|
|
388
|
+
assetAddress,
|
|
389
|
+
spenderAddress,
|
|
390
|
+
feeOptionKey = FeeOption.Fast,
|
|
391
|
+
amount,
|
|
392
|
+
gasLimitFallback,
|
|
393
|
+
from: fromParam,
|
|
394
|
+
nonce,
|
|
395
|
+
}: ApproveParams) {
|
|
396
|
+
const funcParams = [spenderAddress, BigInt(amount || MAX_APPROVAL)];
|
|
397
|
+
const from = (await signer?.getAddress()) || fromParam;
|
|
398
|
+
|
|
399
|
+
const functionCallParams = {
|
|
400
|
+
abi: erc20ABI,
|
|
401
|
+
contractAddress: assetAddress,
|
|
402
|
+
funcName: "approve",
|
|
403
|
+
funcParams,
|
|
404
|
+
signer,
|
|
405
|
+
txOverrides: { from },
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
if (isBrowserProvider(provider)) {
|
|
409
|
+
const createTx = getCreateContractTxObject({ chain, provider });
|
|
410
|
+
const sendTx = getEIP1193SendTransaction(provider);
|
|
411
|
+
const txObject = await createTx(functionCallParams);
|
|
412
|
+
|
|
413
|
+
return sendTx(txObject);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const call = getCall({ chain, isEIP1559Compatible, provider, signer });
|
|
417
|
+
|
|
418
|
+
return call<string>({
|
|
419
|
+
...functionCallParams,
|
|
420
|
+
feeOption: feeOptionKey,
|
|
421
|
+
funcParams,
|
|
422
|
+
txOverrides: { from, gasLimit: gasLimitFallback ? BigInt(gasLimitFallback.toString()) : undefined, nonce },
|
|
423
|
+
});
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function getTransfer({ signer, isEIP1559Compatible = true, provider }: ToolboxWrapParams) {
|
|
428
|
+
return async function transfer({
|
|
429
|
+
assetValue,
|
|
430
|
+
memo,
|
|
431
|
+
recipient,
|
|
432
|
+
feeOptionKey = FeeOption.Fast,
|
|
433
|
+
sender,
|
|
434
|
+
// data,
|
|
435
|
+
// from: fromOverride,
|
|
436
|
+
// maxFeePerGas,
|
|
437
|
+
// maxPriorityFeePerGas,
|
|
438
|
+
// gasPrice,
|
|
439
|
+
...tx
|
|
440
|
+
}: EVMTransferParams) {
|
|
441
|
+
const { hexlify, toUtf8Bytes } = await import("ethers");
|
|
442
|
+
const txAmount = assetValue.getBaseValue("bigint");
|
|
443
|
+
const chain = assetValue.chain as EVMChain;
|
|
444
|
+
const from = sender || (await signer?.getAddress());
|
|
445
|
+
const sendTx = getSendTransaction({ chain, isEIP1559Compatible, provider, signer });
|
|
446
|
+
|
|
447
|
+
if (!from) throw new SwapKitError("toolbox_evm_no_from_address");
|
|
448
|
+
|
|
449
|
+
if (assetValue.isGasAsset) {
|
|
450
|
+
const transaction = {
|
|
451
|
+
...tx,
|
|
452
|
+
data: hexlify(toUtf8Bytes(memo || "")),
|
|
453
|
+
feeOptionKey,
|
|
454
|
+
from,
|
|
455
|
+
to: recipient,
|
|
456
|
+
value: txAmount,
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
return sendTx(transaction);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// const call = getCall({ signer, provider, isEIP1559Compatible });
|
|
463
|
+
const contractAddress = getTokenAddress(assetValue, chain);
|
|
464
|
+
if (!contractAddress) throw new SwapKitError("toolbox_evm_no_contract_address");
|
|
465
|
+
|
|
466
|
+
const { maxFeePerGas, maxPriorityFeePerGas, gasPrice } = (
|
|
467
|
+
await getEstimateGasPrices({ chain, isEIP1559Compatible, provider })()
|
|
468
|
+
)[feeOptionKey];
|
|
469
|
+
|
|
470
|
+
const transaction = await getCreateTransferTx({ chain, provider, signer })({
|
|
471
|
+
assetValue,
|
|
472
|
+
data: hexlify(toUtf8Bytes(memo || "")),
|
|
473
|
+
gasPrice,
|
|
474
|
+
maxFeePerGas,
|
|
475
|
+
maxPriorityFeePerGas,
|
|
476
|
+
memo,
|
|
477
|
+
recipient,
|
|
478
|
+
sender: from,
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
return sendTx(transaction);
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function getEstimateCall({ provider, signer }: { signer?: Signer; provider: Provider }) {
|
|
486
|
+
return function estimateCall({ contractAddress, abi, funcName, funcParams = [], txOverrides }: EstimateCallParams) {
|
|
487
|
+
if (!contractAddress) throw new SwapKitError("toolbox_evm_no_contract_address");
|
|
488
|
+
|
|
489
|
+
const contract = createContract(contractAddress, abi, provider);
|
|
490
|
+
return signer
|
|
491
|
+
? contract
|
|
492
|
+
.connect(signer)
|
|
493
|
+
.getFunction(funcName)
|
|
494
|
+
.estimateGas(...funcParams, txOverrides)
|
|
495
|
+
: contract.getFunction(funcName).estimateGas(...funcParams, txOverrides);
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
function getEstimateGasLimit({ provider, signer }: ToolboxWrapParams) {
|
|
500
|
+
return async function estimateGasLimit({
|
|
501
|
+
assetValue,
|
|
502
|
+
recipient,
|
|
503
|
+
memo,
|
|
504
|
+
data,
|
|
505
|
+
sender,
|
|
506
|
+
funcName,
|
|
507
|
+
funcParams,
|
|
508
|
+
txOverrides,
|
|
509
|
+
}: EVMTransferParams & {
|
|
510
|
+
assetValue: AssetValue;
|
|
511
|
+
funcName?: string;
|
|
512
|
+
funcParams?: unknown[];
|
|
513
|
+
txOverrides?: EVMTxParams;
|
|
514
|
+
data?: string;
|
|
515
|
+
}) {
|
|
516
|
+
// const value = assetValue.getBaseValue("bigint");
|
|
517
|
+
const value = assetValue.bigIntValue;
|
|
518
|
+
|
|
519
|
+
const assetAddress = assetValue.isGasAsset ? null : getTokenAddress(assetValue, assetValue.chain as EVMChain);
|
|
520
|
+
|
|
521
|
+
if (assetAddress && funcName) {
|
|
522
|
+
const estimateCall = getEstimateCall({ provider, signer });
|
|
523
|
+
// ERC20 gas estimate
|
|
524
|
+
return estimateCall({ abi: erc20ABI, contractAddress: assetAddress, funcName, funcParams, txOverrides });
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
const { hexlify, toUtf8Bytes } = await import("ethers");
|
|
528
|
+
|
|
529
|
+
return provider.estimateGas({
|
|
530
|
+
data: data ? data : memo ? hexlify(toUtf8Bytes(memo)) : undefined,
|
|
531
|
+
from: sender,
|
|
532
|
+
to: recipient,
|
|
533
|
+
value,
|
|
534
|
+
});
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
const isEIP1559Transaction = (tx: EVMTxParams) =>
|
|
539
|
+
(tx as EIP1559TxParams).type === 2 ||
|
|
540
|
+
!!(tx as EIP1559TxParams).maxFeePerGas ||
|
|
541
|
+
!!(tx as EIP1559TxParams).maxPriorityFeePerGas;
|
|
542
|
+
|
|
543
|
+
function getSendTransaction({ provider, signer, isEIP1559Compatible = true, chain }: ToolboxWrapParams) {
|
|
544
|
+
return async function sendTransaction({
|
|
545
|
+
feeOptionKey = FeeOption.Fast,
|
|
546
|
+
...tx
|
|
547
|
+
}: EVMTxParams & { feeOptionKey?: FeeOption }) {
|
|
548
|
+
const { from, to, data, value, ...transaction } = tx;
|
|
549
|
+
|
|
550
|
+
if (!signer) throw new SwapKitError("toolbox_evm_no_signer");
|
|
551
|
+
if (!to) throw new SwapKitError("toolbox_evm_no_to_address");
|
|
552
|
+
|
|
553
|
+
const parsedTxObject = { ...transaction, data: data || "0x", from, to, value: BigInt(value || 0) };
|
|
554
|
+
|
|
555
|
+
// early return to skip gas estimation if provider is EIP-1193
|
|
556
|
+
if (isBrowserProvider(provider)) {
|
|
557
|
+
const sendTx = getEIP1193SendTransaction(provider);
|
|
558
|
+
return sendTx(parsedTxObject);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
const address = from || (await signer.getAddress());
|
|
562
|
+
const nonce = tx.nonce || (await provider.getTransactionCount(address));
|
|
563
|
+
const chainId = (await provider.getNetwork()).chainId;
|
|
564
|
+
|
|
565
|
+
const isEIP1559 = isEIP1559Transaction(parsedTxObject) || isEIP1559Compatible;
|
|
566
|
+
const estimateGasPrices = getEstimateGasPrices({ chain, isEIP1559Compatible, provider });
|
|
567
|
+
|
|
568
|
+
const feeData =
|
|
569
|
+
(isEIP1559 &&
|
|
570
|
+
!(
|
|
571
|
+
(parsedTxObject as EIP1559TxParams).maxFeePerGas && (parsedTxObject as EIP1559TxParams).maxPriorityFeePerGas
|
|
572
|
+
)) ||
|
|
573
|
+
!(parsedTxObject as LegacyEVMTxParams).gasPrice
|
|
574
|
+
? Object.entries((await estimateGasPrices())[feeOptionKey]).reduce(
|
|
575
|
+
// biome-ignore lint/performance/noAccumulatingSpread: this is a small object
|
|
576
|
+
(acc, [k, v]) => ({ ...acc, [k]: toHexString(BigInt(v)) }),
|
|
577
|
+
{} as { maxFeePerGas?: string; maxPriorityFeePerGas?: string; gasPrice?: string },
|
|
578
|
+
)
|
|
579
|
+
: {};
|
|
580
|
+
let gasLimit: string;
|
|
581
|
+
try {
|
|
582
|
+
gasLimit = toHexString(parsedTxObject.gasLimit || ((await provider.estimateGas(parsedTxObject)) * 11n) / 10n);
|
|
583
|
+
} catch (error) {
|
|
584
|
+
throw new SwapKitError("toolbox_evm_error_estimating_gas_limit", { error });
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
try {
|
|
588
|
+
const txObject = { ...parsedTxObject, chainId, gasLimit, nonce, type: isEIP1559 ? 2 : 0, ...feeData };
|
|
589
|
+
|
|
590
|
+
try {
|
|
591
|
+
const response = await signer.sendTransaction(txObject);
|
|
592
|
+
return response.hash;
|
|
593
|
+
} catch {
|
|
594
|
+
const txHex = await signer.signTransaction({ ...txObject, from: address });
|
|
595
|
+
const response = await provider.broadcastTransaction(txHex);
|
|
596
|
+
return response.hash;
|
|
597
|
+
}
|
|
598
|
+
} catch (error) {
|
|
599
|
+
throw new SwapKitError("toolbox_evm_error_sending_transaction", { error });
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
function getCreateTransferTx({ provider, signer }: ToolboxWrapParams) {
|
|
605
|
+
return async function createTransferTx({
|
|
606
|
+
assetValue,
|
|
607
|
+
memo,
|
|
608
|
+
recipient,
|
|
609
|
+
data,
|
|
610
|
+
sender: fromOverride,
|
|
611
|
+
maxFeePerGas,
|
|
612
|
+
maxPriorityFeePerGas,
|
|
613
|
+
gasPrice,
|
|
614
|
+
...tx
|
|
615
|
+
}: EVMCreateTransactionParams) {
|
|
616
|
+
const txAmount = assetValue.getBaseValue("bigint");
|
|
617
|
+
const chain = assetValue.chain as EVMChain;
|
|
618
|
+
const from = fromOverride || (await signer?.getAddress());
|
|
619
|
+
|
|
620
|
+
if (!from) throw new SwapKitError("toolbox_evm_no_from_address");
|
|
621
|
+
|
|
622
|
+
if (isGasAsset(assetValue)) {
|
|
623
|
+
const { hexlify, toUtf8Bytes } = await import("ethers");
|
|
624
|
+
|
|
625
|
+
return { ...tx, data: data || hexlify(toUtf8Bytes(memo || "")), from, to: recipient, value: txAmount };
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
const contractAddress = getTokenAddress(assetValue, chain);
|
|
629
|
+
if (!contractAddress) throw new SwapKitError("toolbox_evm_no_contract_address");
|
|
630
|
+
const createTx = getCreateContractTxObject({ chain: assetValue.chain as EVMChain, provider });
|
|
631
|
+
|
|
632
|
+
return createTx({
|
|
633
|
+
abi: erc20ABI,
|
|
634
|
+
contractAddress,
|
|
635
|
+
funcName: "transfer",
|
|
636
|
+
funcParams: [recipient, txAmount],
|
|
637
|
+
txOverrides: { from, gasPrice, maxFeePerGas, maxPriorityFeePerGas },
|
|
638
|
+
});
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
function getCreateApprovalTx({ provider, signer, chain }: ToolboxWrapParams) {
|
|
643
|
+
return async function createApprovalTx({ assetAddress, spenderAddress, amount, from: fromParam }: ApproveParams) {
|
|
644
|
+
const from = (await signer?.getAddress()) || fromParam;
|
|
645
|
+
|
|
646
|
+
const createTx = getCreateContractTxObject({ chain, provider });
|
|
647
|
+
const approvalAmount = ["bigint", "number"].includes(typeof amount)
|
|
648
|
+
? (amount as bigint | number)
|
|
649
|
+
: amount || MAX_APPROVAL;
|
|
650
|
+
|
|
651
|
+
const txObject = await createTx({
|
|
652
|
+
abi: erc20ABI,
|
|
653
|
+
contractAddress: assetAddress,
|
|
654
|
+
funcName: "approve",
|
|
655
|
+
funcParams: [spenderAddress, BigInt(approvalAmount)],
|
|
656
|
+
txOverrides: { from },
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
return txObject;
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
function getEstimateTransactionFee({
|
|
664
|
+
provider,
|
|
665
|
+
isEIP1559Compatible = true,
|
|
666
|
+
}: {
|
|
667
|
+
provider: Provider | BrowserProvider;
|
|
668
|
+
isEIP1559Compatible?: boolean;
|
|
669
|
+
chain: EVMChain;
|
|
670
|
+
}) {
|
|
671
|
+
return async function estimateTransactionFee({
|
|
672
|
+
feeOption = FeeOption.Fast,
|
|
673
|
+
chain,
|
|
674
|
+
...txObject
|
|
675
|
+
}: EIP1559TxParams & { feeOption: FeeOption; chain: EVMChain }) {
|
|
676
|
+
const estimateGasPrices = getEstimateGasPrices({ chain, isEIP1559Compatible, provider });
|
|
677
|
+
const gasPrices = await estimateGasPrices();
|
|
678
|
+
const gasLimit = await provider.estimateGas(txObject);
|
|
679
|
+
|
|
680
|
+
const assetValue = AssetValue.from({ chain });
|
|
681
|
+
const { gasPrice, maxFeePerGas, maxPriorityFeePerGas } = gasPrices[feeOption];
|
|
682
|
+
|
|
683
|
+
if (!isEIP1559Compatible && gasPrice) {
|
|
684
|
+
return assetValue.set(SwapKitNumber.fromBigInt(gasPrice * gasLimit, assetValue.decimal));
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
if (maxFeePerGas && maxPriorityFeePerGas) {
|
|
688
|
+
const fee = (maxFeePerGas + maxPriorityFeePerGas) * gasLimit;
|
|
689
|
+
|
|
690
|
+
return assetValue.set(SwapKitNumber.fromBigInt(fee, assetValue.decimal));
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
throw new SwapKitError("toolbox_evm_no_gas_price");
|
|
694
|
+
};
|
|
695
|
+
}
|