@rabby-wallet/rabby-bridge 0.0.13-alpha.1 → 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 -159
  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 -6
  7. package/dist/index.js +0 -3
  8. package/dist/quote.d.ts +4 -26
  9. package/dist/quote.js +67 -200
  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 -34
  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 -211
  33. package/dist/calldata/destinationSwap.d.ts +0 -14
  34. package/dist/calldata/destinationSwap.js +0 -80
  35. package/dist/calldata/diagnostics.d.ts +0 -4
  36. package/dist/calldata/diagnostics.js +0 -18
  37. package/dist/calldata/expect.d.ts +0 -27
  38. package/dist/calldata/expect.js +0 -158
  39. package/dist/calldata/hex.d.ts +0 -6
  40. package/dist/calldata/hex.js +0 -46
  41. package/dist/calldata/index.d.ts +0 -20
  42. package/dist/calldata/index.js +0 -88
  43. package/dist/calldata/lifi/across/acrossV4Erc20Min.d.ts +0 -2
  44. package/dist/calldata/lifi/across/acrossV4Erc20Min.js +0 -26
  45. package/dist/calldata/lifi/across/acrossV4NativeMin.d.ts +0 -2
  46. package/dist/calldata/lifi/across/acrossV4NativeMin.js +0 -22
  47. package/dist/calldata/lifi/across/index.d.ts +0 -6
  48. package/dist/calldata/lifi/across/index.js +0 -19
  49. package/dist/calldata/lifi/allbridge/index.d.ts +0 -3
  50. package/dist/calldata/lifi/allbridge/index.js +0 -26
  51. package/dist/calldata/lifi/celer/index.d.ts +0 -4
  52. package/dist/calldata/lifi/celer/index.js +0 -10
  53. package/dist/calldata/lifi/centrifuge/index.d.ts +0 -3
  54. package/dist/calldata/lifi/centrifuge/index.js +0 -22
  55. package/dist/calldata/lifi/destination.d.ts +0 -5
  56. package/dist/calldata/lifi/destination.js +0 -40
  57. package/dist/calldata/lifi/frax/index.d.ts +0 -4
  58. package/dist/calldata/lifi/frax/index.js +0 -29
  59. package/dist/calldata/lifi/garden/index.d.ts +0 -3
  60. package/dist/calldata/lifi/garden/index.js +0 -22
  61. package/dist/calldata/lifi/gaszip/index.d.ts +0 -6
  62. package/dist/calldata/lifi/gaszip/index.js +0 -15
  63. package/dist/calldata/lifi/index.d.ts +0 -4
  64. package/dist/calldata/lifi/index.js +0 -62
  65. package/dist/calldata/lifi/intents/index.d.ts +0 -4
  66. package/dist/calldata/lifi/intents/index.js +0 -10
  67. package/dist/calldata/lifi/layerswap/index.d.ts +0 -4
  68. package/dist/calldata/lifi/layerswap/index.js +0 -10
  69. package/dist/calldata/lifi/m0/index.d.ts +0 -3
  70. package/dist/calldata/lifi/m0/index.js +0 -33
  71. package/dist/calldata/lifi/mayan/index.d.ts +0 -4
  72. package/dist/calldata/lifi/mayan/index.js +0 -10
  73. package/dist/calldata/lifi/method.d.ts +0 -6
  74. package/dist/calldata/lifi/method.js +0 -16
  75. package/dist/calldata/lifi/native/index.d.ts +0 -4
  76. package/dist/calldata/lifi/native/index.js +0 -80
  77. package/dist/calldata/lifi/params.d.ts +0 -28
  78. package/dist/calldata/lifi/params.js +0 -347
  79. package/dist/calldata/lifi/paxos/index.d.ts +0 -4
  80. package/dist/calldata/lifi/paxos/index.js +0 -10
  81. package/dist/calldata/lifi/polymer/index.d.ts +0 -4
  82. package/dist/calldata/lifi/polymer/index.js +0 -10
  83. package/dist/calldata/lifi/relay/index.d.ts +0 -6
  84. package/dist/calldata/lifi/relay/index.js +0 -15
  85. package/dist/calldata/lifi/shape.d.ts +0 -4
  86. package/dist/calldata/lifi/shape.js +0 -31
  87. package/dist/calldata/lifi/squid/index.d.ts +0 -6
  88. package/dist/calldata/lifi/squid/index.js +0 -15
  89. package/dist/calldata/lifi/stargate/index.d.ts +0 -5
  90. package/dist/calldata/lifi/stargate/index.js +0 -15
  91. package/dist/calldata/lifi/swap/index.d.ts +0 -5
  92. package/dist/calldata/lifi/swap/index.js +0 -18
  93. package/dist/calldata/lifi/swap/swapMethod.d.ts +0 -2
  94. package/dist/calldata/lifi/swap/swapMethod.js +0 -40
  95. package/dist/calldata/lifi/swapData.d.ts +0 -5
  96. package/dist/calldata/lifi/swapData.js +0 -33
  97. package/dist/calldata/match.d.ts +0 -3
  98. package/dist/calldata/match.js +0 -21
  99. package/dist/calldata/mayan/destination.d.ts +0 -2
  100. package/dist/calldata/mayan/destination.js +0 -13
  101. package/dist/calldata/mayan/fastMctpBridge.d.ts +0 -3
  102. package/dist/calldata/mayan/fastMctpBridge.js +0 -48
  103. package/dist/calldata/mayan/fastMctpCreateOrder.d.ts +0 -3
  104. package/dist/calldata/mayan/fastMctpCreateOrder.js +0 -39
  105. package/dist/calldata/mayan/forward.d.ts +0 -8
  106. package/dist/calldata/mayan/forward.js +0 -35
  107. package/dist/calldata/mayan/forwardERC20.d.ts +0 -2
  108. package/dist/calldata/mayan/forwardERC20.js +0 -19
  109. package/dist/calldata/mayan/forwardEth.d.ts +0 -2
  110. package/dist/calldata/mayan/forwardEth.js +0 -16
  111. package/dist/calldata/mayan/index.d.ts +0 -4
  112. package/dist/calldata/mayan/index.js +0 -21
  113. package/dist/calldata/mayan/mctp.d.ts +0 -5
  114. package/dist/calldata/mayan/mctp.js +0 -41
  115. package/dist/calldata/mayan/readProtocol.d.ts +0 -2
  116. package/dist/calldata/mayan/readProtocol.js +0 -29
  117. package/dist/calldata/mayan/swapAndForwardERC20.d.ts +0 -2
  118. package/dist/calldata/mayan/swapAndForwardERC20.js +0 -24
  119. package/dist/calldata/mayan/swapAndForwardEth.d.ts +0 -2
  120. package/dist/calldata/mayan/swapAndForwardEth.js +0 -23
  121. package/dist/calldata/mayan/swiftCreateOrder.d.ts +0 -3
  122. package/dist/calldata/mayan/swiftCreateOrder.js +0 -49
  123. package/dist/calldata/mayan/validate.d.ts +0 -3
  124. package/dist/calldata/mayan/validate.js +0 -20
  125. package/dist/calldata/protocols.d.ts +0 -9
  126. package/dist/calldata/protocols.js +0 -57
  127. package/dist/calldata/relay/calls.d.ts +0 -13
  128. package/dist/calldata/relay/calls.js +0 -54
  129. package/dist/calldata/relay/depositErc20.d.ts +0 -2
  130. package/dist/calldata/relay/depositErc20.js +0 -22
  131. package/dist/calldata/relay/depositErc20Allowance.d.ts +0 -2
  132. package/dist/calldata/relay/depositErc20Allowance.js +0 -20
  133. package/dist/calldata/relay/depositNative.d.ts +0 -2
  134. package/dist/calldata/relay/depositNative.js +0 -20
  135. package/dist/calldata/relay/index.d.ts +0 -4
  136. package/dist/calldata/relay/index.js +0 -42
  137. package/dist/calldata/relay/multicall.d.ts +0 -2
  138. package/dist/calldata/relay/multicall.js +0 -15
  139. package/dist/calldata/relay/permit2TransferAndMulticall.d.ts +0 -2
  140. package/dist/calldata/relay/permit2TransferAndMulticall.js +0 -42
  141. package/dist/calldata/relay/permit3009TransferAndMulticall.d.ts +0 -2
  142. package/dist/calldata/relay/permit3009TransferAndMulticall.js +0 -41
  143. package/dist/calldata/relay/permit3009TransferAndMulticallSigned.d.ts +0 -2
  144. package/dist/calldata/relay/permit3009TransferAndMulticallSigned.js +0 -40
  145. package/dist/calldata/relay/permitTransferAndMulticall.d.ts +0 -2
  146. package/dist/calldata/relay/permitTransferAndMulticall.js +0 -34
  147. package/dist/calldata/relay/permitTransferAndMulticallLegacy.d.ts +0 -2
  148. package/dist/calldata/relay/permitTransferAndMulticallLegacy.js +0 -35
  149. package/dist/calldata/relay/transferAndMulticall.d.ts +0 -2
  150. package/dist/calldata/relay/transferAndMulticall.js +0 -26
  151. package/dist/calldata/relay/validate.d.ts +0 -3
  152. package/dist/calldata/relay/validate.js +0 -18
  153. package/dist/calldata/resolve.d.ts +0 -2
  154. package/dist/calldata/resolve.js +0 -28
  155. package/dist/calldata/socket/bridge.d.ts +0 -2
  156. package/dist/calldata/socket/bridge.js +0 -28
  157. package/dist/calldata/socket/exec.d.ts +0 -2
  158. package/dist/calldata/socket/exec.js +0 -71
  159. package/dist/calldata/socket/index.d.ts +0 -4
  160. package/dist/calldata/socket/index.js +0 -13
  161. package/dist/calldata/socket/params.d.ts +0 -5
  162. package/dist/calldata/socket/params.js +0 -14
  163. package/dist/calldata/socket/protocols/ccip.d.ts +0 -2
  164. package/dist/calldata/socket/protocols/ccip.js +0 -32
  165. package/dist/calldata/socket/protocols/cctp.d.ts +0 -2
  166. package/dist/calldata/socket/protocols/cctp.js +0 -24
  167. package/dist/calldata/socket/protocols/eco.d.ts +0 -2
  168. package/dist/calldata/socket/protocols/eco.js +0 -20
  169. package/dist/calldata/socket/protocols/index.d.ts +0 -3
  170. package/dist/calldata/socket/protocols/index.js +0 -86
  171. package/dist/calldata/socket/protocols/native.d.ts +0 -2
  172. package/dist/calldata/socket/protocols/native.js +0 -70
  173. package/dist/calldata/socket/protocols/oft.d.ts +0 -2
  174. package/dist/calldata/socket/protocols/oft.js +0 -33
  175. package/dist/calldata/socket/protocols/swapsXYZ.d.ts +0 -2
  176. package/dist/calldata/socket/protocols/swapsXYZ.js +0 -62
  177. package/dist/calldata/socket/swapAndBridge.d.ts +0 -2
  178. package/dist/calldata/socket/swapAndBridge.js +0 -41
  179. package/dist/calldata/socket/validate.d.ts +0 -3
  180. package/dist/calldata/socket/validate.js +0 -24
  181. package/dist/calldata/types.d.ts +0 -82
  182. package/dist/calldata/types.js +0 -20
  183. package/dist/errors/constants.d.ts +0 -891
  184. package/dist/errors/constants.js +0 -898
  185. package/dist/errors/index.d.ts +0 -66
  186. package/dist/errors/index.js +0 -53
  187. package/dist/errors/sanitize.d.ts +0 -3
  188. package/dist/errors/sanitize.js +0 -74
  189. package/dist/providers/data.d.ts +0 -23
  190. package/dist/providers/data.js +0 -116
  191. package/dist/providers/errors.d.ts +0 -7
  192. package/dist/providers/errors.js +0 -10
  193. package/dist/providers/layerswap.d.ts +0 -9
  194. package/dist/providers/layerswap.js +0 -95
  195. package/dist/providers/relay.d.ts +0 -59
  196. package/dist/providers/relay.js +0 -185
  197. package/dist/providers/socket.d.ts +0 -5
  198. package/dist/providers/socket.js +0 -57
