@rabby-wallet/rabby-bridge 0.0.13-alpha.0 → 0.0.13

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.
Files changed (198) hide show
  1. package/README.md +1 -131
  2. package/dist/chains.d.ts +2 -1
  3. package/dist/chains.js +2 -0
  4. package/dist/data.d.ts +3 -0
  5. package/dist/data.js +3 -0
  6. package/dist/index.d.ts +1 -7
  7. package/dist/index.js +0 -3
  8. package/dist/quote.d.ts +4 -18
  9. package/dist/quote.js +65 -282
  10. package/package.json +3 -13
  11. package/dist/calldata/abi.d.ts +0 -29
  12. package/dist/calldata/abi.js +0 -160
  13. package/dist/calldata/across/deposit.d.ts +0 -2
  14. package/dist/calldata/across/deposit.js +0 -36
  15. package/dist/calldata/across/depositNative.d.ts +0 -2
  16. package/dist/calldata/across/depositNative.js +0 -45
  17. package/dist/calldata/across/depositNow.d.ts +0 -2
  18. package/dist/calldata/across/depositNow.js +0 -35
  19. package/dist/calldata/across/depositV3.d.ts +0 -2
  20. package/dist/calldata/across/depositV3.js +0 -35
  21. package/dist/calldata/across/depositV3Now.d.ts +0 -2
  22. package/dist/calldata/across/depositV3Now.js +0 -34
  23. package/dist/calldata/across/index.d.ts +0 -4
  24. package/dist/calldata/across/index.js +0 -31
  25. package/dist/calldata/across/swapAndBridge.d.ts +0 -2
  26. package/dist/calldata/across/swapAndBridge.js +0 -70
  27. package/dist/calldata/across/validate.d.ts +0 -3
  28. package/dist/calldata/across/validate.js +0 -30
  29. package/dist/calldata/chains.d.ts +0 -2
  30. package/dist/calldata/chains.js +0 -35
  31. package/dist/calldata/destination.d.ts +0 -6
  32. package/dist/calldata/destination.js +0 -148
  33. package/dist/calldata/diagnostics.d.ts +0 -4
  34. package/dist/calldata/diagnostics.js +0 -18
  35. package/dist/calldata/expect.d.ts +0 -25
  36. package/dist/calldata/expect.js +0 -129
  37. package/dist/calldata/hex.d.ts +0 -6
  38. package/dist/calldata/hex.js +0 -46
  39. package/dist/calldata/index.d.ts +0 -20
  40. package/dist/calldata/index.js +0 -85
  41. package/dist/calldata/lifi/across/acrossV4Erc20Min.d.ts +0 -2
  42. package/dist/calldata/lifi/across/acrossV4Erc20Min.js +0 -26
  43. package/dist/calldata/lifi/across/acrossV4NativeMin.d.ts +0 -2
  44. package/dist/calldata/lifi/across/acrossV4NativeMin.js +0 -22
  45. package/dist/calldata/lifi/across/index.d.ts +0 -6
  46. package/dist/calldata/lifi/across/index.js +0 -19
  47. package/dist/calldata/lifi/allbridge/index.d.ts +0 -3
  48. package/dist/calldata/lifi/allbridge/index.js +0 -26
  49. package/dist/calldata/lifi/celer/index.d.ts +0 -4
  50. package/dist/calldata/lifi/celer/index.js +0 -10
  51. package/dist/calldata/lifi/centrifuge/index.d.ts +0 -3
  52. package/dist/calldata/lifi/centrifuge/index.js +0 -22
  53. package/dist/calldata/lifi/frax/index.d.ts +0 -4
  54. package/dist/calldata/lifi/frax/index.js +0 -29
  55. package/dist/calldata/lifi/garden/index.d.ts +0 -3
  56. package/dist/calldata/lifi/garden/index.js +0 -22
  57. package/dist/calldata/lifi/gaszip/index.d.ts +0 -6
  58. package/dist/calldata/lifi/gaszip/index.js +0 -15
  59. package/dist/calldata/lifi/index.d.ts +0 -4
  60. package/dist/calldata/lifi/index.js +0 -60
  61. package/dist/calldata/lifi/intents/index.d.ts +0 -4
  62. package/dist/calldata/lifi/intents/index.js +0 -10
  63. package/dist/calldata/lifi/layerswap/index.d.ts +0 -4
  64. package/dist/calldata/lifi/layerswap/index.js +0 -10
  65. package/dist/calldata/lifi/m0/index.d.ts +0 -3
  66. package/dist/calldata/lifi/m0/index.js +0 -33
  67. package/dist/calldata/lifi/mayan/index.d.ts +0 -4
  68. package/dist/calldata/lifi/mayan/index.js +0 -10
  69. package/dist/calldata/lifi/method.d.ts +0 -6
  70. package/dist/calldata/lifi/method.js +0 -16
  71. package/dist/calldata/lifi/native/index.d.ts +0 -4
  72. package/dist/calldata/lifi/native/index.js +0 -80
  73. package/dist/calldata/lifi/params.d.ts +0 -30
  74. package/dist/calldata/lifi/params.js +0 -370
  75. package/dist/calldata/lifi/paxos/index.d.ts +0 -4
  76. package/dist/calldata/lifi/paxos/index.js +0 -10
  77. package/dist/calldata/lifi/polymer/index.d.ts +0 -4
  78. package/dist/calldata/lifi/polymer/index.js +0 -10
  79. package/dist/calldata/lifi/relay/index.d.ts +0 -6
  80. package/dist/calldata/lifi/relay/index.js +0 -15
  81. package/dist/calldata/lifi/shape.d.ts +0 -4
  82. package/dist/calldata/lifi/shape.js +0 -31
  83. package/dist/calldata/lifi/squid/index.d.ts +0 -6
  84. package/dist/calldata/lifi/squid/index.js +0 -15
  85. package/dist/calldata/lifi/stargate/index.d.ts +0 -5
  86. package/dist/calldata/lifi/stargate/index.js +0 -15
  87. package/dist/calldata/lifi/swap/index.d.ts +0 -5
  88. package/dist/calldata/lifi/swap/index.js +0 -18
  89. package/dist/calldata/lifi/swap/swapMethod.d.ts +0 -2
  90. package/dist/calldata/lifi/swap/swapMethod.js +0 -40
  91. package/dist/calldata/match.d.ts +0 -3
  92. package/dist/calldata/match.js +0 -21
  93. package/dist/calldata/mayan/destination.d.ts +0 -2
  94. package/dist/calldata/mayan/destination.js +0 -13
  95. package/dist/calldata/mayan/fastMctpBridge.d.ts +0 -3
  96. package/dist/calldata/mayan/fastMctpBridge.js +0 -43
  97. package/dist/calldata/mayan/fastMctpCreateOrder.d.ts +0 -3
  98. package/dist/calldata/mayan/fastMctpCreateOrder.js +0 -39
  99. package/dist/calldata/mayan/forward.d.ts +0 -8
  100. package/dist/calldata/mayan/forward.js +0 -35
  101. package/dist/calldata/mayan/forwardERC20.d.ts +0 -2
  102. package/dist/calldata/mayan/forwardERC20.js +0 -19
  103. package/dist/calldata/mayan/forwardEth.d.ts +0 -2
  104. package/dist/calldata/mayan/forwardEth.js +0 -16
  105. package/dist/calldata/mayan/index.d.ts +0 -4
  106. package/dist/calldata/mayan/index.js +0 -21
  107. package/dist/calldata/mayan/mctp.d.ts +0 -5
  108. package/dist/calldata/mayan/mctp.js +0 -41
  109. package/dist/calldata/mayan/readProtocol.d.ts +0 -2
  110. package/dist/calldata/mayan/readProtocol.js +0 -29
  111. package/dist/calldata/mayan/swapAndForwardERC20.d.ts +0 -2
  112. package/dist/calldata/mayan/swapAndForwardERC20.js +0 -24
  113. package/dist/calldata/mayan/swapAndForwardEth.d.ts +0 -2
  114. package/dist/calldata/mayan/swapAndForwardEth.js +0 -23
  115. package/dist/calldata/mayan/swiftCreateOrder.d.ts +0 -3
  116. package/dist/calldata/mayan/swiftCreateOrder.js +0 -49
  117. package/dist/calldata/mayan/validate.d.ts +0 -3
  118. package/dist/calldata/mayan/validate.js +0 -20
  119. package/dist/calldata/protocols.d.ts +0 -9
  120. package/dist/calldata/protocols.js +0 -56
  121. package/dist/calldata/relay/calls.d.ts +0 -13
  122. package/dist/calldata/relay/calls.js +0 -54
  123. package/dist/calldata/relay/depositErc20.d.ts +0 -2
  124. package/dist/calldata/relay/depositErc20.js +0 -22
  125. package/dist/calldata/relay/depositErc20Allowance.d.ts +0 -2
  126. package/dist/calldata/relay/depositErc20Allowance.js +0 -20
  127. package/dist/calldata/relay/depositNative.d.ts +0 -2
  128. package/dist/calldata/relay/depositNative.js +0 -20
  129. package/dist/calldata/relay/index.d.ts +0 -4
  130. package/dist/calldata/relay/index.js +0 -40
  131. package/dist/calldata/relay/multicall.d.ts +0 -2
  132. package/dist/calldata/relay/multicall.js +0 -15
  133. package/dist/calldata/relay/permit2TransferAndMulticall.d.ts +0 -2
  134. package/dist/calldata/relay/permit2TransferAndMulticall.js +0 -42
  135. package/dist/calldata/relay/permit3009TransferAndMulticall.d.ts +0 -2
  136. package/dist/calldata/relay/permit3009TransferAndMulticall.js +0 -41
  137. package/dist/calldata/relay/permit3009TransferAndMulticallSigned.d.ts +0 -2
  138. package/dist/calldata/relay/permit3009TransferAndMulticallSigned.js +0 -40
  139. package/dist/calldata/relay/permitTransferAndMulticall.d.ts +0 -2
  140. package/dist/calldata/relay/permitTransferAndMulticall.js +0 -34
  141. package/dist/calldata/relay/permitTransferAndMulticallLegacy.d.ts +0 -2
  142. package/dist/calldata/relay/permitTransferAndMulticallLegacy.js +0 -35
  143. package/dist/calldata/relay/transferAndMulticall.d.ts +0 -2
  144. package/dist/calldata/relay/transferAndMulticall.js +0 -26
  145. package/dist/calldata/relay/validate.d.ts +0 -3
  146. package/dist/calldata/relay/validate.js +0 -18
  147. package/dist/calldata/resolve.d.ts +0 -2
  148. package/dist/calldata/resolve.js +0 -28
  149. package/dist/calldata/socket/bridge.d.ts +0 -2
  150. package/dist/calldata/socket/bridge.js +0 -28
  151. package/dist/calldata/socket/exec.d.ts +0 -2
  152. package/dist/calldata/socket/exec.js +0 -71
  153. package/dist/calldata/socket/index.d.ts +0 -4
  154. package/dist/calldata/socket/index.js +0 -13
  155. package/dist/calldata/socket/params.d.ts +0 -5
  156. package/dist/calldata/socket/params.js +0 -14
  157. package/dist/calldata/socket/protocols/ccip.d.ts +0 -2
  158. package/dist/calldata/socket/protocols/ccip.js +0 -32
  159. package/dist/calldata/socket/protocols/cctp.d.ts +0 -2
  160. package/dist/calldata/socket/protocols/cctp.js +0 -24
  161. package/dist/calldata/socket/protocols/eco.d.ts +0 -2
  162. package/dist/calldata/socket/protocols/eco.js +0 -20
  163. package/dist/calldata/socket/protocols/index.d.ts +0 -3
  164. package/dist/calldata/socket/protocols/index.js +0 -81
  165. package/dist/calldata/socket/protocols/native.d.ts +0 -2
  166. package/dist/calldata/socket/protocols/native.js +0 -70
  167. package/dist/calldata/socket/protocols/oft.d.ts +0 -2
  168. package/dist/calldata/socket/protocols/oft.js +0 -31
  169. package/dist/calldata/socket/protocols/swapsXYZ.d.ts +0 -2
  170. package/dist/calldata/socket/protocols/swapsXYZ.js +0 -62
  171. package/dist/calldata/socket/swapAndBridge.d.ts +0 -2
  172. package/dist/calldata/socket/swapAndBridge.js +0 -37
  173. package/dist/calldata/socket/validate.d.ts +0 -3
  174. package/dist/calldata/socket/validate.js +0 -21
  175. package/dist/calldata/types.d.ts +0 -82
  176. package/dist/calldata/types.js +0 -20
  177. package/dist/errors/constants.d.ts +0 -876
  178. package/dist/errors/constants.js +0 -883
  179. package/dist/errors/index.d.ts +0 -61
  180. package/dist/errors/index.js +0 -53
  181. package/dist/errors/sanitize.d.ts +0 -3
  182. package/dist/errors/sanitize.js +0 -75
  183. package/dist/providers/data.d.ts +0 -23
  184. package/dist/providers/data.js +0 -116
  185. package/dist/providers/errors.d.ts +0 -7
  186. package/dist/providers/errors.js +0 -10
  187. package/dist/providers/index.d.ts +0 -7
  188. package/dist/providers/index.js +0 -340
  189. package/dist/providers/layerswap.d.ts +0 -9
  190. package/dist/providers/layerswap.js +0 -95
  191. package/dist/providers/relay.d.ts +0 -59
  192. package/dist/providers/relay.js +0 -185
  193. package/dist/providers/request.d.ts +0 -23
  194. package/dist/providers/request.js +0 -69
  195. package/dist/providers/socket.d.ts +0 -5
  196. package/dist/providers/socket.js +0 -57
  197. package/dist/providers/types.d.ts +0 -36
  198. package/dist/providers/types.js +0 -1
