@metamask-previews/transaction-pay-controller 30.1.0-preview-43fa35913 → 30.1.0-preview-4fa35a45a

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 (33) hide show
  1. package/dist/strategy/relay/polymarket/calldata.d.ts.map +1 -0
  2. package/dist/strategy/relay/polymarket/calldata.js.map +1 -0
  3. package/dist/strategy/relay/polymarket/constants.d.ts.map +1 -0
  4. package/dist/strategy/relay/polymarket/constants.js.map +1 -0
  5. package/dist/strategy/relay/polymarket/withdraw.d.ts +52 -0
  6. package/dist/strategy/relay/polymarket/withdraw.d.ts.map +1 -0
  7. package/dist/{utils → strategy/relay}/polymarket/withdraw.js +72 -88
  8. package/dist/strategy/relay/polymarket/withdraw.js.map +1 -0
  9. package/dist/strategy/relay/relay-quotes.d.ts.map +1 -1
  10. package/dist/strategy/relay/relay-quotes.js +7 -11
  11. package/dist/strategy/relay/relay-quotes.js.map +1 -1
  12. package/dist/strategy/relay/relay-submit.d.ts.map +1 -1
  13. package/dist/strategy/relay/relay-submit.js +4 -12
  14. package/dist/strategy/relay/relay-submit.js.map +1 -1
  15. package/dist/strategy/relay/relay-validation.d.ts.map +1 -1
  16. package/dist/strategy/relay/relay-validation.js +2 -8
  17. package/dist/strategy/relay/relay-validation.js.map +1 -1
  18. package/package.json +1 -1
  19. package/dist/strategy/relay/deposit-step.d.ts +0 -18
  20. package/dist/strategy/relay/deposit-step.d.ts.map +0 -1
  21. package/dist/strategy/relay/deposit-step.js +0 -21
  22. package/dist/strategy/relay/deposit-step.js.map +0 -1
  23. package/dist/utils/polymarket/calldata.d.ts.map +0 -1
  24. package/dist/utils/polymarket/calldata.js.map +0 -1
  25. package/dist/utils/polymarket/constants.d.ts.map +0 -1
  26. package/dist/utils/polymarket/constants.js.map +0 -1
  27. package/dist/utils/polymarket/withdraw.d.ts +0 -101
  28. package/dist/utils/polymarket/withdraw.d.ts.map +0 -1
  29. package/dist/utils/polymarket/withdraw.js.map +0 -1
  30. /package/dist/{utils → strategy/relay}/polymarket/calldata.d.ts +0 -0
  31. /package/dist/{utils → strategy/relay}/polymarket/calldata.js +0 -0
  32. /package/dist/{utils → strategy/relay}/polymarket/constants.d.ts +0 -0
  33. /package/dist/{utils → strategy/relay}/polymarket/constants.js +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calldata.d.ts","sourceRoot":"","sources":["../../../../src/strategy/relay/polymarket/calldata.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAS3C,wBAAgB,aAAa,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,CAE/D;AAED,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,SAAS,EACT,MAAM,GACP,EAAE;IACD,KAAK,EAAE,GAAG,CAAC;IACX,SAAS,EAAE,GAAG,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,GAAG,CAEN;AAED,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,SAAS,EACT,MAAM,GACP,EAAE;IACD,KAAK,EAAE,GAAG,CAAC;IACX,SAAS,EAAE,GAAG,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,GAAG,CAEN;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG,CAG5D"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calldata.js","sourceRoot":"","sources":["../../../../src/strategy/relay/polymarket/calldata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG/C,MAAM,KAAK,GAAG,IAAI,SAAS,CAAC;IAC1B,mDAAmD;IACnD,mEAAmE;IACnE,iEAAiE;IACjE,sDAAsD;CACvD,CAAC,CAAC;AAEH,MAAM,UAAU,aAAa,CAAC,OAAY,EAAE,MAAc;IACxD,OAAO,KAAK,CAAC,kBAAkB,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAQ,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,EAC3B,KAAK,EACL,SAAS,EACT,MAAM,GAKP;IACC,OAAO,KAAK,CAAC,kBAAkB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,CAAQ,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,EACzB,KAAK,EACL,SAAS,EACT,MAAM,GAKP;IACC,OAAO,KAAK,CAAC,kBAAkB,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,CAAQ,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,IAAS;IACrD,MAAM,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAC/D,OAAO,SAAgB,CAAC;AAC1B,CAAC","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport type { Hex } from '@metamask/utils';\n\nconst iface = new Interface([\n 'function approve(address spender, uint256 amount)',\n 'function unwrap(address asset, address recipient, uint256 amount)',\n 'function wrap(address asset, address recipient, uint256 amount)',\n 'function transfer(address recipient, uint256 amount)',\n]);\n\nexport function encodeApprove(spender: Hex, amount: bigint): Hex {\n return iface.encodeFunctionData('approve', [spender, amount]) as Hex;\n}\n\nexport function encodeUnwrap({\n asset,\n recipient,\n amount,\n}: {\n asset: Hex;\n recipient: Hex;\n amount: bigint;\n}): Hex {\n return iface.encodeFunctionData('unwrap', [asset, recipient, amount]) as Hex;\n}\n\nexport function encodeWrap({\n asset,\n recipient,\n amount,\n}: {\n asset: Hex;\n recipient: Hex;\n amount: bigint;\n}): Hex {\n return iface.encodeFunctionData('wrap', [asset, recipient, amount]) as Hex;\n}\n\nexport function extractErc20TransferRecipient(data: Hex): Hex {\n const [recipient] = iface.decodeFunctionData('transfer', data);\n return recipient as Hex;\n}\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/strategy/relay/polymarket/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAE3C,eAAO,MAAM,qCAAqC,EACA,GAAG,CAAC;AAEtD,eAAO,MAAM,oCAAoC,EACC,GAAG,CAAC;AAEtD,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD,eAAO,MAAM,6BAA6B,OAAO,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../src/strategy/relay/polymarket/constants.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,qCAAqC,GAChD,4CAAmD,CAAC;AAEtD,MAAM,CAAC,MAAM,oCAAoC,GAC/C,4CAAmD,CAAC;AAEtD,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC;AAE9C,MAAM,CAAC,MAAM,4BAA4B,GAAG,IAAI,CAAC;AAEjD,MAAM,CAAC,MAAM,6BAA6B,GAAG,IAAI,CAAC","sourcesContent":["import type { Hex } from '@metamask/utils';\n\nexport const POLYMARKET_COLLATERAL_OFFRAMP_POLYGON =\n '0x2957922Eb93258b93368531d39fAcCA3B4dC5854' as Hex;\n\nexport const POLYMARKET_COLLATERAL_ONRAMP_POLYGON =\n '0x93070a847efEf7F70739046A929D47a521F5B8ee' as Hex;\n\nexport const SWEEP_BALANCE_RETRY_ATTEMPTS = 5;\n\nexport const SWEEP_BALANCE_RETRY_DELAY_MS = 1000;\n\nexport const SWEEP_RELAYER_SETTLE_DELAY_MS = 3000;\n"]}