package/dist/quote.js CHANGED
@@ -1,20 +1,14 @@
1
- import { BRIDGE_ERRORS, BridgeError, asBridgeError, reportBridgeError } from './errors/index.js';
2
- import { InvalidBridgeCalldataError, validateBridgeCalldata, } from './calldata/index.js';
3
- import { calldataDiagnostics } from './calldata/diagnostics.js';
4
- import { sanitizeBridgeError } from './errors/sanitize.js';
5
1
  import { BRIDGE_ENUM } from './consts.js';
6
2
  import { getBridgeAltContracts, getBridgeRouter, getBridgeSpender, isSupportedBridgeAggregator, isSupportedBridgeChain, } from './list.js';
7
- export class InvalidBridgeContractError extends BridgeError {
3
+ export class InvalidBridgeContractError extends Error {
8
4
  constructor(kind, aggregatorId, chainId, expected, received, bridgeId) {
9
- 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}`);
10
6
  this.kind = kind;
11
7
  this.aggregatorId = aggregatorId;
12
8
  this.chainId = chainId;
13
9
  this.expected = expected;
14
10
  this.received = received;
15
11
  this.bridgeId = bridgeId;
16
- this.message =
17
- `Invalid bridge ${kind} for ${aggregatorId} on ${chainId}: expected ${expected}, got ${received}`;
18
12
  this.name = 'InvalidBridgeContractError';
19
13
  }
20
14
  }
@@ -26,19 +20,15 @@ const isSameAddress = (left, right) => {
26
20
  };
27
21
  function assertSupported(aggregatorId, fromChainId) {
28
22
  if (!isSupportedBridgeAggregator(aggregatorId)) {
29
- const error = new BridgeError(BRIDGE_ERRORS.UNSUPPORTED_BRIDGE_AGGREGATOR, { aggregatorId, chainId: fromChainId });
30
- error.message = `${aggregatorId} is not supported`;
31
- throw error;
23
+ throw new Error(`${aggregatorId} is not supported`);
32
24
  }
33
25
  if (!isSupportedBridgeChain(aggregatorId, fromChainId)) {
34
- const error = new BridgeError(BRIDGE_ERRORS.UNSUPPORTED_SOURCE_CHAIN, { aggregatorId, chainId: fromChainId });
35
- error.message = `${aggregatorId} does not support ${fromChainId}`;
36
- throw error;
26
+ throw new Error(`${aggregatorId} does not support ${fromChainId}`);
37
27
  }
38
28
  }
39
29
  const requireSlippage = (slippage) => {
40
30
  if (!slippage) {
41
- throw new BridgeError(BRIDGE_ERRORS.SLIPPAGE_IS_REQUIRED_FOR_THIS_API_CALL);
31
+ throw new Error('slippage is required for this API call');
42
32
  }
43
33
  return slippage;
44
34
  };
@@ -49,22 +39,13 @@ const stringifyQuoteKey = (quoteKey) => {
49
39
  return JSON.stringify(quoteKey || {});
50
40
  };
51
41
  const shouldValidateBridgeContracts = (aggregatorId) => aggregatorId !== BRIDGE_ENUM.NEAR_INTENTS;
52
- const handleNewValidationError = (error, options, context) => {
53
- if (!options.lite)
54
- throw error;
55
- reportBridgeError(options.onError, asBridgeError(error), { ...context, lite: true, blocking: false });
56
- };
57
- export const validateBridgeQuote = (aggregatorId, fromChainId, quote, options = {}) => {
42
+ export const validateBridgeQuote = (aggregatorId, fromChainId, quote) => {
58
43
  if (!shouldValidateBridgeContracts(aggregatorId)) {
59
44
  return true;
60
45
  }
61
46
  const expectedSpender = getBridgeSpender(aggregatorId, fromChainId);
62
47
  const receivedSpender = quote.approve_contract_id;
63
- if (!receivedSpender) {
64
- return true;
65
- }
66
- if (!expectedSpender) {
67
- 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) {
68
49
  return true;
69
50
  }
70
51
  const allowedSpenders = [
@@ -76,191 +57,81 @@ export const validateBridgeQuote = (aggregatorId, fromChainId, quote, options =
76
57
  }
77
58
  return true;
78
59
  };
79
- const quotedToAmount = (quoteKey) => {
80
- let key = quoteKey;
81
- if (typeof key === 'string') {
82
- try {
83
- key = JSON.parse(key);
84
- }
85
- catch {
86
- return undefined;
87
- }
88
- }
89
- if (!key || typeof key !== 'object' || Array.isArray(key))
90
- return undefined;
91
- const amount = key.to_token_raw_amount;
92
- if (typeof amount === 'string' || (typeof amount === 'number' && Number.isSafeInteger(amount))) {
93
- return String(amount);
94
- }
95
- return undefined;
96
- };
97
- const validateBridgeRouter = (aggregatorId, fromChainId, bridgeId, tx) => {
60
+ export const validateBridgeTx = (aggregatorId, fromChainId, bridgeId, tx) => {
98
61
  if (!shouldValidateBridgeContracts(aggregatorId)) {
99
62
  return true;
100
63
  }
101
64
  const expectedRouter = getBridgeRouter(aggregatorId, fromChainId);
65
+ if (!expectedRouter) {
66
+ return true;
67
+ }
102
68
  const allowedRouters = [
103
- ...(expectedRouter ? [expectedRouter] : []),
69
+ expectedRouter,
104
70
  ...getBridgeAltContracts(aggregatorId),
105
71
  ];
106
72
  if (!allowedRouters.some((addr) => isSameAddress(addr, tx.to))) {
107
- throw asBridgeError(new InvalidBridgeContractError('router', aggregatorId, fromChainId, expectedRouter || allowedRouters.join(',') || 'configured router', tx.to, bridgeId), BRIDGE_ERRORS.ROUTER_NOT_ALLOWED, { ...calldataDiagnostics(tx.data),
108
- pass: false, routerPass: false, fromPass: false, toPass: false, receiverPass: false, blocking: true });
73
+ throw new InvalidBridgeContractError('router', aggregatorId, fromChainId, expectedRouter, tx.to, bridgeId);
109
74
  }
110
75
  return true;
111
76
  };
112
- const fieldErrors = {
113
- fromPass: [BRIDGE_ERRORS.FROM_ADDRESS_MISMATCH, BRIDGE_ERRORS.FROM_CHAIN_MISMATCH,
114
- BRIDGE_ERRORS.FROM_TOKEN_MISMATCH, BRIDGE_ERRORS.FROM_AMOUNT_MISMATCH,
115
- BRIDGE_ERRORS.DEPOSITOR_MISMATCH, BRIDGE_ERRORS.MISSING_SOURCE_TOKEN, BRIDGE_ERRORS.MISSING_SOURCE_AMOUNT],
116
- toPass: [BRIDGE_ERRORS.TO_CHAIN_MISMATCH, BRIDGE_ERRORS.TO_TOKEN_MISMATCH,
117
- BRIDGE_ERRORS.MIN_RECEIVE_MISMATCH, BRIDGE_ERRORS.MISSING_DESTINATION,
118
- BRIDGE_ERRORS.MISSING_DESTINATION_CHAIN, BRIDGE_ERRORS.MISSING_OUTPUT_TOKEN,
119
- BRIDGE_ERRORS.MISSING_MIN_OUTPUT, BRIDGE_ERRORS.UNSUPPORTED_DESTINATION_CALL],
120
- receiverPass: [BRIDGE_ERRORS.RECEIVER_MISMATCH, BRIDGE_ERRORS.MISSING_RECEIVER,
121
- BRIDGE_ERRORS.UNSUPPORTED_DESTINATION_CALL],
122
- };
123
- const bindingErrors = [
124
- BRIDGE_ERRORS.QUOTE_ID_MISMATCH, BRIDGE_ERRORS.REQUEST_ID_MISMATCH, BRIDGE_ERRORS.SOCKET_RFQ_QUOTE_ID_MISMATCH,
125
- ];
126
- const checkBridgeTx = (aggregatorId, fromChainId, bridgeId, tx, expectation, options = {}, operation = 'verifyTx') => {
127
- const routerPass = validateBridgeRouter(aggregatorId, fromChainId, bridgeId, tx);
128
- let check;
129
- try {
130
- check = validateBridgeCalldata(aggregatorId, fromChainId, tx, expectation);
131
- }
132
- catch (error) {
133
- check = { ok: false, aggregatorId, errors: asBridgeError(error, BRIDGE_ERRORS.INVALID_CALLDATA).errors };
134
- }
135
- const unverifiedFields = check.unverifiedFields ?? [
136
- 'sourceToken', 'sourceAmount', 'outputToken', 'minOutputAmount', 'receiver',
137
- ...(expectation?.toChainId ? ['destinationChainId'] : []),
138
- ];
139
- const externalDestination = check.parsed && (aggregatorId === BRIDGE_ENUM.RELAY ||
140
- (aggregatorId === BRIDGE_ENUM.SOCKET &&
141
- ['receiveERC20', 'receiveNative', 'depositForBurn'].includes(check.parsed.protocolMethod ?? '')));
142
- // Known local limits remain unverified, without repeating an expected gap as an error.
143
- const reportableFields = unverifiedFields.filter((field) => {
144
- if (!check.parsed)
145
- return true;
146
- if (field === 'outputToken')
147
- return false;
148
- if (field === 'minOutputAmount')
149
- return check.parsed.minOutputAmount !== undefined;
150
- return !(externalDestination && ['receiver', 'destinationChainId'].includes(field));
151
- });
152
- // Unclassified structure failures invalidate every field; known field failures stay separate.
153
- const comparable = Boolean(expectation && check.parsed) && check.errors.every((error) => bindingErrors.some((item) => item.error_code === error.error_code) ||
154
- Object.values(fieldErrors).some((group) => group.some((item) => item.error_code === error.error_code)));
155
- const fieldPass = (field, required) => comparable &&
156
- required.every((item) => !unverifiedFields.includes(item)) &&
157
- !check.errors.some((error) => fieldErrors[field].some((item) => item.error_code === error.error_code));
158
- const flags = {
159
- // shortcut: field checks are observation-only until collected routes justify enforcement.
160
- pass: routerPass, routerPass,
161
- fromPass: fieldPass('fromPass', ['sourceToken', 'sourceAmount']),
162
- toPass: fieldPass('toPass', ['outputToken', 'minOutputAmount', ...(expectation?.toChainId ? ['destinationChainId'] : [])]),
163
- receiverPass: fieldPass('receiverPass', ['receiver']),
164
- };
165
- const context = {
166
- ...check.parsed?.diagnostics, ...calldataDiagnostics(tx.data), aggregatorId,
167
- chainId: fromChainId, toChainId: expectation?.toChainId, bridgeId, operation, method: check.method,
168
- ...(check.parsed ? { hasDestinationCall: Boolean(check.parsed.hasDestinationCall || check.parsed.destinationCallData !== undefined) } : {}),
169
- ...flags, lite: Boolean(options.lite), blocking: false,
77
+ export const getQuote = async (aggregatorId, params, api) => {
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),
170
89
  };
171
- const errors = [
172
- ...check.errors,
173
- ...(reportableFields.length ? [{ ...BRIDGE_ERRORS.UNVERIFIED_BRIDGE_FIELDS, unverifiedFields: reportableFields }] : []),
174
- ].map((error) => sanitizeBridgeError({ ...error, ...context }));
175
- if (errors.length) {
176
- reportBridgeError(options.onError, new InvalidBridgeCalldataError(aggregatorId, fromChainId, check.method, check.reason || errors[0].message, errors), context);
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');
177
95
  }
178
- return { ...flags, unverifiedFields, errors };
179
- };
180
- export const validateBridgeTx = (aggregatorId, fromChainId, bridgeId, tx, expectation, options = {}) => checkBridgeTx(aggregatorId, fromChainId, bridgeId, tx, expectation, options);
181
- export const getQuote = async (aggregatorId, params, api) => {
182
- try {
183
- params = { ...params };
184
- assertSupported(aggregatorId, params.fromChainId);
185
- const baseParams = {
186
- aggregator_id: aggregatorId,
187
- user_addr: params.userAddress,
188
- from_chain_id: params.fromChainId,
189
- from_token_id: params.fromTokenId,
190
- from_token_raw_amount: params.fromTokenRawAmount,
191
- to_chain_id: params.toChainId,
192
- to_token_id: params.toTokenId,
193
- fee_rate: params.feeRate,
194
- slippage: requireSlippage(params.slippage),
195
- };
196
- const quotes = api.getBridgeQuoteListV2
197
- ? await api.getBridgeQuoteListV2(baseParams).catch((error) => { throw asBridgeError(error, BRIDGE_ERRORS.BACKEND_QUOTE_REQUEST_FAILED, { requestKind: 'backend_quote' }); })
198
- : await api.getBridgeQuoteV2?.(baseParams).catch((error) => { throw asBridgeError(error, BRIDGE_ERRORS.BACKEND_QUOTE_REQUEST_FAILED, { requestKind: 'backend_quote' }); });
199
- if (!quotes)
200
- throw new BridgeError(BRIDGE_ERRORS.MISSING_QUOTE_API);
201
- return quotes.filter((quote) => {
202
- try {
203
- validateBridgeQuote(aggregatorId, params.fromChainId, quote, params);
204
- return true;
205
- }
206
- catch (error) {
207
- if (error instanceof InvalidBridgeContractError) {
208
- reportBridgeError(params.onError, error, { aggregatorId, chainId: params.fromChainId, toChainId: params.toChainId, bridgeId: quote.bridge_id, operation: 'getQuote', ...(params.lite ? { lite: true, blocking: true } : {}) });
209
- return false;
210
- }
211
- throw error;
96
+ return quotes.filter((quote) => {
97
+ try {
98
+ validateBridgeQuote(aggregatorId, params.fromChainId, quote);
99
+ return true;
100
+ }
101
+ catch (error) {
102
+ if (error instanceof InvalidBridgeContractError) {
103
+ return false;
212
104
  }
213
- });
214
- }
215
- catch (error) {
216
- throw asBridgeError(error, BRIDGE_ERRORS.UNKNOWN, { aggregatorId, chainId: params.fromChainId, toChainId: params.toChainId, operation: 'getQuote', ...(params.lite ? { lite: true, blocking: true } : {}) });
217
- }
105
+ throw error;
106
+ }
107
+ });
218
108
  };
219
109
  export const buildTx = async (aggregatorId, params, api) => {
220
- try {
221
- // Freeze signing intent before awaiting a backend response.
222
- params = { ...params };
223
- assertSupported(aggregatorId, params.fromChainId);
224
- const quoteKey = stringifyQuoteKey(params.quoteKey);
225
- const expectation = {
226
- userAddress: params.userAddress,
227
- fromTokenId: params.fromTokenId,
228
- fromTokenRawAmount: params.fromTokenRawAmount,
229
- toChainId: params.toChainId,
230
- toTokenId: params.toTokenId,
231
- toTokenRawAmount: params.toTokenRawAmount ?? quotedToAmount(quoteKey),
232
- // The legacy quote+tx API requotes instead of reusing this selection.
233
- quoteKey: typeof api.buildBridgeTx === 'function' ? quoteKey : undefined,
234
- slippage: params.slippage,
235
- };
236
- const buildParams = {
237
- aggregator_id: aggregatorId,
238
- bridge_id: params.bridgeId,
239
- user_addr: params.userAddress,
240
- from_chain_id: params.fromChainId,
241
- from_token_id: params.fromTokenId,
242
- from_token_raw_amount: params.fromTokenRawAmount,
243
- to_chain_id: params.toChainId,
244
- to_token_id: params.toTokenId,
245
- slippage: requireSlippage(params.slippage),
246
- };
247
- const tx = api.buildBridgeTx
248
- ? await api.buildBridgeTx({
249
- ...buildParams,
250
- quote_key: quoteKey,
251
- }).catch((error) => { throw asBridgeError(error, BRIDGE_ERRORS.BACKEND_BUILD_REQUEST_FAILED, { requestKind: 'backend_build' }); })
252
- : (await api.getBridgeQuoteTxV2?.({
253
- ...buildParams,
254
- }).catch((error) => { throw asBridgeError(error, BRIDGE_ERRORS.BACKEND_BUILD_REQUEST_FAILED, { requestKind: 'backend_build' }); }))?.tx;
255
- if (!tx) {
256
- throw new BridgeError(BRIDGE_ERRORS.MISSING_BUILD_API);
257
- }
258
- checkBridgeTx(aggregatorId, params.fromChainId, params.bridgeId, tx, expectation, params, 'buildTx');
259
- return tx;
260
- }
261
- catch (error) {
262
- throw asBridgeError(error, BRIDGE_ERRORS.UNKNOWN, { aggregatorId, chainId: params.fromChainId, toChainId: params.toChainId, operation: 'buildTx', bridgeId: params.bridgeId, ...(params.lite ? { lite: true, blocking: true } : {}) });
263
- }
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;
264
135
  };
265
136
  export const getQuoteListWithTx = async (aggregatorId, params, api) => {
266
137
  const quotes = await getQuote(aggregatorId, params, api);
@@ -270,8 +141,6 @@ export const getQuoteListWithTx = async (aggregatorId, params, api) => {
270
141
  ...params,
271
142
  bridgeId: quote.bridge_id,
272
143
  quoteKey: quote.quote_key,
273
- toTokenRawAmount: quote.to_token_raw_amount_hex_str ??
274
- (Number.isSafeInteger(quote.to_token_raw_amount) ? String(quote.to_token_raw_amount) : undefined),
275
144
  }, api);
276
145
  return {
277
146
  ...quote,
@@ -279,9 +148,7 @@ export const getQuoteListWithTx = async (aggregatorId, params, api) => {
279
148
  };
280
149
  }
281
150
  catch (error) {
282
- if (error instanceof InvalidBridgeContractError ||
283
- error instanceof InvalidBridgeCalldataError) {
284
- 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) {
285
152
  return null;
286
153
  }
287
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.1",
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;
@@ -1,36 +0,0 @@
1
- import { applyAcrossMessage } from '../destination.js';
2
- import { asBigint, asString, decodeCall } from '../abi.js';
3
- import { accountFromBytes32 } from '../hex.js';
4
- const fields = [
5
- { name: 'depositor', kind: 'bytes', size: 32 },
6
- { name: 'recipient', kind: 'bytes', size: 32 },
7
- { name: 'inputToken', kind: 'bytes', size: 32 },
8
- { name: 'outputToken', kind: 'bytes', size: 32 },
9
- { name: 'inputAmount', kind: 'uint' },
10
- { name: 'outputAmount', kind: 'uint' },
11
- { name: 'destinationChainId', kind: 'uint' },
12
- { name: 'exclusiveRelayer', kind: 'bytes', size: 32 },
13
- { name: 'quoteTimestamp', kind: 'uint' },
14
- { name: 'fillDeadline', kind: 'uint' },
15
- { name: 'exclusivityParameter', kind: 'uint' },
16
- { name: 'message', kind: 'bytes' },
17
- ];
18
- export const deposit = {
19
- name: 'deposit',
20
- selector: '0xad5425c6',
21
- decode(data) {
22
- const args = decodeCall(fields, data);
23
- return applyAcrossMessage({
24
- aggregatorId: 'across',
25
- method: 'deposit',
26
- kind: 'bridge',
27
- depositor: accountFromBytes32(asString(args.depositor)),
28
- sourceToken: accountFromBytes32(asString(args.inputToken)),
29
- sourceAmount: asBigint(args.inputAmount),
30
- destinationChainId: asBigint(args.destinationChainId),
31
- receiver: accountFromBytes32(asString(args.recipient)),
32
- outputToken: accountFromBytes32(asString(args.outputToken)),
33
- minOutputAmount: asBigint(args.outputAmount),
34
- }, asString(args.message));
35
- },
36
- };
@@ -1,2 +0,0 @@
1
- import type { CalldataMethod } from '../abi.js';
2
- export declare const depositNative: CalldataMethod;
@@ -1,45 +0,0 @@
1
- import { BRIDGE_ERRORS, BridgeError } from '../../errors/index.js';
2
- import { applyAcrossMessage } from '../destination.js';
3
- import { asBigint, asString, decodeCall } from '../abi.js';
4
- import { accountFromBytes32 } from '../hex.js';
5
- import { NATIVE_TOKEN } from '../protocols.js';
6
- const fields = [
7
- { name: 'spokePool', kind: 'address' },
8
- { name: 'depositor', kind: 'address' },
9
- { name: 'recipient', kind: 'bytes', size: 32 },
10
- { name: 'inputToken', kind: 'address' },
11
- { name: 'inputAmount', kind: 'uint' },
12
- { name: 'outputToken', kind: 'bytes', size: 32 },
13
- { name: 'outputAmount', kind: 'uint' },
14
- { name: 'destinationChainId', kind: 'uint' },
15
- { name: 'exclusiveRelayer', kind: 'bytes', size: 32 },
16
- { name: 'quoteTimestamp', kind: 'uint' },
17
- { name: 'fillDeadline', kind: 'uint' },
18
- { name: 'exclusivityParameter', kind: 'uint' },
19
- { name: 'message', kind: 'bytes' },
20
- ];
21
- export const depositNative = {
22
- name: 'depositNative',
23
- selector: '0x609ea081',
24
- decode(data, value) {
25
- const args = decodeCall(fields, data);
26
- const inputAmount = asBigint(args.inputAmount);
27
- if (inputAmount > 0n && value !== inputAmount)
28
- throw new BridgeError(BRIDGE_ERRORS.ACROSS_NATIVE_VALUE_MISMATCH);
29
- return applyAcrossMessage({
30
- aggregatorId: 'across',
31
- method: 'depositNative',
32
- kind: 'bridge',
33
- depositor: asString(args.depositor),
34
- sourceToken: NATIVE_TOKEN,
35
- sourceAmount: inputAmount > 0n ? inputAmount : value,
36
- bridgeToken: asString(args.inputToken),
37
- bridgeAmount: inputAmount > 0n ? inputAmount : value,
38
- destinationChainId: asBigint(args.destinationChainId),
39
- receiver: accountFromBytes32(asString(args.recipient)),
40
- outputToken: accountFromBytes32(asString(args.outputToken)),
41
- minOutputAmount: asBigint(args.outputAmount),
42
- spokePool: asString(args.spokePool),
43
- }, asString(args.message));
44
- },
45
- };
@@ -1,2 +0,0 @@
1
- import type { CalldataMethod } from '../abi.js';
2
- export declare const depositNow: CalldataMethod;