@cryptorubic/web3 0.4.1 → 0.4.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cryptorubic/web3",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "scripts": {
5
5
  "build": "tsc --project tsconfig.lib.json --outDir ../../dist && cp package.json ../../dist/packages/web3"
6
6
  },
package/src/index.d.ts CHANGED
@@ -23,6 +23,8 @@ export * from './lib/adapter/adapters/models/tonapi-models';
23
23
  export * from './lib/adapter/adapters/models/toncenter-types';
24
24
  export * from './lib/adapter/adapters/models/approve-adapter';
25
25
  export * from './lib/adapter/adapters/models/gas-price';
26
+ export * from './lib/adapter/adapters/models/btc-wallet-provider';
27
+ export * from './lib/adapter/adapters/bitcoin-adapter';
26
28
  export * from './lib/utils/web3-pure';
27
29
  export * from './lib/utils/models/evm-transaction-config';
28
30
  export * from './lib/utils/web3-types/bitcoin-web3-pure';
package/src/index.js CHANGED
@@ -23,6 +23,8 @@ tslib_1.__exportStar(require("./lib/adapter/adapters/models/tonapi-models"), exp
23
23
  tslib_1.__exportStar(require("./lib/adapter/adapters/models/toncenter-types"), exports);
24
24
  tslib_1.__exportStar(require("./lib/adapter/adapters/models/approve-adapter"), exports);
25
25
  tslib_1.__exportStar(require("./lib/adapter/adapters/models/gas-price"), exports);
26
+ tslib_1.__exportStar(require("./lib/adapter/adapters/models/btc-wallet-provider"), exports);
27
+ tslib_1.__exportStar(require("./lib/adapter/adapters/bitcoin-adapter"), exports);
26
28
  // utils aka web3pure
27
29
  tslib_1.__exportStar(require("./lib/utils/web3-pure"), exports);
28
30
  tslib_1.__exportStar(require("./lib/utils/models/evm-transaction-config"), exports);
@@ -0,0 +1,14 @@
1
+ import { BitcoinBlockchainName, BlockchainName, HttpClient, ICustomLogger, Token } from '@cryptorubic/core';
2
+ import BigNumber from 'bignumber.js';
3
+ import { AbstractAdapter } from './abstract-adapter';
4
+ import { BasicTransactionOptions } from './models/basic-transaction-options';
5
+ import { BtcWallet } from './models/btc-wallet-provider';
6
+ export declare class BitcoinAdapter extends AbstractAdapter<BtcWallet, BtcWallet, BitcoinBlockchainName> {
7
+ private readonly httpClient;
8
+ constructor(httpClient: HttpClient, logger?: ICustomLogger);
9
+ getBalance(userAddress: string): Promise<BigNumber>;
10
+ callForTokensInfo(tokenAddresses: string[] | ReadonlyArray<string>): Promise<Token<BlockchainName>[]>;
11
+ read<T>(args: unknown): Promise<T>;
12
+ write(args: unknown): Promise<string>;
13
+ transfer(recipient: string, amount: string, fromAddress: string, memo?: string, options?: BasicTransactionOptions): Promise<string>;
14
+ }
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BitcoinAdapter = void 0;
4
+ const core_1 = require("@cryptorubic/core");
5
+ const bignumber_js_1 = require("bignumber.js");
6
+ const abstract_adapter_1 = require("./abstract-adapter");
7
+ class BitcoinAdapter extends abstract_adapter_1.AbstractAdapter {
8
+ constructor(httpClient, logger) {
9
+ super(core_1.BLOCKCHAIN_NAME.BITCOIN, logger);
10
+ this.httpClient = httpClient;
11
+ }
12
+ async getBalance(userAddress) {
13
+ const url = `https://api.blockcypher.com/v1/btc/main/addrs/${userAddress}/balance`;
14
+ const response = await this.httpClient.get(url);
15
+ return new bignumber_js_1.default(response.final_balance);
16
+ }
17
+ async callForTokensInfo(tokenAddresses) {
18
+ return [core_1.nativeTokensList[core_1.BLOCKCHAIN_NAME.BITCOIN]];
19
+ }
20
+ read(args) {
21
+ throw new Error('Not implemented');
22
+ }
23
+ write(args) {
24
+ throw new Error('Not implemented');
25
+ }
26
+ async transfer(recipient, amount, fromAddress, memo, options) {
27
+ const hashPromise = new Promise((resolve, reject) => {
28
+ this.wallet.request({
29
+ method: 'transfer',
30
+ params: [
31
+ {
32
+ feeRate: 10,
33
+ from: fromAddress,
34
+ recipient,
35
+ amount: {
36
+ amount,
37
+ decimals: 8,
38
+ },
39
+ ...(memo && { memo }),
40
+ },
41
+ ],
42
+ }, (error, txHash) => {
43
+ if (error) {
44
+ reject(error);
45
+ }
46
+ else {
47
+ options?.onTransactionHash?.(txHash);
48
+ resolve(txHash);
49
+ }
50
+ });
51
+ });
52
+ try {
53
+ const hash = await hashPromise;
54
+ if (typeof hash === 'string') {
55
+ // const statusData = this.getSrcStatusRecursive(srcTxHash, BLOCKCHAIN_NAME.BITCOIN, 300_000);
56
+ return hash;
57
+ }
58
+ throw new Error();
59
+ }
60
+ catch {
61
+ throw new Error('Failed to transfer funds');
62
+ }
63
+ }
64
+ }
65
+ exports.BitcoinAdapter = BitcoinAdapter;
@@ -0,0 +1,2 @@
1
+ import { Abi } from 'viem';
2
+ export declare const UNI_V3_PERMIT_2_ABI: Abi;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UNI_V3_PERMIT_2_ABI = void 0;
4
+ exports.UNI_V3_PERMIT_2_ABI = [
5
+ {
6
+ inputs: [
7
+ {
8
+ internalType: 'address',
9
+ name: 'owner',
10
+ type: 'address',
11
+ },
12
+ {
13
+ internalType: 'address',
14
+ name: 'token',
15
+ type: 'address',
16
+ },
17
+ {
18
+ internalType: 'address',
19
+ name: 'spender',
20
+ type: 'address',
21
+ },
22
+ ],
23
+ name: 'allowance',
24
+ outputs: [
25
+ {
26
+ internalType: 'uint160',
27
+ name: 'amount',
28
+ type: 'uint160',
29
+ },
30
+ {
31
+ internalType: 'uint48',
32
+ name: 'expiration',
33
+ type: 'uint48',
34
+ },
35
+ {
36
+ internalType: 'uint48',
37
+ name: 'nonce',
38
+ type: 'uint48',
39
+ },
40
+ ],
41
+ stateMutability: 'view',
42
+ type: 'function',
43
+ },
44
+ {
45
+ inputs: [
46
+ {
47
+ internalType: 'address',
48
+ name: 'token',
49
+ type: 'address',
50
+ },
51
+ {
52
+ internalType: 'address',
53
+ name: 'spender',
54
+ type: 'address',
55
+ },
56
+ {
57
+ internalType: 'uint160',
58
+ name: 'amount',
59
+ type: 'uint160',
60
+ },
61
+ {
62
+ internalType: 'uint48',
63
+ name: 'expiration',
64
+ type: 'uint48',
65
+ },
66
+ ],
67
+ name: 'approve',
68
+ outputs: [],
69
+ stateMutability: 'nonpayable',
70
+ type: 'function',
71
+ },
72
+ ];
@@ -18,7 +18,7 @@ export declare class EvmAdapter extends AbstractAdapter<PublicActions & PublicCl
18
18
  multicallByContract<T>(contracts: MulticallParameters, allowErrors?: boolean): Promise<MulticallResponse<T>[]>;
19
19
  multicallByAddress<T>(address: string, abi: Abi, method: string, methodArgs?: unknown[][], allowErrors?: boolean): Promise<MulticallResponse<T>[]>;
20
20
  static encodeMethodCall(contractAddress: string, contractAbi: Abi, method: string, parameters?: unknown[], value?: string): EvmTransactionConfig;
21
- simulateTransaction(config: EvmTransactionConfig, from: string): Promise<string>;
21
+ simulateTransaction(config: EvmTransactionConfig, from: string, timeout?: number): Promise<string>;
22
22
  callForTokensInfo(tokenAddresses: string[] | ReadonlyArray<string>): Promise<Token<EvmBlockchainName>[]>;
23
23
  getGasPrice(): Promise<string>;
24
24
  checkEnoughBalance(token: TokenAmount | PriceTokenAmount, walletAddress: string, amount?: BigNumber): Promise<boolean>;
@@ -33,6 +33,9 @@ export declare class EvmAdapter extends AbstractAdapter<PublicActions & PublicCl
33
33
  encodeApprove(tokenAddress: string, spenderAddress: string, amount?: string): EvmTransactionConfig;
34
34
  needApprove(token: TokenAmount, contractAddress: string, walletAddress: string, amount: string): Promise<boolean>;
35
35
  approve(fromAddress: string, tokenAddress: string, spenderAddress: string, amount?: string): Promise<string>;
36
+ needPermit2Approve(token: TokenAmount, permit2Address: string, walletAddress: string, spenderAddress: string): Promise<boolean>;
37
+ encodePermit2Approve(tokenAddress: string, spenderAddress: string, permit2Address: string, expiration: string, amount: string): EvmTransactionConfig;
38
+ approveOnPermit2(fromAddress: string, tokenAddress: string, permit2Address: string, spenderAddress: string, deadline?: BigNumber, amount?: BigNumber): Promise<string>;
36
39
  /**
37
40
  * Calculates EIP-1559 specific gas details.
38
41
  * @see {@link https://github.com/ethers-io/ethers.js/blob/master/packages/abstract-provider/src.ts/index.ts#L235}
@@ -9,6 +9,7 @@ const core_1 = require("@cryptorubic/core");
9
9
  const bignumber_js_1 = require("bignumber.js");
10
10
  const web3_pure_1 = require("../../utils/web3-pure");
11
11
  const possible_errors_1 = require("./constants/possible-errors");
12
+ const uni_v3_permit_abi_1 = require("./constants/uni-v3-permit-abi");
12
13
  class EvmAdapter extends abstract_adapter_1.AbstractAdapter {
13
14
  async needPreswapAction(token, contractAddress, walletAddress, amount) {
14
15
  return this.needApprove(token, contractAddress, walletAddress, amount);
@@ -137,7 +138,7 @@ class EvmAdapter extends abstract_adapter_1.AbstractAdapter {
137
138
  throw err;
138
139
  }
139
140
  }
140
- async simulateTransaction(config, from) {
141
+ async simulateTransaction(config, from, timeout = 15000) {
141
142
  try {
142
143
  const callParams = {
143
144
  account: from,
@@ -145,8 +146,11 @@ class EvmAdapter extends abstract_adapter_1.AbstractAdapter {
145
146
  to: config.to,
146
147
  ...(config.value && { value: BigInt(config.value) }),
147
148
  };
148
- const gasLimitWei = await this.public.estimateGas(callParams);
149
- return gasLimitWei.toString();
149
+ const gasLimitWei = await Promise.race([
150
+ this.public.estimateGas(callParams),
151
+ new Promise((_, reject) => setTimeout(() => reject('Timeout'), timeout)),
152
+ ]);
153
+ return gasLimitWei?.toString();
150
154
  }
151
155
  catch (err) {
152
156
  this.logger?.customError('Error while simulating transaction', err);
@@ -262,6 +266,26 @@ class EvmAdapter extends abstract_adapter_1.AbstractAdapter {
262
266
  const config = this.encodeApprove(tokenAddress, spenderAddress, amount);
263
267
  return this.write(fromAddress, config.to, config.value, config.data);
264
268
  }
269
+ async needPermit2Approve(token, permit2Address, walletAddress, spenderAddress) {
270
+ const res = await this.read(permit2Address, uni_v3_permit_abi_1.UNI_V3_PERMIT_2_ABI, 'allowance', [walletAddress, token.address, spenderAddress]);
271
+ const [amount, expiration, _nonce] = res;
272
+ return (token.weiAmount.gt(amount) ||
273
+ new bignumber_js_1.default(Date.now()).gt(Number(expiration) * 1000));
274
+ }
275
+ encodePermit2Approve(tokenAddress, spenderAddress, permit2Address, expiration, amount) {
276
+ const tx = EvmAdapter.encodeMethodCall(permit2Address, uni_v3_permit_abi_1.UNI_V3_PERMIT_2_ABI, 'approve', [tokenAddress, spenderAddress, amount, expiration]);
277
+ return {
278
+ data: tx.data,
279
+ value: tx.value,
280
+ to: tx.to,
281
+ };
282
+ }
283
+ async approveOnPermit2(fromAddress, tokenAddress, permit2Address, spenderAddress, deadline = new bignumber_js_1.default(1000000), amount) {
284
+ const approveAmount = amount ? amount : new bignumber_js_1.default(2).pow(256).minus(1);
285
+ const expiration = new bignumber_js_1.default(Date.now()).plus(deadline).toFixed();
286
+ const tx = this.encodePermit2Approve(tokenAddress, spenderAddress, permit2Address, expiration, approveAmount.toFixed());
287
+ return this.write(fromAddress, tx.to, tx.value, tx.data);
288
+ }
265
289
  /**
266
290
  * Calculates EIP-1559 specific gas details.
267
291
  * @see {@link https://github.com/ethers-io/ethers.js/blob/master/packages/abstract-provider/src.ts/index.ts#L235}
@@ -0,0 +1,10 @@
1
+ export interface BtcWallet {
2
+ on: (event: string, callback: (...args: unknown[]) => void) => unknown;
3
+ request<T>(args: {
4
+ method: string;
5
+ params: unknown[];
6
+ }, fn: (error: Error, txHash: string) => unknown): Promise<{
7
+ error: null | Error;
8
+ result: T;
9
+ }>;
10
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1 @@
1
+ export type Permit2AllowanceContractResponse = [string, number, number];
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -34,8 +34,13 @@ class SolanaAdapter extends abstract_adapter_1.AbstractAdapter {
34
34
  }
35
35
  async simulateTransaction(_config, _from) { }
36
36
  async callForTokensInfo(tokenAddresses) {
37
+ const nativeToken = core_1.nativeTokensList[core_1.BLOCKCHAIN_NAME.SOLANA];
37
38
  const nativeTokenIndex = tokenAddresses.findIndex((address) => web3_pure_1.Web3Pure.isNativeAddress(core_1.CHAIN_TYPE.SOLANA, address));
38
39
  const filteredTokenAddresses = tokenAddresses.filter((_, index) => index !== nativeTokenIndex);
40
+ // only native token in tokenAddresses
41
+ if (!filteredTokenAddresses.length) {
42
+ return [nativeToken];
43
+ }
39
44
  const mints = filteredTokenAddresses.map((address) => new web3_js_1.PublicKey(address));
40
45
  const tokenSdk = new utl_sdk_1.Client();
41
46
  const tokensMint = await tokenSdk.fetchMints(mints);
@@ -51,8 +56,7 @@ class SolanaAdapter extends abstract_adapter_1.AbstractAdapter {
51
56
  if (nativeTokenIndex === -1) {
52
57
  return tokens;
53
58
  }
54
- const blockchainNativeToken = core_1.nativeTokensList[core_1.BLOCKCHAIN_NAME.SOLANA];
55
- tokens.splice(nativeTokenIndex, 0, blockchainNativeToken);
59
+ tokens.splice(nativeTokenIndex, 0, nativeToken);
56
60
  return tokens;
57
61
  }
58
62
  }
@@ -2,10 +2,11 @@ import { SolanaAdapter } from './adapters/solana-adapter';
2
2
  import { TronAdapter } from './adapters/tron-adapter';
3
3
  import { AbstractAdapter } from './adapters/abstract-adapter';
4
4
  import { WalletProvider } from './constants/models/wallet-provider';
5
- import { BlockchainName, EvmBlockchainName, SolanaBlockchainName, TronBlockchainName, ICustomLogger, HttpClient, TonBlockchainName } from '@cryptorubic/core';
5
+ import { BlockchainName, EvmBlockchainName, SolanaBlockchainName, TronBlockchainName, ICustomLogger, HttpClient, TonBlockchainName, BitcoinBlockchainName } from '@cryptorubic/core';
6
6
  import { TonAdapter } from './adapters/ton-adapter';
7
7
  import { TonAdapterConfig } from './adapters/models/ton-adapter-config';
8
8
  import { EvmAdapter } from './adapters/evm-adapter';
9
+ import { BitcoinAdapter } from './adapters/bitcoin-adapter';
9
10
  export declare class BlockchainAdapterFactoryService {
10
11
  private readonly rpcList;
11
12
  private readonly createLogger?;
@@ -19,6 +20,7 @@ export declare class BlockchainAdapterFactoryService {
19
20
  getAdapter(blockchain: EvmBlockchainName): EvmAdapter;
20
21
  getAdapter(blockchain: TronBlockchainName): TronAdapter;
21
22
  getAdapter(blockchain: TonBlockchainName): TonAdapter;
23
+ getAdapter(blockchain: BitcoinBlockchainName): BitcoinAdapter;
22
24
  private createStorage;
23
25
  private createAdapter;
24
26
  connectWallet(walletProvider: WalletProvider): void;
@@ -8,6 +8,7 @@ const viem_1 = require("viem");
8
8
  const core_1 = require("@cryptorubic/core");
9
9
  const ton_adapter_1 = require("./adapters/ton-adapter");
10
10
  const evm_adapter_1 = require("./adapters/evm-adapter");
11
+ const bitcoin_adapter_1 = require("./adapters/bitcoin-adapter");
11
12
  class BlockchainAdapterFactoryService {
12
13
  constructor(rpcList, createLogger, httpClient, tonParams) {
13
14
  this.rpcList = rpcList;
@@ -46,6 +47,7 @@ class BlockchainAdapterFactoryService {
46
47
  return [blockchain, null];
47
48
  });
48
49
  const tonAdapter = this.createAdapter(core_1.BLOCKCHAIN_NAME.TON, []);
50
+ const btcAdapter = this.createAdapter(core_1.BLOCKCHAIN_NAME.BITCOIN, []);
49
51
  adapters.push(tonAdapter
50
52
  ? [core_1.BLOCKCHAIN_NAME.TON, tonAdapter]
51
53
  : [core_1.BLOCKCHAIN_NAME.TON, null]);
@@ -85,6 +87,9 @@ class BlockchainAdapterFactoryService {
85
87
  this.tonParams?.tonClientConfig) {
86
88
  return new ton_adapter_1.TonAdapter(this.httpClient, this.tonParams, this.createLogger?.(`TON_ADAPTER`));
87
89
  }
90
+ if (blockchain === core_1.BLOCKCHAIN_NAME.BITCOIN && this.httpClient) {
91
+ return new bitcoin_adapter_1.BitcoinAdapter(this.httpClient, this.createLogger?.(`BTC_ADAPTER`));
92
+ }
88
93
  return null;
89
94
  }
90
95
  connectWallet(walletProvider) {
@@ -117,6 +122,12 @@ class BlockchainAdapterFactoryService {
117
122
  store.wallet = walletProvider[core_1.CHAIN_TYPE.TON].core;
118
123
  store.walletAddress = walletProvider[core_1.CHAIN_TYPE.TON].address;
119
124
  }
125
+ if (walletProvider?.[core_1.CHAIN_TYPE.BITCOIN]?.core &&
126
+ this.adapterStore?.[core_1.BLOCKCHAIN_NAME.BITCOIN]) {
127
+ const store = this.adapterStore[core_1.BLOCKCHAIN_NAME.BITCOIN];
128
+ store.wallet = walletProvider[core_1.CHAIN_TYPE.BITCOIN].core;
129
+ store.walletAddress = walletProvider[core_1.CHAIN_TYPE.BITCOIN].address;
130
+ }
120
131
  }
121
132
  }
122
133
  exports.BlockchainAdapterFactoryService = BlockchainAdapterFactoryService;
@@ -1,6 +1,7 @@
1
1
  import { CHAIN_TYPE } from '@cryptorubic/core';
2
2
  import { SolanaWeb3 } from './solana-web3';
3
3
  import { TronWeb } from 'tronweb';
4
+ import { BtcWallet } from '../../adapters/models/btc-wallet-provider';
4
5
  export interface WalletProviderCore<T = any> {
5
6
  /**
6
7
  * Core provider.
@@ -17,6 +18,7 @@ export type EvmWalletProviderCore = WalletProviderCore<{
17
18
  export type TronWalletProviderCore = WalletProviderCore<typeof TronWeb>;
18
19
  export type SolanaWalletProviderCore = WalletProviderCore<SolanaWeb3>;
19
20
  export type TonWaleltProviderCore = WalletProviderCore<unknown>;
21
+ export type BitcoinWalletProviderCore = WalletProviderCore<BtcWallet>;
20
22
  /**
21
23
  * Stores wallet core and information about current user, used to make `send` transactions.
22
24
  */
@@ -25,6 +27,7 @@ interface IWalletProvider {
25
27
  readonly [CHAIN_TYPE.TRON]?: TronWalletProviderCore;
26
28
  readonly [CHAIN_TYPE.SOLANA]?: SolanaWalletProviderCore;
27
29
  readonly [CHAIN_TYPE.TON]?: TonWaleltProviderCore;
30
+ readonly [CHAIN_TYPE.BITCOIN]?: BitcoinWalletProviderCore;
28
31
  }
29
32
  export type WalletProvider = Partial<IWalletProvider>;
30
33
  export {};
@@ -65,7 +65,7 @@ exports.viemBlockchainMapping = {
65
65
  [core_1.BLOCKCHAIN_NAME.ROOTSTOCK]: chain_configs_1.viemConfig[core_1.BLOCKCHAIN_NAME.ROOTSTOCK],
66
66
  [core_1.BLOCKCHAIN_NAME.MODE]: chains_1.mode,
67
67
  [core_1.BLOCKCHAIN_NAME.ZK_FAIR]: chains_1.zkFair,
68
- [core_1.BLOCKCHAIN_NAME.ZK_LINK]: chain_configs_1.viemConfig[core_1.BLOCKCHAIN_NAME.ZK_LINK],
68
+ [core_1.BLOCKCHAIN_NAME.ZK_LINK]: chains_1.zkLinkNova,
69
69
  [core_1.BLOCKCHAIN_NAME.XLAYER]: chain_configs_1.viemConfig[core_1.BLOCKCHAIN_NAME.XLAYER], // viem xLayer config without multicall address
70
70
  [core_1.BLOCKCHAIN_NAME.BAHAMUT]: chain_configs_1.viemConfig[core_1.BLOCKCHAIN_NAME.BAHAMUT],
71
71
  [core_1.BLOCKCHAIN_NAME.BITLAYER]: chain_configs_1.viemConfig[core_1.BLOCKCHAIN_NAME.BITLAYER],