@@ -0,0 +1,52 @@
1
+ import type { TransactionMeta } from '@metamask/transaction-controller';
2
+ import type { Hex } from '@metamask/utils';
3
+ import type { QuoteRequest, TransactionPayControllerMessenger, TransactionPayQuote } from '../../../types.js';
4
+ import type { QuoteSimulation } from '../../../utils/validation.js';
5
+ import type { RelayQuote, RelayQuoteRequest, RelayStatus } from '../types.js';
6
+ type RelayQuoteStep = RelayQuote['steps'][number];
7
+ /**
8
+ * Whether a quote request + transaction represent a Predict withdraw post-quote
9
+ * flow.
10
+ *
11
+ * @param request - Quote request.
12
+ * @param transaction - Original transaction metadata.
13
+ * @returns True when this is a Predict withdraw post-quote flow.
14
+ */
15
+ export declare function isPredictWithdraw(request: QuoteRequest, transaction: TransactionMeta): boolean;
16
+ /**
17
+ * Resolve the Polymarket Safe proxy address that must act as `msg.sender` when
18
+ * estimating gas for the withdraw leg of a Safe-based Predict withdraw.
19
+ *
20
+ * Only applies to the Safe variant on deposit-style Relay routes: the source
21
+ * token lives in the Safe (carried as `request.refundTo`), and swap-only routes
22
+ * keep the EOA `from` because DEX aggregators reject contract callers.
23
+ *
24
+ * @param request - Quote request.
25
+ * @param steps - Relay quote steps (used to detect a deposit-style route).
26
+ * @param transaction - Original transaction metadata.
27
+ * @returns The Safe proxy address, or `undefined` when the default EOA `from`
28
+ * should be used.
29
+ */
30
+ export declare function getPredictWithdrawSafeAddress(request: QuoteRequest, steps: RelayQuoteStep[], transaction: TransactionMeta): Hex | undefined;
31
+ /**
32
+ * Build the simulation for a Polymarket deposit-wallet Predict withdraw,
33
+ * mirroring the approve + unwrap batch broadcast by {@link submitPolymarketWithdraw}
34
+ * so validation checks the deposit wallet holds enough pUSD.
35
+ *
36
+ * @param quote - Relay quote (source amount + deposit step).
37
+ * @param from - The user EOA that owns the deposit wallet.
38
+ * @param messenger - Controller messenger.
39
+ * @returns Simulation for the approve + unwrap batch from the deposit wallet.
40
+ */
41
+ export declare function buildPolymarketDepositWalletSimulation(quote: TransactionPayQuote<RelayQuote>, from: Hex, messenger: TransactionPayControllerMessenger): Promise<QuoteSimulation>;
42
+ export declare function applyPolymarketDepositWalletOverrides(body: Omit<RelayQuoteRequest, 'amount' | 'tradeType'>, request: QuoteRequest, messenger: TransactionPayControllerMessenger): Promise<void>;
43
+ export declare function submitPolymarketWithdraw(quote: TransactionPayQuote<RelayQuote>, from: Hex, messenger: TransactionPayControllerMessenger): Promise<{
44
+ sourceHash: Hex;
45
+ preSubmitUsdceBalance: bigint;
46
+ }>;
47
+ export declare function sweepPolymarketDepositWallet(from: Hex, messenger: TransactionPayControllerMessenger, options: {
48
+ relayStatus: RelayStatus | 'timeout';
49
+ preSubmitUsdceBalance: bigint;
50
+ }): Promise<void>;
51
+ export {};
52
+ //# sourceMappingURL=withdraw.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"withdraw.d.ts","sourceRoot":"","sources":["../../../../src/strategy/relay/polymarket/withdraw.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAS3C,OAAO,KAAK,EACV,YAAY,EACZ,iCAAiC,EACjC,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EACV,UAAU,EACV,iBAAiB,EACjB,WAAW,EAEZ,MAAM,aAAa,CAAC;AAiBrB,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;AAElD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,YAAY,EACrB,WAAW,EAAE,eAAe,GAC3B,OAAO,CAKT;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE,cAAc,EAAE,EACvB,WAAW,EAAE,eAAe,GAC3B,GAAG,GAAG,SAAS,CAkBjB;AAED;;;;;;;;;GASG;AACH,wBAAsB,sCAAsC,CAC1D,KAAK,EAAE,mBAAmB,CAAC,UAAU,CAAC,EACtC,IAAI,EAAE,GAAG,EACT,SAAS,EAAE,iCAAiC,GAC3C,OAAO,CAAC,eAAe,CAAC,CAgB1B;AAED,wBAAsB,qCAAqC,CACzD,IAAI,EAAE,IAAI,CAAC,iBAAiB,EAAE,QAAQ,GAAG,WAAW,CAAC,EACrD,OAAO,EAAE,YAAY,EACrB,SAAS,EAAE,iCAAiC,GAC3C,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,mBAAmB,CAAC,UAAU,CAAC,EACtC,IAAI,EAAE,GAAG,EACT,SAAS,EAAE,iCAAiC,GAC3C,OAAO,CAAC;IAAE,UAAU,EAAE,GAAG,CAAC;IAAC,qBAAqB,EAAE,MAAM,CAAA;CAAE,CAAC,CA0B7D;AAED,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,GAAG,EACT,SAAS,EAAE,iCAAiC,EAC5C,OAAO,EAAE;IACP,WAAW,EAAE,WAAW,GAAG,SAAS,CAAC;IACrC,qBAAqB,EAAE,MAAM,CAAC;CAC/B,GACA,OAAO,CAAC,IAAI,CAAC,CAyDf"}
@@ -1,8 +1,8 @@
1
1
  import { TransactionType, hasTransactionType, } from '@metamask/transaction-controller';