package/dist/quote.js CHANGED
@@ -1,21 +1,14 @@
1
- import { BRIDGE_ERRORS, BridgeError, asBridgeError, reportBridgeError } from './errors/index.js';
2
- import { CALLDATA_AGGREGATORS, InvalidBridgeCalldataError, validateBridgeCalldata, } from './calldata/index.js';
3
- import { calldataDiagnostics } from './calldata/diagnostics.js';
4
- import { InvalidBridgeProviderError } from './providers/errors.js';
5
- import { SOCKET_PROVIDER_ROUTES } from './providers/socket.js';
6
1
  import { BRIDGE_ENUM } from './consts.js';
7
2
  import { getBridgeAltContracts, getBridgeRouter, getBridgeSpender, isSupportedBridgeAggregator, isSupportedBridgeChain, } from './list.js';
8
- export class InvalidBridgeContractError extends BridgeError {
3
+ export class InvalidBridgeContractError extends Error {
9
4
  constructor(kind, aggregatorId, chainId, expected, received, bridgeId) {
10
- super(kind === 'router' ? BRIDGE_ERRORS.ROUTER_NOT_ALLOWED : BRIDGE_ERRORS.SPENDER_NOT_ALLOWED, { aggregatorId, chainId, bridgeId });
5
+ super(`Invalid bridge ${kind} for ${aggregatorId} on ${chainId}: expected ${expected}, got ${received}`);
11
6
  this.kind = kind;
12
7
  this.aggregatorId = aggregatorId;
13
8
  this.chainId = chainId;
14
9
  this.expected = expected;
15
10
  this.received = received;
16
11
  this.bridgeId = bridgeId;
17
- this.message =
18
- `Invalid bridge ${kind} for ${aggregatorId} on ${chainId}: expected ${expected}, got ${received}`;
19
12
  this.name = 'InvalidBridgeContractError';
20
13
  }
21
14
  }
@@ -27,19 +20,15 @@ const isSameAddress = (left, right) => {
27
20
  };
28
21
  function assertSupported(aggregatorId, fromChainId) {
29
22
  if (!isSupportedBridgeAggregator(aggregatorId)) {
30
- const error = new BridgeError(BRIDGE_ERRORS.UNSUPPORTED_BRIDGE_AGGREGATOR, { aggregatorId, chainId: fromChainId });
31
- error.message = `${aggregatorId} is not supported`;
32
- throw error;
23
+ throw new Error(`${aggregatorId} is not supported`);
33
24
  }
34
25
  if (!isSupportedBridgeChain(aggregatorId, fromChainId)) {
35
- const error = new BridgeError(BRIDGE_ERRORS.UNSUPPORTED_SOURCE_CHAIN, { aggregatorId, chainId: fromChainId });
36
- error.message = `${aggregatorId} does not support ${fromChainId}`;
37
- throw error;
26
+ throw new Error(`${aggregatorId} does not support ${fromChainId}`);
38
27
  }
39
28
  }
40
29
  const requireSlippage = (slippage) => {
41
30
  if (!slippage) {
42
- throw new BridgeError(BRIDGE_ERRORS.SLIPPAGE_IS_REQUIRED_FOR_THIS_API_CALL);
31
+ throw new Error('slippage is required for this API call');
43
32
  }
44
33
  return slippage;
45
34
  };
@@ -50,22 +39,13 @@ const stringifyQuoteKey = (quoteKey) => {
50
39
  return JSON.stringify(quoteKey || {});
51
40
  };
52
41
  const shouldValidateBridgeContracts = (aggregatorId) => aggregatorId !== BRIDGE_ENUM.NEAR_INTENTS;
53
- const handleNewValidationError = (error, options, context) => {
54
- if (!options.lite)
55
- throw error;
56
- reportBridgeError(options.onError, asBridgeError(error), { ...context, lite: true, blocking: false });
57
- };
58
- export const validateBridgeQuote = (aggregatorId, fromChainId, quote, options = {}) => {
42
+ export const validateBridgeQuote = (aggregatorId, fromChainId, quote) => {
59
43
  if (!shouldValidateBridgeContracts(aggregatorId)) {
60
44
  return true;
61
45
  }
62
46
  const expectedSpender = getBridgeSpender(aggregatorId, fromChainId);
63
47
  const receivedSpender = quote.approve_contract_id;
64
- if (!receivedSpender) {
65
- return true;
66
- }
67
- if (!expectedSpender) {
68
- handleNewValidationError(new InvalidBridgeContractError('spender', aggregatorId, fromChainId, 'configured spender', receivedSpender, quote.bridge_id), options, { aggregatorId, chainId: fromChainId, bridgeId: quote.bridge_id, operation: 'getQuote' });
48
+ if (!expectedSpender || !receivedSpender) {
69
49
  return true;
70
50
  }
71
51
  const allowedSpenders = [
@@ -77,273 +57,81 @@ export const validateBridgeQuote = (aggregatorId, fromChainId, quote, options =
77
57
  }
78
58
  return true;
79
59
  };
80
- const quotedToAmount = (quoteKey) => {
81
- let key = quoteKey;
82
- if (typeof key === 'string') {
83
- try {
84
- key = JSON.parse(key);
85
- }
86
- catch {
87
- return undefined;
88
- }
89
- }
90
- if (!key || typeof key !== 'object' || Array.isArray(key))
91
- return undefined;
92
- const amount = key.to_token_raw_amount;
93
- if (typeof amount === 'string' || (typeof amount === 'number' && Number.isSafeInteger(amount))) {
94
- return String(amount);
95
- }
96
- return undefined;
97
- };
98
- const validateBridgeRouter = (aggregatorId, fromChainId, bridgeId, tx, legacy = false) => {
60
+ export const validateBridgeTx = (aggregatorId, fromChainId, bridgeId, tx) => {
99
61
  if (!shouldValidateBridgeContracts(aggregatorId)) {
100
- return undefined;
62
+ return true;
101
63
  }
102
64
  const expectedRouter = getBridgeRouter(aggregatorId, fromChainId);
103
- if (legacy && !expectedRouter)
104
- return;
65
+ if (!expectedRouter) {
66
+ return true;
67
+ }
105
68
  const allowedRouters = [
106
- ...(expectedRouter ? [expectedRouter] : []),
69
+ expectedRouter,
107
70
  ...getBridgeAltContracts(aggregatorId),
108
71
  ];
109
72
  if (!allowedRouters.some((addr) => isSameAddress(addr, tx.to))) {
110
- throw asBridgeError(new InvalidBridgeContractError('router', aggregatorId, fromChainId, expectedRouter || allowedRouters.join(',') || 'configured router', tx.to, bridgeId), BRIDGE_ERRORS.ROUTER_NOT_ALLOWED, calldataDiagnostics(tx.data));
111
- }
112
- };
113
- const checkBridgeTx = (aggregatorId, fromChainId, bridgeId, tx, expectation, options = {}, operation = 'verifyTx') => {
114
- const context = { aggregatorId, chainId: fromChainId, toChainId: expectation?.toChainId, bridgeId, operation,
115
- ...calldataDiagnostics(tx.data) };
116
- // A configured-router mismatch was already blocking on main; never suppress it.
117
- if (options.lite)
118
- validateBridgeRouter(aggregatorId, fromChainId, bridgeId, tx, true);
119
- try {
120
- validateBridgeRouter(aggregatorId, fromChainId, bridgeId, tx);
121
- }
122
- catch (error) {
123
- handleNewValidationError(error, options, context);
73
+ throw new InvalidBridgeContractError('router', aggregatorId, fromChainId, expectedRouter, tx.to, bridgeId);
124
74
  }
125
- if (CALLDATA_AGGREGATORS.includes(aggregatorId) || options.lite) {
126
- let check;
127
- try {
128
- check = validateBridgeCalldata(aggregatorId, fromChainId, tx, expectation);
129
- }
130
- catch (error) {
131
- handleNewValidationError(error, options, context);
132
- return undefined;
133
- }
134
- if (!check.ok) {
135
- handleNewValidationError(new InvalidBridgeCalldataError(aggregatorId, fromChainId, check.method, check.reason || BRIDGE_ERRORS.INVALID_CALLDATA.message, check.errors.map((error) => ({ ...error, bridgeId }))), options, context);
136
- }
137
- return check;
138
- }
139
- return undefined;
140
- };
141
- export const validateBridgeTx = (aggregatorId, fromChainId, bridgeId, tx, expectation, options = {}) => {
142
- checkBridgeTx(aggregatorId, fromChainId, bridgeId, tx, expectation, options);
143
75
  return true;
144
76
  };
145
77
  export const getQuote = async (aggregatorId, params, api) => {
146
- try {
147
- params = { ...params };
148
- assertSupported(aggregatorId, params.fromChainId);
149
- let assertContext;
78
+ assertSupported(aggregatorId, params.fromChainId);
79
+ const baseParams = {
80
+ aggregator_id: aggregatorId,
81
+ user_addr: params.userAddress,
82
+ from_chain_id: params.fromChainId,
83
+ from_token_id: params.fromTokenId,
84
+ from_token_raw_amount: params.fromTokenRawAmount,
85
+ to_chain_id: params.toChainId,
86
+ to_token_id: params.toTokenId,
87
+ fee_rate: params.feeRate,
88
+ slippage: requireSlippage(params.slippage),
89
+ };
90
+ const quotes = api.getBridgeQuoteListV2
91
+ ? await api.getBridgeQuoteListV2(baseParams)
92
+ : await api.getBridgeQuoteV2?.(baseParams);
93
+ if (!quotes) {
94
+ throw new Error('Bridge API does not provide a quote list method');
95
+ }
96
+ return quotes.filter((quote) => {
150
97
  try {
151
- assertContext = params.providerClient?.captureContext();
98
+ validateBridgeQuote(aggregatorId, params.fromChainId, quote);
99
+ return true;
152
100
  }
153
101
  catch (error) {
154
- handleNewValidationError(error, params, { aggregatorId, chainId: params.fromChainId, toChainId: params.toChainId, operation: 'getQuote' });
155
- }
156
- if (aggregatorId === BRIDGE_ENUM.RELAY && !params.lite) {
157
- if (!params.providerClient)
158
- throw new InvalidBridgeProviderError('relay', BRIDGE_ERRORS.DIRECT_PROVIDER_CLIENT_IS_REQUIRED);
159
- const quotes = await params.providerClient.getQuotes('relay', params);
160
- try {
161
- assertContext?.();
162
- }
163
- catch (error) {
164
- handleNewValidationError(error, params, { aggregatorId, chainId: params.fromChainId, toChainId: params.toChainId, operation: 'getQuote' });
102
+ if (error instanceof InvalidBridgeContractError) {
103
+ return false;
165
104
  }
166
- return quotes;
167
- }
168
- const baseParams = {
169
- aggregator_id: aggregatorId,
170
- user_addr: params.userAddress,
171
- from_chain_id: params.fromChainId,
172
- from_token_id: params.fromTokenId,
173
- from_token_raw_amount: params.fromTokenRawAmount,
174
- to_chain_id: params.toChainId,
175
- to_token_id: params.toTokenId,
176
- fee_rate: params.feeRate,
177
- slippage: requireSlippage(params.slippage),
178
- };
179
- const [backendQuotes, providerQuotes] = await Promise.all([
180
- api.getBridgeQuoteListV2
181
- ? api.getBridgeQuoteListV2(baseParams).catch((error) => { throw asBridgeError(error, BRIDGE_ERRORS.BACKEND_QUOTE_REQUEST_FAILED, { requestKind: 'backend_quote' }); })
182
- : api.getBridgeQuoteV2?.(baseParams).catch((error) => { throw asBridgeError(error, BRIDGE_ERRORS.BACKEND_QUOTE_REQUEST_FAILED, { requestKind: 'backend_quote' }); }),
183
- aggregatorId === BRIDGE_ENUM.SOCKET && params.providerClient && !params.lite
184
- ? params.providerClient.getQuotes('socket', params).catch((error) => {
185
- if (error instanceof InvalidBridgeProviderError) {
186
- reportBridgeError(params.onError, error, { aggregatorId, chainId: params.fromChainId, toChainId: params.toChainId, operation: 'getQuote' });
187
- return [];
188
- }
189
- throw error;
190
- })
191
- : Promise.resolve([]),
192
- ]);
193
- try {
194
- assertContext?.();
195
- }
196
- catch (error) {
197
- handleNewValidationError(error, params, { aggregatorId, chainId: params.fromChainId, toChainId: params.toChainId, operation: 'getQuote' });
198
- }
199
- if (!backendQuotes) {
200
- throw new BridgeError(BRIDGE_ERRORS.MISSING_QUOTE_API);
105
+ throw error;
201
106
  }
202
- const quotes = [
203
- ...backendQuotes.filter((quote) => !(aggregatorId === BRIDGE_ENUM.SOCKET && params.providerClient && !params.lite &&
204
- SOCKET_PROVIDER_ROUTES.includes(quote.bridge_id))),
205
- ...providerQuotes,
206
- ];
207
- return quotes.filter((quote) => {
208
- try {
209
- validateBridgeQuote(aggregatorId, params.fromChainId, quote, params);
210
- return true;
211
- }
212
- catch (error) {
213
- if (error instanceof InvalidBridgeContractError) {
214
- reportBridgeError(params.onError, error, { aggregatorId, chainId: params.fromChainId, toChainId: params.toChainId, bridgeId: quote.bridge_id, operation: 'getQuote', ...(params.lite ? { lite: true, blocking: true } : {}) });
215
- return false;
216
- }
217
- throw error;
218
- }
219
- });
220
- }
221
- catch (error) {
222
- throw asBridgeError(error, BRIDGE_ERRORS.UNKNOWN, { aggregatorId, chainId: params.fromChainId, toChainId: params.toChainId, operation: 'getQuote', ...(params.lite ? { lite: true, blocking: true } : {}) });
223
- }
107
+ });
224
108
  };
225
109
  export const buildTx = async (aggregatorId, params, api) => {
226
- try {
227
- // Freeze signing intent before awaiting a backend response.
228
- params = { ...params };
229
- assertSupported(aggregatorId, params.fromChainId);
230
- let assertContext;
231
- try {
232
- assertContext = params.providerClient?.captureContext();
233
- }
234
- catch (error) {
235
- handleNewValidationError(error, params, { aggregatorId, chainId: params.fromChainId, toChainId: params.toChainId, operation: 'buildTx' });
236
- }
237
- if (!params.lite && (aggregatorId === BRIDGE_ENUM.RELAY ||
238
- (aggregatorId === BRIDGE_ENUM.SOCKET && SOCKET_PROVIDER_ROUTES.includes(params.bridgeId)))) {
239
- if (!params.providerClient)
240
- throw new InvalidBridgeProviderError(aggregatorId, BRIDGE_ERRORS.DIRECT_PROVIDER_CLIENT_IS_REQUIRED);
241
- const tx = await params.providerClient.buildTx(aggregatorId, params);
242
- try {
243
- assertContext?.();
244
- }
245
- catch (error) {
246
- handleNewValidationError(error, params, { aggregatorId, chainId: params.fromChainId, toChainId: params.toChainId, operation: 'buildTx' });
247
- }
248
- return tx;
249
- }
250
- const buildParams = {
251
- aggregator_id: aggregatorId,
252
- bridge_id: params.bridgeId,
253
- user_addr: params.userAddress,
254
- from_chain_id: params.fromChainId,
255
- from_token_id: params.fromTokenId,
256
- from_token_raw_amount: params.fromTokenRawAmount,
257
- to_chain_id: params.toChainId,
258
- to_token_id: params.toTokenId,
259
- slippage: requireSlippage(params.slippage),
260
- };
261
- const tx = api.buildBridgeTx
262
- ? await api.buildBridgeTx({
263
- ...buildParams,
264
- quote_key: stringifyQuoteKey(params.quoteKey),
265
- }).catch((error) => { throw asBridgeError(error, BRIDGE_ERRORS.BACKEND_BUILD_REQUEST_FAILED, { requestKind: 'backend_build' }); })
266
- : (await api.getBridgeQuoteTxV2?.({
267
- ...buildParams,
268
- }).catch((error) => { throw asBridgeError(error, BRIDGE_ERRORS.BACKEND_BUILD_REQUEST_FAILED, { requestKind: 'backend_build' }); }))?.tx;
269
- if (!tx) {
270
- throw new BridgeError(BRIDGE_ERRORS.MISSING_BUILD_API);
271
- }
272
- try {
273
- assertContext?.();
274
- }
275
- catch (error) {
276
- handleNewValidationError(error, params, { aggregatorId, chainId: params.fromChainId, toChainId: params.toChainId, operation: 'buildTx' });
277
- }
278
- const expectation = {
279
- userAddress: params.userAddress,
280
- fromTokenId: params.fromTokenId,
281
- fromTokenRawAmount: params.fromTokenRawAmount,
282
- toChainId: params.toChainId,
283
- toTokenId: params.toTokenId,
284
- toTokenRawAmount: params.toTokenRawAmount ?? quotedToAmount(params.quoteKey),
285
- slippage: params.slippage,
286
- };
287
- const check = checkBridgeTx(aggregatorId, params.fromChainId, params.bridgeId, tx, expectation, params, 'buildTx');
288
- // A backend may mislabel bridge_id. Decide from calldata as well, so renaming
289
- // an RFQ/CCTP/LayerSwap route cannot bypass the provider requirement.
290
- const parsed = check?.parsed;
291
- if (params.lite && (aggregatorId === BRIDGE_ENUM.RELAY ||
292
- (aggregatorId === BRIDGE_ENUM.SOCKET && SOCKET_PROVIDER_ROUTES.includes(params.bridgeId)))) {
293
- try {
294
- if (!params.providerClient)
295
- throw new InvalidBridgeProviderError(aggregatorId, BRIDGE_ERRORS.DIRECT_PROVIDER_CLIENT_IS_REQUIRED);
296
- params.providerClient.verifyTx(aggregatorId, params, tx);
297
- }
298
- catch (error) {
299
- handleNewValidationError(error, params, { aggregatorId, chainId: params.fromChainId,
300
- toChainId: params.toChainId, bridgeId: params.bridgeId, operation: 'buildTx' });
301
- }
302
- return tx;
303
- }
304
- try {
305
- if (aggregatorId === BRIDGE_ENUM.LIFI && parsed?.method.endsWith('ViaLayerSwap')) {
306
- if (!params.providerClient)
307
- throw new InvalidBridgeProviderError('layerswap', BRIDGE_ERRORS.DIRECT_PROVIDER_CLIENT_IS_REQUIRED);
308
- const verification = params.providerClient.verifyLayerSwapTx({
309
- ...params, toTokenRawAmount: expectation.toTokenRawAmount,
310
- }, params.lite ? { ...tx } : tx);
311
- if (params.lite) {
312
- void verification.then(() => assertContext?.()).catch((error) => {
313
- handleNewValidationError(error, params, { aggregatorId, chainId: params.fromChainId,
314
- toChainId: params.toChainId, bridgeId: params.bridgeId, operation: 'buildTx' });
315
- });
316
- return tx;
317
- }
318
- await verification;
319
- try {
320
- assertContext?.();
321
- }
322
- catch (error) {
323
- handleNewValidationError(error, params, { aggregatorId, chainId: params.fromChainId, toChainId: params.toChainId, operation: 'buildTx' });
324
- }
325
- return tx;
326
- }
327
- if (aggregatorId === BRIDGE_ENUM.SOCKET && parsed?.unresolvedFields?.length &&
328
- ['receiveERC20', 'depositForBurn'].includes(parsed.protocolMethod ?? '')) {
329
- throw new InvalidBridgeProviderError(aggregatorId, BRIDGE_ERRORS.PROVIDER_DESTINATION_UNBOUND);
330
- }
331
- // shortcut: chain-state output checks are deferred until the follow-up RPC PR.
332
- const unverifiedFields = check?.unverifiedFields?.filter((field) => !(field === 'outputToken' && parsed?.outputToken === undefined && parsed?.outputTokenReference) &&
333
- !(field === 'minOutputAmount' && parsed?.minOutputAmount === undefined && parsed?.outputAmountReference));
334
- if (unverifiedFields?.length) {
335
- throw new InvalidBridgeCalldataError(aggregatorId, params.fromChainId, check?.method, `unverified bridge fields: ${unverifiedFields.join(',')}`, [{ ...BRIDGE_ERRORS.UNVERIFIED_BRIDGE_FIELDS, bridgeId: params.bridgeId, unverifiedFields }]);
336
- }
337
- }
338
- catch (error) {
339
- handleNewValidationError(error, params, { aggregatorId, chainId: params.fromChainId,
340
- toChainId: params.toChainId, bridgeId: params.bridgeId, operation: 'buildTx' });
341
- }
342
- return tx;
343
- }
344
- catch (error) {
345
- throw asBridgeError(error, BRIDGE_ERRORS.UNKNOWN, { aggregatorId, chainId: params.fromChainId, toChainId: params.toChainId, operation: 'buildTx', bridgeId: params.bridgeId, ...(params.lite ? { lite: true, blocking: true } : {}) });
346
- }
110
+ assertSupported(aggregatorId, params.fromChainId);
111
+ const buildParams = {
112
+ aggregator_id: aggregatorId,
113
+ bridge_id: params.bridgeId,
114
+ user_addr: params.userAddress,
115
+ from_chain_id: params.fromChainId,
116
+ from_token_id: params.fromTokenId,
117
+ from_token_raw_amount: params.fromTokenRawAmount,
118
+ to_chain_id: params.toChainId,
119
+ to_token_id: params.toTokenId,
120
+ slippage: requireSlippage(params.slippage),
121
+ };
122
+ const tx = api.buildBridgeTx
123
+ ? await api.buildBridgeTx({
124
+ ...buildParams,
125
+ quote_key: stringifyQuoteKey(params.quoteKey),
126
+ })
127
+ : (await api.getBridgeQuoteTxV2?.({
128
+ ...buildParams,
129
+ }))?.tx;
130
+ if (!tx) {
131
+ throw new Error('Bridge API does not provide a build tx method');
132
+ }
133
+ validateBridgeTx(aggregatorId, params.fromChainId, params.bridgeId, tx);
134
+ return tx;
347
135
  };
348
136
  export const getQuoteListWithTx = async (aggregatorId, params, api) => {
349
137
  const quotes = await getQuote(aggregatorId, params, api);
@@ -353,8 +141,6 @@ export const getQuoteListWithTx = async (aggregatorId, params, api) => {
353
141
  ...params,
354
142
  bridgeId: quote.bridge_id,
355
143
  quoteKey: quote.quote_key,
356
- toTokenRawAmount: quote.to_token_raw_amount_hex_str ??
357
- (Number.isSafeInteger(quote.to_token_raw_amount) ? String(quote.to_token_raw_amount) : undefined),
358
144
  }, api);
359
145
  return {
360
146
  ...quote,
@@ -362,10 +148,7 @@ export const getQuoteListWithTx = async (aggregatorId, params, api) => {
362
148
  };
363
149
  }
364
150
  catch (error) {
365
- if (error instanceof InvalidBridgeContractError ||
366
- error instanceof InvalidBridgeCalldataError ||
367
- error instanceof InvalidBridgeProviderError) {
368
- reportBridgeError(params.onError, error, { aggregatorId, chainId: params.fromChainId, toChainId: params.toChainId, bridgeId: quote.bridge_id, operation: 'buildTx', ...(params.lite ? { lite: true, blocking: true } : {}) });
151
+ if (error instanceof InvalidBridgeContractError) {
369
152
  return null;
370
153
  }
371
154
  throw error;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rabby-wallet/rabby-bridge",
3
- "version": "0.0.13-alpha.0",
3
+ "version": "0.0.13",
4
4
  "description": "Bridge quote helpers and contract allowlists for Rabby",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -22,13 +22,7 @@
22
22
  "scripts": {
23
23
  "prepublishOnly": "yarn build",
24
24
  "build": "rimraf dist && tsc",
25
- "test": "yarn build && NODE_OPTIONS=--experimental-vm-modules jest --runInBand --watchman=false",
26
- "test:bridge-calldata": "yarn build && NODE_OPTIONS=--experimental-vm-modules jest --runInBand --watchman=false tests/calldata",
27
- "test:bridge-calldata:lifi": "yarn test:bridge-calldata --testNamePattern='\\[LiFi\\]'",
28
- "test:bridge-calldata:socket": "yarn test:bridge-calldata --testNamePattern='\\[Socket\\]'",
29
- "test:bridge-calldata:relay": "yarn test:bridge-calldata --testNamePattern='\\[Relay\\]'",
30
- "test:bridge-calldata:across": "yarn test:bridge-calldata --testNamePattern='\\[Across\\]'",
31
- "test:bridge-calldata:mayan": "yarn test:bridge-calldata --testNamePattern='\\[Mayan\\]'"
25
+ "test": "yarn build && NODE_OPTIONS=--experimental-vm-modules jest --runInBand --watchman=false"
32
26
  },
33
27
  "devDependencies": {
34
28
  "@debank/common": "^0.3.60",
@@ -38,9 +32,5 @@
38
32
  "rimraf": "^3.0.2",
39
33
  "typescript": "^5.8.3"
40
34
  },
41
- "packageManager": "yarn@4.12.0",
42
- "dependencies": {
43
- "@ethersproject/hash": "5.8.0",
44
- "@ethersproject/strings": "5.8.0"
45
- }
35
+ "packageManager": "yarn@4.12.0"
46
36
  }
@@ -1,29 +0,0 @@
1
- import type { ParsedBridgeCall } from './types.js';
2
- export type AbiParam = {
3
- name: string;
4
- kind: 'address' | 'uint' | 'bool' | 'bytes' | 'string' | 'array' | 'tuple';
5
- size?: number;
6
- length?: number;
7
- item?: AbiParam;
8
- components?: AbiParam[];
9
- };
10
- export type AbiValue = string | bigint | boolean | AbiValue[] | {
11
- [key: string]: AbiValue;
12
- };
13
- export declare const decodeCall: (params: AbiParam[], calldata: string) => {
14
- [key: string]: AbiValue;
15
- };
16
- export declare const decodeParameters: (params: AbiParam[], data: string) => {
17
- [key: string]: AbiValue;
18
- };
19
- export declare const asRecord: (value: AbiValue) => {
20
- [key: string]: AbiValue;
21
- };
22
- export declare const asArray: (value: AbiValue) => AbiValue[];
23
- export declare const asBigint: (value: AbiValue) => bigint;
24
- export declare const asString: (value: AbiValue) => string;
25
- export type CalldataMethod = {
26
- name: string;
27
- selector: string;
28
- decode: (data: string, value: bigint) => ParsedBridgeCall;
29
- };
@@ -1,160 +0,0 @@
1
- import { BRIDGE_ERRORS, BridgeError } from '../errors/index.js';
2
- import { toUtf8String, Utf8ErrorFuncs } from '@ethersproject/strings';
3
- import { bytesToHex, hexToBytes } from './hex.js';
4
- const isDynamic = (param) => {
5
- if (param.kind === 'string') {
6
- return true;
7
- }
8
- if (param.kind === 'bytes') {
9
- return param.size === undefined;
10
- }
11
- if (param.kind === 'array') {
12
- return param.length === undefined || isDynamic(param.item);
13
- }
14
- if (param.kind === 'tuple') {
15
- return (param.components ?? []).some(isDynamic);
16
- }
17
- return false;
18
- };
19
- const staticWordCount = (param) => {
20
- if (isDynamic(param)) {
21
- return 1;
22
- }
23
- if (param.kind === 'tuple') {
24
- return (param.components ?? []).reduce((sum, item) => sum + staticWordCount(item), 0);
25
- }
26
- if (param.kind === 'array') {
27
- return (param.length ?? 0) * staticWordCount(param.item);
28
- }
29
- return 1;
30
- };
31
- const readWord = (buf, offset) => {
32
- if (offset < 0 || offset + 32 > buf.length) {
33
- throw new BridgeError(BRIDGE_ERRORS.ABI_WORD_OUT_OF_BOUNDS, { abiOffset: offset, abiBufferBytes: buf.length });
34
- }
35
- let value = 0n;
36
- for (let index = 0; index < 32; index += 1) {
37
- value = (value << 8n) + BigInt(buf[offset + index]);
38
- }
39
- return value;
40
- };
41
- const toAddress = (word) => {
42
- if (word >= (1n << 160n))
43
- throw new BridgeError(BRIDGE_ERRORS.INVALID_ABI_ADDRESS);
44
- return `0x${word.toString(16).padStart(40, '0')}`;
45
- };
46
- const readByteLength = (buf, offset) => {
47
- const length = readWord(buf, offset);
48
- if (length > BigInt(buf.length)) {
49
- throw new BridgeError(BRIDGE_ERRORS.ABI_BYTES_OUT_OF_BOUNDS, { abiOffset: offset, abiBufferBytes: buf.length });
50
- }
51
- return Number(length);
52
- };
53
- const readDynamicBytes = (buf, offset) => {
54
- const length = readByteLength(buf, offset);
55
- const start = offset + 32;
56
- if (start + length > buf.length) {
57
- throw new BridgeError(BRIDGE_ERRORS.ABI_BYTES_OUT_OF_BOUNDS, { abiOffset: offset, abiBufferBytes: buf.length });
58
- }
59
- return bytesToHex(buf.subarray(start, start + length));
60
- };
61
- const decodeSequence = (params, buf, base) => {
62
- let cursor = base;
63
- const locations = [];
64
- for (const param of params) {
65
- if (isDynamic(param)) {
66
- const relative = readWord(buf, cursor);
67
- if (relative > BigInt(buf.length)) {
68
- throw new BridgeError(BRIDGE_ERRORS.ABI_OFFSET_OUT_OF_BOUNDS, { abiOffset: cursor, abiBufferBytes: buf.length });
69
- }
70
- locations.push(base + Number(relative));
71
- cursor += 32;
72
- }
73
- else {
74
- locations.push(cursor);
75
- cursor += staticWordCount(param) * 32;
76
- }
77
- }
78
- return params.map((param, index) => decodeAt(param, buf, locations[index]));
79
- };
80
- const decodeAt = (param, buf, offset) => {
81
- switch (param.kind) {
82
- case 'address':
83
- return toAddress(readWord(buf, offset));
84
- case 'uint':
85
- return readWord(buf, offset);
86
- case 'bool': {
87
- const word = readWord(buf, offset);
88
- if (word !== 0n && word !== 1n) {
89
- throw new BridgeError(BRIDGE_ERRORS.INVALID_BOOL);
90
- }
91
- return word === 1n;
92
- }
93
- case 'bytes': {
94
- if (param.size === undefined) {
95
- return readDynamicBytes(buf, offset);
96
- }
97
- if (offset + 32 > buf.length) {
98
- throw new BridgeError(BRIDGE_ERRORS.ABI_WORD_OUT_OF_BOUNDS, { abiOffset: offset, abiBufferBytes: buf.length });
99
- }
100
- return bytesToHex(buf.subarray(offset, offset + param.size));
101
- }
102
- case 'string':
103
- return toUtf8String(readDynamicBytes(buf, offset), Utf8ErrorFuncs.replace).replace(/^\uFEFF/, '');
104
- case 'tuple':
105
- return decodeTuple(param.components ?? [], buf, offset);
106
- case 'array': {
107
- const item = param.item;
108
- if (param.length === undefined) {
109
- const length = readByteLength(buf, offset);
110
- if (length > 2048) {
111
- throw new BridgeError(BRIDGE_ERRORS.ABI_ARRAY_TOO_LONG);
112
- }
113
- return decodeSequence(Array.from({ length }, () => item), buf, offset + 32);
114
- }
115
- return decodeSequence(Array.from({ length: param.length }, () => item), buf, offset);
116
- }
117
- default:
118
- throw new BridgeError(BRIDGE_ERRORS.UNSUPPORTED_ABI_TYPE);
119
- }
120
- };
121
- const decodeTuple = (components, buf, offset) => {
122
- const values = decodeSequence(components, buf, offset);
123
- return Object.fromEntries(components.map((component, index) => [component.name, values[index]]));
124
- };
125
- export const decodeCall = (params, calldata) => {
126
- const bytes = hexToBytes(calldata);
127
- if (bytes.length < 4) {
128
- throw new BridgeError(BRIDGE_ERRORS.MISSING_SELECTOR);
129
- }
130
- const values = decodeSequence(params, bytes.subarray(4), 0);
131
- return Object.fromEntries(params.map((param, index) => [param.name, values[index]]));
132
- };
133
- export const decodeParameters = (params, data) => {
134
- const values = decodeSequence(params, hexToBytes(data), 0);
135
- return Object.fromEntries(params.map((param, index) => [param.name, values[index]]));
136
- };
137
- export const asRecord = (value) => {
138
- if (!value || typeof value !== 'object' || Array.isArray(value)) {
139
- throw new BridgeError(BRIDGE_ERRORS.EXPECTED_TUPLE);
140
- }
141
- return value;
142
- };
143
- export const asArray = (value) => {
144
- if (!Array.isArray(value)) {
145
- throw new BridgeError(BRIDGE_ERRORS.EXPECTED_ARRAY);
146
- }
147
- return value;
148
- };
149
- export const asBigint = (value) => {
150
- if (typeof value !== 'bigint') {
151
- throw new BridgeError(BRIDGE_ERRORS.EXPECTED_UINT);
152
- }
153
- return value;
154
- };
155
- export const asString = (value) => {
156
- if (typeof value !== 'string') {
157
- throw new BridgeError(BRIDGE_ERRORS.EXPECTED_STRING);
158
- }
159
- return value;
160
- };
@@ -1,2 +0,0 @@
1
- import type { CalldataMethod } from '../abi.js';
2
- export declare const deposit: CalldataMethod;