2
2
  import { createModuleLogger } from '@metamask/utils';
3
- import { CHAIN_ID_POLYGON, POLYGON_PUSD_ADDRESS, POLYGON_USDCE_ADDRESS, } from '../../constants.js';
4
- import { projectLogger } from '../../logger.js';
5
- import { getLiveTokenBalance } from '../token.js';
3
+ import { CHAIN_ID_POLYGON, POLYGON_PUSD_ADDRESS, POLYGON_USDCE_ADDRESS, } from '../../../constants.js';
4
+ import { projectLogger } from '../../../logger.js';
5
+ import { getLiveTokenBalance } from '../../../utils/token.js';
6
6
  import { encodeApprove, encodeUnwrap, encodeWrap, extractErc20TransferRecipient, } from './calldata.js';
7
7
  import { POLYMARKET_COLLATERAL_OFFRAMP_POLYGON, POLYMARKET_COLLATERAL_ONRAMP_POLYGON, SWEEP_BALANCE_RETRY_ATTEMPTS, SWEEP_BALANCE_RETRY_DELAY_MS, SWEEP_RELAYER_SETTLE_DELAY_MS, } from './constants.js';
8
8
  const log = createModuleLogger(projectLogger, 'polymarket-withdraw');
@@ -22,108 +22,85 @@ export function isPredictWithdraw(request, transaction) {
22
22
  * Resolve the Polymarket Safe proxy address that must act as `msg.sender` when
23
23
  * estimating gas for the withdraw leg of a Safe-based Predict withdraw.
24
24
  *
25
- * Only applies to the Safe variant on deposit-style routes: the source token
26
- * lives in the Safe (carried as `request.refundTo`), and swap-only routes keep
27
- * the EOA `from` because DEX aggregators reject contract callers.
25
+ * Only applies to the Safe variant on deposit-style Relay routes: the source
26
+ * token lives in the Safe (carried as `request.refundTo`), and swap-only routes
27
+ * keep the EOA `from` because DEX aggregators reject contract callers.
28
28
  *
29
29
  * @param request - Quote request.
30
+ * @param steps - Relay quote steps (used to detect a deposit-style route).
30
31
  * @param transaction - Original transaction metadata.
31
- * @param hasDepositStep - Whether the quote routes through a deposit step.
32
32
  * @returns The Safe proxy address, or `undefined` when the default EOA `from`
33
33
  * should be used.
34
34
  */
35
- export function getPredictWithdrawSafeAddress(request, transaction, hasDepositStep) {
36
- if (!hasDepositStep ||
37
- request.isPolymarketDepositWallet ||
38
- !isPredictWithdraw(request, transaction)) {
35
+ export function getPredictWithdrawSafeAddress(request, steps, transaction) {
36
+ if (!isPredictWithdraw(request, transaction)) {
37
+ return undefined;
38
+ }
39
+ // Deposit-wallet withdraws are validated via their own simulation builder;
40
+ // `request.refundTo` is not the deposit wallet for that variant.
41
+ if (request.isPolymarketDepositWallet) {
42
+ return undefined;
43
+ }
44
+ const hasDepositStep = steps.some((step) => step.id === 'deposit');
45
+ if (!hasDepositStep) {
39
46
  return undefined;
40
47
  }
41
48
  return request.refundTo;
42
49
  }
43
50
  /**
44
- * Resolve the account holding the source token for gas-fee-token lookups.
45
- *
46
- * Unlike {@link getPredictWithdrawSafeAddress} this applies to every Predict
47
- * withdraw route: the source token lives in the Safe and the EOA is empty until
48
- * the Safe call runs mid-batch.
49
- *
50
- * @param request - Quote request.
51
- * @param transaction - Original transaction metadata.
52
- * @returns The Safe proxy address, or `undefined` for other flows.
53
- */
54
- export function getPredictWithdrawFeeTokenAccount(request, transaction) {
55
- return isPredictWithdraw(request, transaction) ? request.refundTo : undefined;
56
- }
57
- /**
58
- * Resolve the quote overrides for a deposit-wallet Predict withdraw. The deposit
59
- * wallet is both the sender and the refund address, and the provider is funded
60
- * with the USDC.e produced by unwrapping pUSD.
51
+ * Build the simulation for a Polymarket deposit-wallet Predict withdraw,
52
+ * mirroring the approve + unwrap batch broadcast by {@link submitPolymarketWithdraw}
53
+ * so validation checks the deposit wallet holds enough pUSD.
61
54
  *
55
+ * @param quote - Relay quote (source amount + deposit step).
62
56
  * @param from - The user EOA that owns the deposit wallet.
63
57
  * @param messenger - Controller messenger.
64
- * @returns The deposit wallet and the source token to quote.
65
- */
66
- export async function getPolymarketDepositWalletOverrides(from, messenger) {
67
- return {
68
- depositWallet: await getDepositWalletAddress(messenger, from),
69
- sourceTokenAddress: POLYGON_USDCE_ADDRESS,
70
- };
71
- }
72
- /**
73
- * Build the simulation for a deposit-wallet Predict withdraw, mirroring the
74
- * batch broadcast by {@link submitPolymarketWithdraw}.
75
- *
76
- * @param request - Withdraw request.
77
58
  * @returns Simulation for the approve + unwrap batch from the deposit wallet.
78
59
  */
79
- export async function buildPolymarketDepositWalletSimulation(request) {
80
- const depositWallet = await getDepositWalletAddress(request.messenger, request.from);
60
+ export async function buildPolymarketDepositWalletSimulation(quote, from, messenger) {
61
+ const depositWalletAddress = await getDepositWalletAddress(messenger, from);
62
+ const relayDepositAddress = extractRelayDepositAddress(quote.original);
63
+ const amount = BigInt(quote.sourceAmount.raw);
81
64
  return {
82
- transactions: buildUnwrapCalls(request).map((call) => ({
83
- data: call.data,
84
- from: depositWallet,
65
+ transactions: buildDepositWalletUnwrapCalls(relayDepositAddress, amount).map((call) => ({
66
+ from: depositWalletAddress,
85
67
  to: call.target,
68
+ data: call.data,
86
69
  value: '0x0',
87
70
  })),
88
71
  };
89
72
  }
90
- /**
91
- * Unwrap the deposit wallet's pUSD straight to the provider deposit address.
92
- *
93
- * @param request - Withdraw request.
94
- * @returns The batch hash, and the USDC.e balance before submission so a
95
- * later sweep can detect a refund.
96
- */
97
- export async function submitPolymarketWithdraw(request) {
98
- const { from, messenger } = request;
99
- const depositWallet = await getDepositWalletAddress(messenger, from);
100
- const calls = buildUnwrapCalls(request);
101
- const preSubmitUsdceBalance = await readUsdceBalanceOrZero(messenger, depositWallet);
102
- log('Submitting unwrap batch to deposit address', {
103
- depositWallet,
73
+ export async function applyPolymarketDepositWalletOverrides(body, request, messenger) {
74
+ const depositWalletAddress = await getDepositWalletAddress(messenger, request.from);
75
+ body.originCurrency = POLYGON_USDCE_ADDRESS;
76
+ body.user = depositWalletAddress;
77
+ body.refundTo = depositWalletAddress;
78
+ body.useDepositAddress = true;
79
+ body.strict = true;
80
+ }
81
+ export async function submitPolymarketWithdraw(quote, from, messenger) {
82
+ const depositWalletAddress = await getDepositWalletAddress(messenger, from);
83
+ const relayDepositAddress = extractRelayDepositAddress(quote.original);
84
+ const amount = BigInt(quote.sourceAmount.raw);
85
+ const preSubmitUsdceBalance = await readUsdceBalanceOrZero(messenger, depositWalletAddress);
86
+ log('Submitting unwrap batch to Relay deposit address', {
87
+ depositWalletAddress,
88
+ relayDepositAddress,
89
+ amount: amount.toString(),
104
90
  preSubmitUsdceBalance: preSubmitUsdceBalance.toString(),
105
- sourceAmountRaw: request.sourceAmountRaw,
106
91
  });
107
92
  const result = await submitDepositWalletBatch(messenger, {
108
- calls: calls.map((call) => ({ ...call, value: '0' })),
109
- depositWallet,
110
93
  eoa: from,
94
+ depositWallet: depositWalletAddress,
95
+ calls: buildDepositWalletUnwrapCalls(relayDepositAddress, amount).map((call) => ({ ...call, value: '0' })),
111
96
  });
112
97
  return { ...result, preSubmitUsdceBalance };
113
98
  }
114
- /**
115
- * Wrap any USDC.e left on the deposit wallet back into pUSD, such as a refund
116
- * from a failed withdraw.
117
- *
118
- * @param options - Sweep options.
119
- * @param options.from - The user EOA that owns the deposit wallet.
120
- * @param options.isRefund - Whether the provider refunded the withdraw, in which
121
- * case the sweep waits for the refunded balance to land.
122
- * @param options.messenger - Controller messenger.
123
- * @param options.preSubmitUsdceBalance - USDC.e balance before the withdraw.
124
- */
125
- export async function sweepPolymarketDepositWallet({ from, isRefund, messenger, preSubmitUsdceBalance, }) {
126
- const waitForBalanceAbove = isRefund ? preSubmitUsdceBalance : undefined;
99
+ export async function sweepPolymarketDepositWallet(from, messenger, options) {
100
+ const isRefund = options.relayStatus === 'refund' || options.relayStatus === 'refunded';
101
+ const waitForBalanceAbove = isRefund
102
+ ? options.preSubmitUsdceBalance
103
+ : undefined;
127
104
  const depositWalletAddress = await getDepositWalletAddress(messenger, from);
128
105
  const usdceBalance = await readDepositWalletUsdceBalance(messenger, depositWalletAddress, waitForBalanceAbove);
129
106
  if (usdceBalance === undefined) {
@@ -222,22 +199,29 @@ async function submitDepositWalletBatch(messenger, params) {
222
199
  });
223
200
  return result;
224
201
  }
202
+ function extractRelayDepositAddress(relayQuote) {
203
+ const depositStep = relayQuote.steps.find((step) => step.id === 'deposit');
204
+ if (depositStep?.kind !== 'transaction') {
205
+ throw new Error('Polymarket deposit wallet withdraw: Relay quote has no deposit step');
206
+ }
207
+ const transactionStep = depositStep;
208
+ const depositCallData = transactionStep.items[0]?.data?.data;
209
+ if (!depositCallData) {
210
+ throw new Error('Polymarket deposit wallet withdraw: Relay quote deposit step is missing calldata');
211
+ }
212
+ return extractErc20TransferRecipient(depositCallData);
213
+ }
225
214
  /**
226
215
  * Build the approve + unwrap batch that moves a deposit wallet's pUSD to the
227
- * provider deposit address as USDC.e. Shared by the simulation and the real
228
- * submit so both model the exact same calls.
216
+ * Relay deposit address as USDC.e. Shared by the simulation and the real submit
217
+ * so both model the exact same calls.
229
218
  *
230
- * @param request - Withdraw request.
231
- * @param request.depositData - Calldata of the provider deposit step.
232
- * @param request.sourceAmountRaw - Amount of pUSD to unwrap.
219
+ * @param relayDepositAddress - The Relay deposit address that receives the
220
+ * unwrapped USDC.e.
221
+ * @param amount - The pUSD amount to unwrap.
233
222
  * @returns The two `{ target, data }` calls.
234
223
  */
235
- function buildUnwrapCalls({ depositData, sourceAmountRaw, }) {
236
- if (!depositData) {
237
- throw new Error('Polymarket deposit wallet withdraw: quote has no deposit step calldata');
238
- }
239
- const depositAddress = extractErc20TransferRecipient(depositData);
240
- const amount = BigInt(sourceAmountRaw);
224
+ function buildDepositWalletUnwrapCalls(relayDepositAddress, amount) {
241
225
  return [
242
226
  {
243
227
  target: POLYGON_PUSD_ADDRESS,
@@ -247,7 +231,7 @@ function buildUnwrapCalls({ depositData, sourceAmountRaw, }) {
247
231
  target: POLYMARKET_COLLATERAL_OFFRAMP_POLYGON,
248
232
  data: encodeUnwrap({
249
233
  asset: POLYGON_USDCE_ADDRESS,
250
- recipient: depositAddress,
234
+ recipient: relayDepositAddress,
251
235
  amount,
252
236
  }),
253
237
  },
@@ -0,0 +1 @@
1
+ {"version":3,"file":"withdraw.js","sourceRoot":"","sources":["../../../../src/strategy/relay/polymarket/withdraw.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n TransactionType,\n hasTransactionType,\n} from '@metamask/transaction-controller';\nimport type { TransactionMeta } from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\n\nimport {\n CHAIN_ID_POLYGON,\n POLYGON_PUSD_ADDRESS,\n POLYGON_USDCE_ADDRESS,\n} from '../../../constants.js';\nimport { projectLogger } from '../../../logger.js';\nimport type {\n QuoteRequest,\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../../types.js';\nimport { getLiveTokenBalance } from '../../../utils/token.js';\nimport type { QuoteSimulation } from '../../../utils/validation.js';\nimport type {\n RelayQuote,\n RelayQuoteRequest,\n RelayStatus,\n RelayTransactionStep,\n} from '../types.js';\nimport {\n encodeApprove,\n encodeUnwrap,\n encodeWrap,\n extractErc20TransferRecipient,\n} from './calldata.js';\nimport {\n POLYMARKET_COLLATERAL_OFFRAMP_POLYGON,\n POLYMARKET_COLLATERAL_ONRAMP_POLYGON,\n SWEEP_BALANCE_RETRY_ATTEMPTS,\n SWEEP_BALANCE_RETRY_DELAY_MS,\n SWEEP_RELAYER_SETTLE_DELAY_MS,\n} from './constants.js';\n\nconst log = createModuleLogger(projectLogger, 'polymarket-withdraw');\n\ntype RelayQuoteStep = RelayQuote['steps'][number];\n\n/**\n * Whether a quote request + transaction represent a Predict withdraw post-quote\n * flow.\n *\n * @param request - Quote request.\n * @param transaction - Original transaction metadata.\n * @returns True when this is a Predict withdraw post-quote flow.\n */\nexport function isPredictWithdraw(\n request: QuoteRequest,\n transaction: TransactionMeta,\n): boolean {\n return Boolean(\n request.isPostQuote &&\n hasTransactionType(transaction, [TransactionType.predictWithdraw]),\n );\n}\n\n/**\n * Resolve the Polymarket Safe proxy address that must act as `msg.sender` when\n * estimating gas for the withdraw leg of a Safe-based Predict withdraw.\n *\n * Only applies to the Safe variant on deposit-style Relay routes: the source\n * token lives in the Safe (carried as `request.refundTo`), and swap-only routes\n * keep the EOA `from` because DEX aggregators reject contract callers.\n *\n * @param request - Quote request.\n * @param steps - Relay quote steps (used to detect a deposit-style route).\n * @param transaction - Original transaction metadata.\n * @returns The Safe proxy address, or `undefined` when the default EOA `from`\n * should be used.\n */\nexport function getPredictWithdrawSafeAddress(\n request: QuoteRequest,\n steps: RelayQuoteStep[],\n transaction: TransactionMeta,\n): Hex | undefined {\n if (!isPredictWithdraw(request, transaction)) {\n return undefined;\n }\n\n // Deposit-wallet withdraws are validated via their own simulation builder;\n // `request.refundTo` is not the deposit wallet for that variant.\n if (request.isPolymarketDepositWallet) {\n return undefined;\n }\n\n const hasDepositStep = steps.some((step) => step.id === 'deposit');\n\n if (!hasDepositStep) {\n return undefined;\n }\n\n return request.refundTo;\n}\n\n/**\n * Build the simulation for a Polymarket deposit-wallet Predict withdraw,\n * mirroring the approve + unwrap batch broadcast by {@link submitPolymarketWithdraw}\n * so validation checks the deposit wallet holds enough pUSD.\n *\n * @param quote - Relay quote (source amount + deposit step).\n * @param from - The user EOA that owns the deposit wallet.\n * @param messenger - Controller messenger.\n * @returns Simulation for the approve + unwrap batch from the deposit wallet.\n */\nexport async function buildPolymarketDepositWalletSimulation(\n quote: TransactionPayQuote<RelayQuote>,\n from: Hex,\n messenger: TransactionPayControllerMessenger,\n): Promise<QuoteSimulation> {\n const depositWalletAddress = await getDepositWalletAddress(messenger, from);\n const relayDepositAddress = extractRelayDepositAddress(quote.original);\n const amount = BigInt(quote.sourceAmount.raw);\n\n return {\n transactions: buildDepositWalletUnwrapCalls(\n relayDepositAddress,\n amount,\n ).map((call) => ({\n from: depositWalletAddress,\n to: call.target,\n data: call.data,\n value: '0x0',\n })),\n };\n}\n\nexport async function applyPolymarketDepositWalletOverrides(\n body: Omit<RelayQuoteRequest, 'amount' | 'tradeType'>,\n request: QuoteRequest,\n messenger: TransactionPayControllerMessenger,\n): Promise<void> {\n const depositWalletAddress = await getDepositWalletAddress(\n messenger,\n request.from,\n );\n\n body.originCurrency = POLYGON_USDCE_ADDRESS;\n body.user = depositWalletAddress;\n body.refundTo = depositWalletAddress;\n body.useDepositAddress = true;\n body.strict = true;\n}\n\nexport async function submitPolymarketWithdraw(\n quote: TransactionPayQuote<RelayQuote>,\n from: Hex,\n messenger: TransactionPayControllerMessenger,\n): Promise<{ sourceHash: Hex; preSubmitUsdceBalance: bigint }> {\n const depositWalletAddress = await getDepositWalletAddress(messenger, from);\n const relayDepositAddress = extractRelayDepositAddress(quote.original);\n const amount = BigInt(quote.sourceAmount.raw);\n\n const preSubmitUsdceBalance = await readUsdceBalanceOrZero(\n messenger,\n depositWalletAddress,\n );\n\n log('Submitting unwrap batch to Relay deposit address', {\n depositWalletAddress,\n relayDepositAddress,\n amount: amount.toString(),\n preSubmitUsdceBalance: preSubmitUsdceBalance.toString(),\n });\n\n const result = await submitDepositWalletBatch(messenger, {\n eoa: from,\n depositWallet: depositWalletAddress,\n calls: buildDepositWalletUnwrapCalls(relayDepositAddress, amount).map(\n (call) => ({ ...call, value: '0' }),\n ),\n });\n\n return { ...result, preSubmitUsdceBalance };\n}\n\nexport async function sweepPolymarketDepositWallet(\n from: Hex,\n messenger: TransactionPayControllerMessenger,\n options: {\n relayStatus: RelayStatus | 'timeout';\n preSubmitUsdceBalance: bigint;\n },\n): Promise<void> {\n const isRefund =\n options.relayStatus === 'refund' || options.relayStatus === 'refunded';\n const waitForBalanceAbove = isRefund\n ? options.preSubmitUsdceBalance\n : undefined;\n\n const depositWalletAddress = await getDepositWalletAddress(messenger, from);\n const usdceBalance = await readDepositWalletUsdceBalance(\n messenger,\n depositWalletAddress,\n waitForBalanceAbove,\n );\n\n if (usdceBalance === undefined) {\n return;\n }\n\n if (usdceBalance === 0n) {\n log('USDC.e sweep: nothing to wrap');\n return;\n }\n\n if (waitForBalanceAbove !== undefined && usdceBalance > waitForBalanceAbove) {\n log('USDC.e sweep: waiting for relayer RPC to catch up to new balance');\n await new Promise((resolve) =>\n setTimeout(resolve, SWEEP_RELAYER_SETTLE_DELAY_MS),\n );\n }\n\n try {\n await submitDepositWalletBatch(messenger, {\n eoa: from,\n depositWallet: depositWalletAddress,\n calls: [\n {\n target: POLYGON_USDCE_ADDRESS,\n value: '0',\n data: encodeApprove(\n POLYMARKET_COLLATERAL_ONRAMP_POLYGON,\n usdceBalance,\n ),\n },\n {\n target: POLYMARKET_COLLATERAL_ONRAMP_POLYGON,\n value: '0',\n data: encodeWrap({\n asset: POLYGON_USDCE_ADDRESS,\n recipient: depositWalletAddress,\n amount: usdceBalance,\n }),\n },\n ],\n });\n } catch (error) {\n log('USDC.e sweep: batch submission failed', { error });\n }\n}\n\nasync function readUsdceBalanceOrZero(\n messenger: TransactionPayControllerMessenger,\n depositWalletAddress: Hex,\n): Promise<bigint> {\n try {\n const raw = await getLiveTokenBalance(\n messenger,\n depositWalletAddress,\n CHAIN_ID_POLYGON,\n POLYGON_USDCE_ADDRESS,\n );\n return BigInt(raw);\n } catch (error) {\n log('USDC.e balance read failed, defaulting to zero', { error });\n return 0n;\n }\n}\n\nasync function readDepositWalletUsdceBalance(\n messenger: TransactionPayControllerMessenger,\n depositWalletAddress: Hex,\n waitForBalanceAbove: bigint | undefined,\n): Promise<bigint | undefined> {\n const shouldRetry = waitForBalanceAbove !== undefined;\n const maxAttempts = shouldRetry ? SWEEP_BALANCE_RETRY_ATTEMPTS : 1;\n let lastBalance = 0n;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n if (attempt > 1) {\n await new Promise((resolve) =>\n setTimeout(resolve, SWEEP_BALANCE_RETRY_DELAY_MS),\n );\n }\n\n try {\n const raw = await getLiveTokenBalance(\n messenger,\n depositWalletAddress,\n CHAIN_ID_POLYGON,\n POLYGON_USDCE_ADDRESS,\n );\n lastBalance = BigInt(raw);\n } catch (error) {\n log('USDC.e sweep: failed to read deposit wallet balance', { error });\n return undefined;\n }\n\n log('USDC.e sweep: deposit wallet balance', {\n depositWalletAddress,\n balance: lastBalance.toString(),\n attempt,\n waitForBalanceAbove: waitForBalanceAbove?.toString(),\n });\n\n const hasIncreased =\n waitForBalanceAbove === undefined || lastBalance > waitForBalanceAbove;\n\n if (hasIncreased) {\n return lastBalance;\n }\n }\n\n return lastBalance;\n}\n\nasync function getDepositWalletAddress(\n messenger: TransactionPayControllerMessenger,\n eoa: Hex,\n): Promise<Hex> {\n const depositWalletAddress = await messenger.call(\n 'TransactionPayController:polymarketGetDepositWalletAddress',\n { eoa },\n );\n log('Polymarket callback: getDepositWalletAddress', {\n eoa,\n depositWalletAddress,\n });\n return depositWalletAddress;\n}\n\nasync function submitDepositWalletBatch(\n messenger: TransactionPayControllerMessenger,\n params: {\n eoa: Hex;\n depositWallet: Hex;\n calls: { target: Hex; data: Hex; value: string }[];\n },\n): Promise<{ sourceHash: Hex }> {\n log('Polymarket callback: submitDepositWalletBatch', {\n eoa: params.eoa,\n depositWallet: params.depositWallet,\n callCount: params.calls.length,\n });\n const result = await messenger.call(\n 'TransactionPayController:polymarketSubmitDepositWalletBatch',\n params,\n );\n log('Polymarket callback: submitDepositWalletBatch returned', {\n sourceHash: result.sourceHash,\n });\n return result;\n}\n\nfunction extractRelayDepositAddress(relayQuote: RelayQuote): Hex {\n const depositStep = relayQuote.steps.find((step) => step.id === 'deposit');\n\n if (depositStep?.kind !== 'transaction') {\n throw new Error(\n 'Polymarket deposit wallet withdraw: Relay quote has no deposit step',\n );\n }\n\n const transactionStep = depositStep as RelayTransactionStep;\n const depositCallData = transactionStep.items[0]?.data?.data;\n\n if (!depositCallData) {\n throw new Error(\n 'Polymarket deposit wallet withdraw: Relay quote deposit step is missing calldata',\n );\n }\n\n return extractErc20TransferRecipient(depositCallData);\n}\n\n/**\n * Build the approve + unwrap batch that moves a deposit wallet's pUSD to the\n * Relay deposit address as USDC.e. Shared by the simulation and the real submit\n * so both model the exact same calls.\n *\n * @param relayDepositAddress - The Relay deposit address that receives the\n * unwrapped USDC.e.\n * @param amount - The pUSD amount to unwrap.\n * @returns The two `{ target, data }` calls.\n */\nfunction buildDepositWalletUnwrapCalls(\n relayDepositAddress: Hex,\n amount: bigint,\n): { target: Hex; data: Hex }[] {\n return [\n {\n target: POLYGON_PUSD_ADDRESS,\n data: encodeApprove(POLYMARKET_COLLATERAL_OFFRAMP_POLYGON, amount),\n },\n {\n target: POLYMARKET_COLLATERAL_OFFRAMP_POLYGON,\n data: encodeUnwrap({\n asset: POLYGON_USDCE_ADDRESS,\n recipient: relayDepositAddress,\n amount,\n }),\n },\n ];\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"relay-quotes.d.ts","sourceRoot":"","sources":["../../../src/strategy/relay/relay-quotes.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAGV,2BAA2B,EAG3B,mBAAmB,EACpB,MAAM,gBAAgB,CAAC;AA0CxB,OAAO,KAAK,EACV,UAAU,EAIX,MAAM,YAAY,CAAC;AAuBpB;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC,CAsE5C"}
1
+ {"version":3,"file":"relay-quotes.d.ts","sourceRoot":"","sources":["../../../src/strategy/relay/relay-quotes.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAGV,2BAA2B,EAG3B,mBAAmB,EACpB,MAAM,gBAAgB,CAAC;AAyCxB,OAAO,KAAK,EACV,UAAU,EAIX,MAAM,YAAY,CAAC;AAuBpB;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC,CAsE5C"}
@@ -10,14 +10,13 @@ import { getFiatValueFromUsd } from '../../utils/amounts.js';
10
10
  import { getFeatureFlags, getRelayOriginGasOverhead, getSlippage, getStablecoins, isAtomicMaxEnabled, isEIP7702Chain, isRelayExecuteEnabled, } from '../../utils/feature-flags.js';
11
11
  import { GasPaymentMode, resolveGasPayment, resolveGasStationCost, } from '../../utils/gas-payment.js';
12
12
  import { calculateGasCost } from '../../utils/gas.js';
13
- import { getPolymarketDepositWalletOverrides, getPredictWithdrawFeeTokenAccount, getPredictWithdrawSafeAddress, } from '../../utils/polymarket/withdraw.js';
14
13
  import { estimateQuoteGasLimits } from '../../utils/quote-gas.js';
15
14
  import { resolveNonAtomicRecipient } from '../../utils/second-leg.js';
16
15
  import { getNativeToken, getTokenFiatRate, normalizeTokenAddress, TokenAddressTarget, } from '../../utils/token.js';
17
16
  import { getQuotePricing } from '../../utils/trade-type.js';
18
17
  import { TOKEN_TRANSFER_FOUR_BYTE } from './constants.js';
19
- import { hasRelayDepositStep } from './deposit-step.js';
20
18
  import { applyHyperliquidActivationFee } from './hyperliquid-activation.js';
19
+ import { applyPolymarketDepositWalletOverrides, getPredictWithdrawSafeAddress, isPredictWithdraw, } from './polymarket/withdraw.js';
21
20
  import { fetchRelayQuote } from './relay-api.js';
22
21
  import { getRelayMaxQuote, isSubsidizedAtomicMaxQuote, throwAtomicPromotionFailed, } from './relay-max.js';
23
22
  import { validateRelayQuotes } from './relay-validation.js';
@@ -193,13 +192,7 @@ async function getSingleQuote(request, fullRequest) {
193
192
  user: from,
194
193
  };
195
194
  if (effectiveRequest.isPolymarketDepositWallet) {
196
- const overrides = await getPolymarketDepositWalletOverrides(from, messenger);
197
- const { depositWallet } = overrides;
198
- body.originCurrency = overrides.sourceTokenAddress;
199
- body.user = depositWallet;
200
- body.refundTo = depositWallet;
201
- body.useDepositAddress = true;
202
- body.strict = true;
195
+ await applyPolymarketDepositWalletOverrides(body, effectiveRequest, messenger);
203
196
  }
204
197
  const isAtomic = effectiveRequest.atomic !== false;
205
198
  const processedTransactions = await processTransactions(transaction, effectiveRequest, body, messenger);
@@ -569,6 +562,7 @@ async function calculateSourceNetworkCost(quote, messenger, request, transaction
569
562
  .flatMap((step) => step.items)
570
563
  .map((item) => item.data);
571
564
  const { chainId, data, maxFeePerGas, maxPriorityFeePerGas, to, value } = relayParams[0];
565
+ const isPredictWithdrawFlow = isPredictWithdraw(request, transaction);
572
566
  // `fromOverride = Safe proxy` is only valid for deposit-style Relay routes
573
567
  // where the deposit contract reads the user's source-token balance directly.
574
568
  // Same-chain destinations route through DEX swap aggregators that frequently
@@ -577,7 +571,7 @@ async function calculateSourceNetworkCost(quote, messenger, request, transaction
577
571
  // native balance). Simulating those from the Safe proxy reverts and breaks
578
572
  // gas estimation. For swap-only routes, fall back to the relay params'
579
573
  // EOA `from` so simulation succeeds.
580
- const fromOverride = getPredictWithdrawSafeAddress(request, transaction, hasRelayDepositStep(quote.steps));
574
+ const fromOverride = getPredictWithdrawSafeAddress(request, quote.steps, transaction);
581
575
  // For post-quote flows the original transaction will be prepended to the
582
576
  // batch at submission time. Include it in the gas estimation so
583
577
  // estimateGasBatch sees the full batch and can detect EIP-7702 support.
@@ -623,7 +617,9 @@ async function calculateSourceNetworkCost(quote, messenger, request, transaction
623
617
  // return nothing and force users to hold POL.
624
618
  // (`useFromOverride` only governs the gas-estimation `from` address, where
625
619
  // swap-style routes need EOA because DEX routers reject contract callers.)
626
- const proxyFeeTokenAccount = getPredictWithdrawFeeTokenAccount(request, transaction);
620
+ const proxyFeeTokenAccount = isPredictWithdrawFlow
621
+ ? request.refundTo
622
+ : undefined;
627
623
  const gasStationCost = await resolveGasStationCost({
628
624
  accountSupports7702,
629
625
  feeTokenAccount: proxyFeeTokenAccount,