From a099b555672d6f74875e6bd113c406ff95177d70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren?= Date: Wed, 31 Jan 2024 15:23:45 +0100 Subject: [PATCH 1/6] Remove ability to send bridged USDC via its transfer contract --- client/src/PublicRequest.ts | 8 ---- src/config/config.local.js | 1 - src/config/config.mainnet.js | 1 - src/config/config.testnet.js | 1 - .../polygon/PolygonContractABIs.full.js.txt | 48 ------------------- src/lib/polygon/PolygonContractABIs.js | 5 -- .../SignPolygonTransaction.js | 31 ------------ .../SignPolygonTransactionApi.js | 29 +---------- types/Keyguard.d.ts | 8 ---- 9 files changed, 1 insertion(+), 131 deletions(-) diff --git a/client/src/PublicRequest.ts b/client/src/PublicRequest.ts index 34e71678a..e647968ae 100644 --- a/client/src/PublicRequest.ts +++ b/client/src/PublicRequest.ts @@ -219,14 +219,6 @@ export type PolygonTransactionInfo = { */ amount?: number, - /** - * The sender's nonce in the token contract, required when calling the - * contract function `transferWithApproval` for bridged USDC.e. - */ - approval?: { - tokenNonce: number, - }, - /** * The sender's nonce in the token contract, required when calling the * contract function `transferWithPermit` for native USDC. diff --git a/src/config/config.local.js b/src/config/config.local.js index 4eee1fb41..42ba07c0e 100644 --- a/src/config/config.local.js +++ b/src/config/config.local.js @@ -18,7 +18,6 @@ const CONFIG = { // eslint-disable-line no-unused-vars POLYGON_CHAIN_ID: 80001, USDC_CONTRACT_ADDRESS: '0x0FA8781a83E46826621b3BC094Ea2A0212e71B23', - USDC_TRANSFER_CONTRACT_ADDRESS: '0x2805f3187dcDfa424EFA8c55Db6012Cf08Fa6eEc', // v3 USDC_HTLC_CONTRACT_ADDRESS: '0x2EB7cd7791b947A25d629219ead941fCd8f364BF', NATIVE_USDC_CONTRACT_ADDRESS: '0x9999f7Fea5938fD3b1E26A12c3f2fb024e194f97', diff --git a/src/config/config.mainnet.js b/src/config/config.mainnet.js index c49802267..f287686d7 100644 --- a/src/config/config.mainnet.js +++ b/src/config/config.mainnet.js @@ -9,7 +9,6 @@ const CONFIG = { // eslint-disable-line no-unused-vars POLYGON_CHAIN_ID: 137, USDC_CONTRACT_ADDRESS: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174', - USDC_TRANSFER_CONTRACT_ADDRESS: '0x98E69a6927747339d5E543586FC0262112eBe4BD', USDC_HTLC_CONTRACT_ADDRESS: '0xF615bD7EA00C4Cc7F39Faad0895dB5f40891359f', NATIVE_USDC_CONTRACT_ADDRESS: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359', diff --git a/src/config/config.testnet.js b/src/config/config.testnet.js index cf13e7271..9bbaaca97 100644 --- a/src/config/config.testnet.js +++ b/src/config/config.testnet.js @@ -9,7 +9,6 @@ const CONFIG = { // eslint-disable-line no-unused-vars POLYGON_CHAIN_ID: 80001, USDC_CONTRACT_ADDRESS: '0x0FA8781a83E46826621b3BC094Ea2A0212e71B23', - USDC_TRANSFER_CONTRACT_ADDRESS: '0x2805f3187dcDfa424EFA8c55Db6012Cf08Fa6eEc', USDC_HTLC_CONTRACT_ADDRESS: '0x2EB7cd7791b947A25d629219ead941fCd8f364BF', NATIVE_USDC_CONTRACT_ADDRESS: '0x9999f7Fea5938fD3b1E26A12c3f2fb024e194f97', diff --git a/src/lib/polygon/PolygonContractABIs.full.js.txt b/src/lib/polygon/PolygonContractABIs.full.js.txt index 0f731aa89..a20a4824d 100644 --- a/src/lib/polygon/PolygonContractABIs.full.js.txt +++ b/src/lib/polygon/PolygonContractABIs.full.js.txt @@ -74,54 +74,6 @@ const PolygonContractABIsFull = { // eslint-disable-line no-unused-vars 'function withdrawWithAuthorization(address owner, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 nonce, uint8 v, bytes32 r, bytes32 s)', ], - USDC_TRANSFER_CONTRACT_ABI: [ - 'constructor()', - 'event DomainRegistered(bytes32 indexed domainSeparator, bytes domainValue)', - 'event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)', - 'event RequestTypeRegistered(bytes32 indexed typeHash, string typeStr)', - 'function EIP712_DOMAIN_TYPE() view returns (string)', - 'function deposits(address) view returns (uint256)', - 'function domains(bytes32) view returns (bool)', - 'function execute(tuple(address from, address to, uint256 value, uint256 gas, uint256 nonce, bytes data, uint256 validUntil) request, bytes32 domainSeparator, bytes32 requestTypeHash, bytes suffixData, bytes signature) payable returns (bool success, bytes ret)', - 'function getGasAndDataLimits() view returns (tuple(uint256 acceptanceBudget, uint256 preRelayedCallGasLimit, uint256 postRelayedCallGasLimit, uint256 calldataSizeLimit) limits)', - 'function getHubAddr() view returns (address)', - 'function getMinimumRelayFee(tuple(uint256 gasPrice, uint256 pctRelayFee, uint256 baseRelayFee, address relayWorker, address paymaster, address forwarder, bytes paymasterData, uint256 clientId) relayData) view returns (uint256 amount)', - 'function getNonce(address from) view returns (uint256)', - 'function getRelayHubDeposit() view returns (uint256)', - 'function getRequiredRelayFee(tuple(uint256 gasPrice, uint256 pctRelayFee, uint256 baseRelayFee, address relayWorker, address paymaster, address forwarder, bytes paymasterData, uint256 clientId) relayData, bytes4 methodId) view returns (uint256 amount)', - 'function getRequiredRelayGas(bytes4 methodId) view returns (uint256 gas)', - 'function isTrustedForwarder(address forwarder) view returns (bool)', - 'function owner() view returns (address)', - 'function postRelayedCall(bytes context, bool success, uint256 gasUseWithoutPost, tuple(uint256 gasPrice, uint256 pctRelayFee, uint256 baseRelayFee, address relayWorker, address paymaster, address forwarder, bytes paymasterData, uint256 clientId) relayData)', - 'function preRelayedCall(tuple(tuple(address from, address to, uint256 value, uint256 gas, uint256 nonce, bytes data, uint256 validUntil) request, tuple(uint256 gasPrice, uint256 pctRelayFee, uint256 baseRelayFee, address relayWorker, address paymaster, address forwarder, bytes paymasterData, uint256 clientId) relayData) relayRequest, bytes signature, bytes approvalData, uint256 maxPossibleGas) returns (bytes context, bool revertOnRecipientRevert)', - 'function registerDomainSeparator(string name, string version)', - 'function registerRequestType(string typeName, string typeSuffix)', - 'function registerToken(address token, address pool)', - 'function registeredTokenPool(address) view returns (address)', - 'function registeredTokenPoolFee(address token) view returns (uint24 fee)', - 'function renounceOwnership()', - 'function requiredRelayGas() view returns (uint256)', - 'function setGasAndDataLimits(tuple(uint256 acceptanceBudget, uint256 preRelayedCallGasLimit, uint256 postRelayedCallGasLimit, uint256 calldataSizeLimit) limits)', - 'function setMaxRequiredRelayGas(uint256 gas)', - 'function setRelayHub(address hub)', - 'function setRequiredRelayGas(bytes4 methodId, uint256 gas)', - 'function setWrappedChainToken(address _wrappedChainToken)', - 'function transfer(address token, uint256 amount, address target, uint256 fee)', - 'function transferOwnership(address newOwner)', - 'function transferWithApproval(address token, uint256 amount, address target, uint256 fee, uint256 approval, bytes32 sigR, bytes32 sigS, uint8 sigV)', - 'function trustedForwarder() view returns (address forwarder)', - 'function typeHashes(bytes32) view returns (bool)', - 'function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes _data)', - 'function unregisterToken(address token)', - 'function verify(tuple(address from, address to, uint256 value, uint256 gas, uint256 nonce, bytes data, uint256 validUntil) forwardRequest, bytes32 domainSeparator, bytes32 requestTypeHash, bytes suffixData, bytes signature) view', - 'function versionPaymaster() view returns (string)', - 'function versionRecipient() view returns (string)', - 'function withdraw(uint256 amount, address target)', - 'function withdrawRelayHubDeposit(uint256 amount, address target)', - 'function withdrawToken(address token, uint256 amount, address target)', - 'function wrappedChainToken() view returns (address)', - ], - USDC_HTLC_CONTRACT_ABI: [ 'constructor()', 'event DomainRegistered(bytes32 indexed domainSeparator, bytes domainValue)', diff --git a/src/lib/polygon/PolygonContractABIs.js b/src/lib/polygon/PolygonContractABIs.js index 30516a83c..df595724e 100644 --- a/src/lib/polygon/PolygonContractABIs.js +++ b/src/lib/polygon/PolygonContractABIs.js @@ -4,11 +4,6 @@ const PolygonContractABIs = { // eslint-disable-line no-unused-vars 'function approve(address spender, uint256 amount) returns (bool)', ], - USDC_TRANSFER_CONTRACT_ABI: [ - 'function transfer(address token, uint256 amount, address target, uint256 fee)', - 'function transferWithApproval(address token, uint256 amount, address target, uint256 fee, uint256 approval, bytes32 sigR, bytes32 sigS, uint8 sigV)', - ], - USDC_HTLC_CONTRACT_ABI: [ 'function open(bytes32 id, address token, uint256 amount, address refundAddress, address recipientAddress, bytes32 hash, uint256 timeout, uint256 fee)', 'function openWithApproval(bytes32 id, address token, uint256 amount, address refundAddress, address recipientAddress, bytes32 hash, uint256 timeout, uint256 fee, uint256 approval, bytes32 sigR, bytes32 sigS, uint8 sigV)', diff --git a/src/request/sign-polygon-transaction/SignPolygonTransaction.js b/src/request/sign-polygon-transaction/SignPolygonTransaction.js index c3834b2cb..13d3cca20 100644 --- a/src/request/sign-polygon-transaction/SignPolygonTransaction.js +++ b/src/request/sign-polygon-transaction/SignPolygonTransaction.js @@ -120,37 +120,6 @@ class SignPolygonTransaction { // Has been validated to be an approved transfer contract address const transferContract = request.request.to; - if (request.description.name === 'transferWithApproval') { - const { sigR, sigS, sigV } = await polygonKey.signUsdcApproval( - request.keyPath, - new ethers.Contract( - CONFIG.USDC_CONTRACT_ADDRESS, - PolygonContractABIs.USDC_CONTRACT_ABI, - ), - transferContract, - request.description.args.approval, - // Has been validated to be defined when function called is `transferWithApproval` - /** @type {{ tokenNonce: number }} */ (request.approval).tokenNonce, - request.request.from, - ); - - const usdcTransfer = new ethers.Contract( - transferContract, - PolygonContractABIs.USDC_TRANSFER_CONTRACT_ABI, - ); - - request.request.data = usdcTransfer.interface.encodeFunctionData(request.description.name, [ - /* address token */ request.description.args.token, - /* uint256 amount */ request.description.args.amount, - /* address target */ request.description.args.target, - /* uint256 fee */ request.description.args.fee, - /* uint256 approval */ request.description.args.approval, - /* bytes32 sigR */ sigR, - /* bytes32 sigS */ sigS, - /* uint8 sigV */ sigV, - ]); - } - if (request.description.name === 'transferWithPermit') { const { sigR, sigS, sigV } = await polygonKey.signUsdcPermit( request.keyPath, diff --git a/src/request/sign-polygon-transaction/SignPolygonTransactionApi.js b/src/request/sign-polygon-transaction/SignPolygonTransactionApi.js index 12d2c7571..3ce8f1893 100644 --- a/src/request/sign-polygon-transaction/SignPolygonTransactionApi.js +++ b/src/request/sign-polygon-transaction/SignPolygonTransactionApi.js @@ -58,7 +58,6 @@ class SignPolygonTransactionApi extends PolygonRequestParserMixin(TopLevelApi) { * @returns {[ * KeyguardRequest.OpenGsnForwardRequest, * PolygonTransferDescription - * | PolygonTransferWithApprovalDescription * | PolygonTransferWithPermitDescription * | PolygonRefundDescription, * ]} @@ -68,32 +67,12 @@ class SignPolygonTransactionApi extends PolygonRequestParserMixin(TopLevelApi) { /** * @type {PolygonTransferDescription - * | PolygonTransferWithApprovalDescription * | PolygonTransferWithPermitDescription * | PolygonRefundDescription} */ let description; - if (forwardRequest.to === CONFIG.USDC_TRANSFER_CONTRACT_ADDRESS) { - const usdcTransferContract = new ethers.Contract( - CONFIG.USDC_TRANSFER_CONTRACT_ADDRESS, - PolygonContractABIs.USDC_TRANSFER_CONTRACT_ABI, - ); - - /** @type {PolygonTransferDescription | PolygonTransferWithApprovalDescription} */ - description = (usdcTransferContract.interface.parseTransaction({ - data: forwardRequest.data, - value: forwardRequest.value, - })); - - if (description.args.token !== CONFIG.USDC_CONTRACT_ADDRESS) { - throw new Errors.InvalidRequestError('Invalid USDC token contract in request data'); - } - - if (!['transfer', 'transferWithApproval'].includes(description.name)) { - throw new Errors.InvalidRequestError('Requested Polygon contract method is invalid'); - } - } else if (forwardRequest.to === CONFIG.NATIVE_USDC_TRANSFER_CONTRACT_ADDRESS) { + if (forwardRequest.to === CONFIG.NATIVE_USDC_TRANSFER_CONTRACT_ADDRESS) { const nativeUsdcTransferContract = new ethers.Contract( CONFIG.NATIVE_USDC_TRANSFER_CONTRACT_ADDRESS, PolygonContractABIs.NATIVE_USDC_TRANSFER_CONTRACT_ABI, @@ -136,12 +115,6 @@ class SignPolygonTransactionApi extends PolygonRequestParserMixin(TopLevelApi) { throw new Errors.InvalidRequestError('`amount` is only allowed for contract method "refund"'); } - // Check that approval object exists when method is 'transferWithApproval', and unset for other methods. - if ((description.name === 'transferWithApproval') !== !!request.approval) { - throw new Errors.InvalidRequestError('`approval` object is only allowed for contract method ' - + '"transferWithApproval"'); - } - // Check that permit object exists when method is 'transferWithPermit', and unset for other methods. if ((description.name === 'transferWithPermit') !== !!request.permit) { throw new Errors.InvalidRequestError('`permit` object is only allowed for contract method ' diff --git a/types/Keyguard.d.ts b/types/Keyguard.d.ts index dde5d8a0a..28bea8127 100644 --- a/types/Keyguard.d.ts +++ b/types/Keyguard.d.ts @@ -81,13 +81,6 @@ type PolygonTransferDescription = ethers.utils.TransactionDescription & { readonly args: PolygonTransferArgs, }; -interface PolygonTransferWithApprovalArgs extends PolygonTransferArgs, PolygonUsdcApproval {} - -type PolygonTransferWithApprovalDescription = ethers.utils.TransactionDescription & { - readonly name: 'transferWithApproval', - readonly args: PolygonTransferWithApprovalArgs, -}; - interface PolygonTransferWithPermitArgs extends PolygonTransferArgs, PolygonUsdcPermit {} type PolygonTransferWithPermitDescription = ethers.utils.TransactionDescription & { @@ -292,7 +285,6 @@ type Parsed = T extends Is ? KeyId2KeyInfo & { description: PolygonTransferDescription - | PolygonTransferWithApprovalDescription | PolygonTransferWithPermitDescription | PolygonRefundDescription } : T extends Is ? From c2fe36baff0906c95f9b7b8a29ffed9044746557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren?= Date: Wed, 31 Jan 2024 16:06:34 +0100 Subject: [PATCH 2/6] Add support to swap bridged USDC.e to native USDC --- client/src/PublicRequest.ts | 8 +++ src/assets/icons/usdc_dark.svg | 5 ++ src/components/PolygonAddressInfo.js | 4 +- src/config/config.local.js | 2 + src/config/config.mainnet.js | 2 + src/config/config.testnet.js | 2 + .../polygon/PolygonContractABIs.full.js.txt | 50 +++++++++++++++++++ src/lib/polygon/PolygonContractABIs.js | 5 ++ .../SignPolygonTransaction.js | 50 ++++++++++++++++--- .../SignPolygonTransactionApi.js | 41 ++++++++++++--- types/Keyguard.d.ts | 24 ++++++++- 11 files changed, 178 insertions(+), 15 deletions(-) create mode 100644 src/assets/icons/usdc_dark.svg diff --git a/client/src/PublicRequest.ts b/client/src/PublicRequest.ts index e647968ae..567471098 100644 --- a/client/src/PublicRequest.ts +++ b/client/src/PublicRequest.ts @@ -219,6 +219,14 @@ export type PolygonTransactionInfo = { */ amount?: number, + /** + * The sender's nonce in the token contract, required when calling the + * contract function `swapWithApproval` for bridged USDC.e. + */ + approval?: { + tokenNonce: number, + }, + /** * The sender's nonce in the token contract, required when calling the * contract function `transferWithPermit` for native USDC. diff --git a/src/assets/icons/usdc_dark.svg b/src/assets/icons/usdc_dark.svg new file mode 100644 index 000000000..7f80ce961 --- /dev/null +++ b/src/assets/icons/usdc_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/components/PolygonAddressInfo.js b/src/components/PolygonAddressInfo.js index 1bb71c2a6..3e9e789bd 100644 --- a/src/components/PolygonAddressInfo.js +++ b/src/components/PolygonAddressInfo.js @@ -7,7 +7,7 @@ class PolygonAddressInfo { // eslint-disable-line no-unused-vars /** * @param {string} address * @param {string} [label] - * @param {'none' | 'usdc' | 'unknown'} [logo = 'none'] + * @param {'none' | 'usdc' | 'usdc_dark' | 'unknown'} [logo = 'none'] */ constructor(address, label, logo = 'none') { this._address = address; @@ -37,7 +37,7 @@ class PolygonAddressInfo { // eslint-disable-line no-unused-vars $avatar.classList.add('unlabelled'); } $el.appendChild($avatar); - } else if (this._logo === 'usdc' || this._logo === 'unknown') { + } else if (this._logo === 'usdc' || this._logo === 'usdc_dark' || this._logo === 'unknown') { const $img = document.createElement('img'); $img.classList.add('logo'); $img.src = `../../assets/icons/${this._logo}.svg`; diff --git a/src/config/config.local.js b/src/config/config.local.js index 42ba07c0e..7c12e7883 100644 --- a/src/config/config.local.js +++ b/src/config/config.local.js @@ -22,4 +22,6 @@ const CONFIG = { // eslint-disable-line no-unused-vars NATIVE_USDC_CONTRACT_ADDRESS: '0x9999f7Fea5938fD3b1E26A12c3f2fb024e194f97', NATIVE_USDC_TRANSFER_CONTRACT_ADDRESS: '0x5D101A320547f8D640c44fDfe5d1f35224f00B8B', // v1 + + USDC_SWAP_CONTRACT_ADDRESS: '0x72e64Cff5cfFD4BFbC5b8d4fB081B33B9EE3e30e', }; diff --git a/src/config/config.mainnet.js b/src/config/config.mainnet.js index f287686d7..a73a750a8 100644 --- a/src/config/config.mainnet.js +++ b/src/config/config.mainnet.js @@ -13,4 +13,6 @@ const CONFIG = { // eslint-disable-line no-unused-vars NATIVE_USDC_CONTRACT_ADDRESS: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359', NATIVE_USDC_TRANSFER_CONTRACT_ADDRESS: '0x3157d422cd1be13AC4a7cb00957ed717e648DFf2', // v1 + + USDC_SWAP_CONTRACT_ADDRESS: '', }; diff --git a/src/config/config.testnet.js b/src/config/config.testnet.js index 9bbaaca97..f83fe8b68 100644 --- a/src/config/config.testnet.js +++ b/src/config/config.testnet.js @@ -13,4 +13,6 @@ const CONFIG = { // eslint-disable-line no-unused-vars NATIVE_USDC_CONTRACT_ADDRESS: '0x9999f7Fea5938fD3b1E26A12c3f2fb024e194f97', NATIVE_USDC_TRANSFER_CONTRACT_ADDRESS: '0x5D101A320547f8D640c44fDfe5d1f35224f00B8B', // v1 + + USDC_SWAP_CONTRACT_ADDRESS: '0x72e64Cff5cfFD4BFbC5b8d4fB081B33B9EE3e30e', }; diff --git a/src/lib/polygon/PolygonContractABIs.full.js.txt b/src/lib/polygon/PolygonContractABIs.full.js.txt index a20a4824d..73c2ef07b 100644 --- a/src/lib/polygon/PolygonContractABIs.full.js.txt +++ b/src/lib/polygon/PolygonContractABIs.full.js.txt @@ -247,5 +247,55 @@ const PolygonContractABIsFull = { // eslint-disable-line no-unused-vars 'function withdrawToken(address token, uint256 amount, address target)', 'function wrappedChainToken() view returns (address)', ], + + SWAP_CONTRACT_ABI: [ + "constructor()", + "event DomainRegistered(bytes32 indexed domainSeparator, bytes domainValue)", + "event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)", + "event RequestTypeRegistered(bytes32 indexed typeHash, string typeStr)", + "function EIP712_DOMAIN_TYPE() view returns (string)", + "function deposits(address) view returns (uint256)", + "function domains(bytes32) view returns (bool)", + "function execute(tuple(address from, address to, uint256 value, uint256 gas, uint256 nonce, bytes data, uint256 validUntil) request, bytes32 domainSeparator, bytes32 requestTypeHash, bytes suffixData, bytes signature) payable returns (bool success, bytes ret)", + "function getGasAndDataLimits() view returns (tuple(uint256 acceptanceBudget, uint256 preRelayedCallGasLimit, uint256 postRelayedCallGasLimit, uint256 calldataSizeLimit) limits)", + "function getHubAddr() view returns (address)", + "function getMinimumRelayFee(tuple(uint256 gasPrice, uint256 pctRelayFee, uint256 baseRelayFee, address relayWorker, address paymaster, address forwarder, bytes paymasterData, uint256 clientId) relayData) view returns (uint256 amount)", + "function getNonce(address from) view returns (uint256)", + "function getRelayHubDeposit() view returns (uint256)", + "function getRequiredRelayFee(tuple(uint256 gasPrice, uint256 pctRelayFee, uint256 baseRelayFee, address relayWorker, address paymaster, address forwarder, bytes paymasterData, uint256 clientId) relayData, bytes4 methodId) view returns (uint256 amount)", + "function getRequiredRelayGas(bytes4 methodId) view returns (uint256 gas)", + "function isTrustedForwarder(address forwarder) view returns (bool)", + "function owner() view returns (address)", + "function postRelayedCall(bytes context, bool success, uint256 gasUseWithoutPost, tuple(uint256 gasPrice, uint256 pctRelayFee, uint256 baseRelayFee, address relayWorker, address paymaster, address forwarder, bytes paymasterData, uint256 clientId) relayData)", + "function preRelayedCall(tuple(tuple(address from, address to, uint256 value, uint256 gas, uint256 nonce, bytes data, uint256 validUntil) request, tuple(uint256 gasPrice, uint256 pctRelayFee, uint256 baseRelayFee, address relayWorker, address paymaster, address forwarder, bytes paymasterData, uint256 clientId) relayData) relayRequest, bytes signature, bytes approvalData, uint256 maxPossibleGas) returns (bytes context, bool revertOnRecipientRevert)", + "function registerDomainSeparator(string name, string version)", + "function registerRequestType(string typeName, string typeSuffix)", + "function registerSwapPool(address pool)", + "function registerToken(address token, address pool)", + "function registeredSwapPool(address) view returns (bool)", + "function registeredTokenPool(address) view returns (address)", + "function registeredTokenPoolFee(address token) view returns (uint24 fee)", + "function renounceOwnership()", + "function requiredRelayGas() view returns (uint256)", + "function setGasAndDataLimits(tuple(uint256 acceptanceBudget, uint256 preRelayedCallGasLimit, uint256 postRelayedCallGasLimit, uint256 calldataSizeLimit) limits)", + "function setMaxRequiredRelayGas(uint256 gas)", + "function setRelayHub(address hub)", + "function setRequiredRelayGas(bytes4 methodId, uint256 gas)", + "function setWrappedChainToken(address _wrappedChainToken)", + "function swap(address token, uint256 amount, address pool, uint256 targetAmount, uint256 fee)", + "function swapWithApproval(address token, uint256 amount, address pool, uint256 targetAmount, uint256 fee, uint256 approval, bytes32 sigR, bytes32 sigS, uint8 sigV)", + "function transferOwnership(address newOwner)", + "function trustedForwarder() view returns (address forwarder)", + "function typeHashes(bytes32) view returns (bool)", + "function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes _data)", + "function unregisterToken(address token)", + "function verify(tuple(address from, address to, uint256 value, uint256 gas, uint256 nonce, bytes data, uint256 validUntil) forwardRequest, bytes32 domainSeparator, bytes32 requestTypeHash, bytes suffixData, bytes signature) view", + "function versionPaymaster() view returns (string)", + "function versionRecipient() view returns (string)", + "function withdraw(uint256 amount, address target)", + "function withdrawRelayHubDeposit(uint256 amount, address target)", + "function withdrawToken(address token, uint256 amount, address target)", + "function wrappedChainToken() view returns (address)", + ], }; /* eslint-enable max-len */ diff --git a/src/lib/polygon/PolygonContractABIs.js b/src/lib/polygon/PolygonContractABIs.js index df595724e..3c5e869dd 100644 --- a/src/lib/polygon/PolygonContractABIs.js +++ b/src/lib/polygon/PolygonContractABIs.js @@ -18,5 +18,10 @@ const PolygonContractABIs = { // eslint-disable-line no-unused-vars 'function transfer(address token, uint256 amount, address target, uint256 fee)', 'function transferWithPermit(address token, uint256 amount, address target, uint256 fee, uint256 value, bytes32 sigR, bytes32 sigS, uint8 sigV)', ], + + SWAP_CONTRACT_ABI: [ + 'function swap(address token, uint256 amount, address pool, uint256 targetAmount, uint256 fee)', + 'function swapWithApproval(address token, uint256 amount, address pool, uint256 targetAmount, uint256 fee, uint256 approval, bytes32 sigR, bytes32 sigS, uint8 sigV)', + ], }; /* eslint-enable max-len */ diff --git a/src/request/sign-polygon-transaction/SignPolygonTransaction.js b/src/request/sign-polygon-transaction/SignPolygonTransaction.js index 13d3cca20..c229269fc 100644 --- a/src/request/sign-polygon-transaction/SignPolygonTransaction.js +++ b/src/request/sign-polygon-transaction/SignPolygonTransaction.js @@ -34,18 +34,24 @@ class SignPolygonTransaction { const $sender = (this.$el.querySelector('.accounts .sender')); if (request.description.name === 'refund') { new PolygonAddressInfo(relayRequest.to, request.senderLabel, 'unknown').renderTo($sender); + } else if (request.description.name === 'swap' || request.description.name === 'swapWithApproval') { + new PolygonAddressInfo(relayRequest.from, 'USDC.e', 'usdc_dark').renderTo($sender); } else { new PolygonAddressInfo(relayRequest.from, request.keyLabel, 'usdc').renderTo($sender); } /** @type {HTMLLinkElement} */ const $recipient = (this.$el.querySelector('.accounts .recipient')); - const recipientAddress = /** @type {string} */ (request.description.args.target); - new PolygonAddressInfo( - recipientAddress, - request.description.name === 'refund' ? request.keyLabel : request.recipientLabel, - request.description.name === 'refund' ? 'usdc' : 'none', - ).renderTo($recipient); + if (request.description.name === 'swap' || request.description.name === 'swapWithApproval') { + new PolygonAddressInfo(relayRequest.from, 'USDC', 'usdc').renderTo($recipient); + } else { + const recipientAddress = /** @type {string} */ (request.description.args.target); + new PolygonAddressInfo( + recipientAddress, + request.description.name === 'refund' ? request.keyLabel : request.recipientLabel, + request.description.name === 'refund' ? 'usdc' : 'none', + ).renderTo($recipient); + } /** @type {HTMLDivElement} */ const $value = (this.$el.querySelector('#value')); @@ -149,6 +155,38 @@ class SignPolygonTransaction { ]); } + if (request.description.name === 'swapWithApproval') { + const { sigR, sigS, sigV } = await polygonKey.signUsdcApproval( + request.keyPath, + new ethers.Contract( + CONFIG.USDC_CONTRACT_ADDRESS, + PolygonContractABIs.USDC_CONTRACT_ABI, + ), + transferContract, + request.description.args.approval, + // Has been validated to be defined when function called is `swapWithApproval` + /** @type {{ tokenNonce: number }} */ (request.approval).tokenNonce, + request.request.from, + ); + + const swapContract = new ethers.Contract( + transferContract, + PolygonContractABIs.SWAP_CONTRACT_ABI, + ); + + request.request.data = swapContract.interface.encodeFunctionData(request.description.name, [ + /* address token */ request.description.args.token, + /* uint256 amount */ request.description.args.amount, + /* address pool */ request.description.args.pool, + /* uint256 targetAmount */ request.description.args.targetAmount, + /* uint256 fee */ request.description.args.fee, + /* uint256 approval */ request.description.args.approval, + /* bytes32 sigR */ sigR, + /* bytes32 sigS */ sigS, + /* uint8 sigV */ sigV, + ]); + } + const typedData = new OpenGSN.TypedRequestData( CONFIG.POLYGON_CHAIN_ID, transferContract, diff --git a/src/request/sign-polygon-transaction/SignPolygonTransactionApi.js b/src/request/sign-polygon-transaction/SignPolygonTransactionApi.js index 3ce8f1893..06fae5cc9 100644 --- a/src/request/sign-polygon-transaction/SignPolygonTransactionApi.js +++ b/src/request/sign-polygon-transaction/SignPolygonTransactionApi.js @@ -59,7 +59,9 @@ class SignPolygonTransactionApi extends PolygonRequestParserMixin(TopLevelApi) { * KeyguardRequest.OpenGsnForwardRequest, * PolygonTransferDescription * | PolygonTransferWithPermitDescription - * | PolygonRefundDescription, + * | PolygonRefundDescription + * | PolygonSwapDescription + * | PolygonSwapWithApprovalDescription, * ]} */ parseOpenGsnForwardRequest(request) { @@ -68,7 +70,9 @@ class SignPolygonTransactionApi extends PolygonRequestParserMixin(TopLevelApi) { /** * @type {PolygonTransferDescription * | PolygonTransferWithPermitDescription - * | PolygonRefundDescription} + * | PolygonRefundDescription + * | PolygonSwapDescription + * | PolygonSwapWithApprovalDescription} */ let description; @@ -106,19 +110,44 @@ class SignPolygonTransactionApi extends PolygonRequestParserMixin(TopLevelApi) { if (!['refund'].includes(description.name)) { throw new Errors.InvalidRequestError('Requested Polygon contract method is invalid'); } + } else if (forwardRequest.to === CONFIG.USDC_SWAP_CONTRACT_ADDRESS) { + const usdcTransferContract = new ethers.Contract( + CONFIG.USDC_SWAP_CONTRACT_ADDRESS, + PolygonContractABIs.SWAP_CONTRACT_ABI, + ); + + /** @type {PolygonSwapDescription | PolygonSwapWithApprovalDescription} */ + description = (usdcTransferContract.interface.parseTransaction({ + data: forwardRequest.data, + value: forwardRequest.value, + })); + + if (description.args.token !== CONFIG.USDC_CONTRACT_ADDRESS) { + throw new Errors.InvalidRequestError('Invalid USDC token contract in request data'); + } + + if (!['swap', 'swapWithApproval'].includes(description.name)) { + throw new Errors.InvalidRequestError('Requested Polygon contract method is invalid'); + } } else { throw new Errors.InvalidRequestError('request.to address is not allowed'); } + // Check that permit object exists when method is 'transferWithPermit', and unset for other methods. + if ((description.name === 'transferWithPermit') !== !!request.permit) { + throw new Errors.InvalidRequestError('`permit` object is only allowed for contract method ' + + '"transferWithPermit"'); + } + // Check that amount exists when method is 'refund', and unset for other methods. if ((description.name === 'refund') !== !!request.amount) { throw new Errors.InvalidRequestError('`amount` is only allowed for contract method "refund"'); } - // Check that permit object exists when method is 'transferWithPermit', and unset for other methods. - if ((description.name === 'transferWithPermit') !== !!request.permit) { - throw new Errors.InvalidRequestError('`permit` object is only allowed for contract method ' - + '"transferWithPermit"'); + // Check that approval object exists when method is 'swapWithApproval', and unset for other methods. + if ((description.name === 'swapWithApproval') !== !!request.approval) { + throw new Errors.InvalidRequestError('`approval` object is only allowed for contract method ' + + '"swapWithApproval"'); } return [forwardRequest, description]; diff --git a/types/Keyguard.d.ts b/types/Keyguard.d.ts index 28bea8127..9dd3a3b8c 100644 --- a/types/Keyguard.d.ts +++ b/types/Keyguard.d.ts @@ -145,6 +145,26 @@ type PolygonRefundDescription = ethers.utils.TransactionDescription & { readonly args: PolygonRefundArgs, }; +interface PolygonSwapArgs extends ReadonlyArray { + readonly token: string, + readonly amount: ethers.BigNumber, + readonly pool: string, + readonly targetAmount: ethers.BigNumber, + readonly fee: ethers.BigNumber, +} + +type PolygonSwapDescription = ethers.utils.TransactionDescription & { + readonly name: 'swap', + readonly args: PolygonSwapArgs, +}; + +interface PolygonSwapWithApprovalArgs extends PolygonSwapArgs, PolygonUsdcApproval {} + +type PolygonSwapWithApprovalDescription = ethers.utils.TransactionDescription & { + readonly name: 'swapWithApproval', + readonly args: PolygonSwapWithApprovalArgs, +}; + type NimHtlcContents = { refundAddress: string, redeemAddress: string, @@ -286,7 +306,9 @@ type Parsed = KeyId2KeyInfo & { description: PolygonTransferDescription | PolygonTransferWithPermitDescription - | PolygonRefundDescription } : + | PolygonRefundDescription + | PolygonSwapDescription + | PolygonSwapWithApprovalDescription } : T extends Is ? KeyId2KeyInfo> & { layout: KeyguardRequest.SignSwapRequestLayout } : From f520440d6e00cdf5b0c612b497110ddc7551c49c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren?= Date: Thu, 22 Feb 2024 13:00:54 +0100 Subject: [PATCH 3/6] Improve differentiation between contract methods for USDC recipient --- .../SignPolygonTransaction.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/request/sign-polygon-transaction/SignPolygonTransaction.js b/src/request/sign-polygon-transaction/SignPolygonTransaction.js index c229269fc..44515c5f9 100644 --- a/src/request/sign-polygon-transaction/SignPolygonTransaction.js +++ b/src/request/sign-polygon-transaction/SignPolygonTransaction.js @@ -42,14 +42,19 @@ class SignPolygonTransaction { /** @type {HTMLLinkElement} */ const $recipient = (this.$el.querySelector('.accounts .recipient')); - if (request.description.name === 'swap' || request.description.name === 'swapWithApproval') { + if (request.description.name === 'refund') { + new PolygonAddressInfo( + /** @type {string} */ (request.description.args.target), + request.keyLabel, + 'usdc', + ).renderTo($recipient); + } else if (request.description.name === 'swap' || request.description.name === 'swapWithApproval') { new PolygonAddressInfo(relayRequest.from, 'USDC', 'usdc').renderTo($recipient); } else { - const recipientAddress = /** @type {string} */ (request.description.args.target); new PolygonAddressInfo( - recipientAddress, - request.description.name === 'refund' ? request.keyLabel : request.recipientLabel, - request.description.name === 'refund' ? 'usdc' : 'none', + /** @type {string} */ (request.description.args.target), + request.recipientLabel, + 'none', ).renderTo($recipient); } From 6062a255d43dcd744ef20bfc15bbaa9da4e1448a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren?= Date: Thu, 22 Feb 2024 13:01:32 +0100 Subject: [PATCH 4/6] Verify a USDC swap's `targetAmount` is not too low Must be >= 99% of the input `amount`. --- .../SignPolygonTransactionApi.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/request/sign-polygon-transaction/SignPolygonTransactionApi.js b/src/request/sign-polygon-transaction/SignPolygonTransactionApi.js index 06fae5cc9..22b8f0be2 100644 --- a/src/request/sign-polygon-transaction/SignPolygonTransactionApi.js +++ b/src/request/sign-polygon-transaction/SignPolygonTransactionApi.js @@ -129,6 +129,19 @@ class SignPolygonTransactionApi extends PolygonRequestParserMixin(TopLevelApi) { if (!['swap', 'swapWithApproval'].includes(description.name)) { throw new Errors.InvalidRequestError('Requested Polygon contract method is invalid'); } + + // Ensure swap `targetAmount` is not too low + const inputAmount = /** @type {PolygonSwapDescription | PolygonSwapWithApprovalDescription} */ (description) + .args + .amount; + const targetAmount = /** @type {PolygonSwapDescription | PolygonSwapWithApprovalDescription} */ (description) // eslint-disable-line max-len + .args + .targetAmount; + if (targetAmount.lt(inputAmount.mul(99).div(100))) { + throw new Errors.InvalidRequestError( + 'Requested Polygon swap `targetAmount` more than 1% lower than the input `amount`', + ); + } } else { throw new Errors.InvalidRequestError('request.to address is not allowed'); } From 5b425cad2cbce053e8ab27ecf5f91682bfe9247e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren?= Date: Thu, 22 Feb 2024 13:11:23 +0100 Subject: [PATCH 5/6] Prefix legacy USDC constants with BRIDGED_* --- src/config/config.local.js | 4 +- src/config/config.mainnet.js | 4 +- src/config/config.testnet.js | 4 +- .../polygon/PolygonContractABIs.full.js.txt | 4 +- src/lib/polygon/PolygonContractABIs.js | 4 +- src/lib/polygon/PolygonKey.js | 2 +- .../SignPolygonTransaction.js | 4 +- .../SignPolygonTransactionApi.js | 8 ++-- src/request/sign-swap/SignSwap.js | 10 ++-- src/request/sign-swap/SignSwapApi.js | 8 ++-- src/request/swap-iframe/SwapIFrameApi.js | 46 +++++++++++-------- 11 files changed, 53 insertions(+), 45 deletions(-) diff --git a/src/config/config.local.js b/src/config/config.local.js index 7c12e7883..8371066c9 100644 --- a/src/config/config.local.js +++ b/src/config/config.local.js @@ -17,8 +17,8 @@ const CONFIG = { // eslint-disable-line no-unused-vars ROOT_REDIRECT: 'https://wallet.nimiq-testnet.com', POLYGON_CHAIN_ID: 80001, - USDC_CONTRACT_ADDRESS: '0x0FA8781a83E46826621b3BC094Ea2A0212e71B23', - USDC_HTLC_CONTRACT_ADDRESS: '0x2EB7cd7791b947A25d629219ead941fCd8f364BF', + BRIDGED_USDC_CONTRACT_ADDRESS: '0x0FA8781a83E46826621b3BC094Ea2A0212e71B23', + BRIDGED_USDC_HTLC_CONTRACT_ADDRESS: '0x2EB7cd7791b947A25d629219ead941fCd8f364BF', NATIVE_USDC_CONTRACT_ADDRESS: '0x9999f7Fea5938fD3b1E26A12c3f2fb024e194f97', NATIVE_USDC_TRANSFER_CONTRACT_ADDRESS: '0x5D101A320547f8D640c44fDfe5d1f35224f00B8B', // v1 diff --git a/src/config/config.mainnet.js b/src/config/config.mainnet.js index a73a750a8..0ea16cc40 100644 --- a/src/config/config.mainnet.js +++ b/src/config/config.mainnet.js @@ -8,8 +8,8 @@ const CONFIG = { // eslint-disable-line no-unused-vars ROOT_REDIRECT: 'https://wallet.nimiq.com', POLYGON_CHAIN_ID: 137, - USDC_CONTRACT_ADDRESS: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174', - USDC_HTLC_CONTRACT_ADDRESS: '0xF615bD7EA00C4Cc7F39Faad0895dB5f40891359f', + BRIDGED_USDC_CONTRACT_ADDRESS: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174', + BRIDGED_USDC_HTLC_CONTRACT_ADDRESS: '0xF615bD7EA00C4Cc7F39Faad0895dB5f40891359f', NATIVE_USDC_CONTRACT_ADDRESS: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359', NATIVE_USDC_TRANSFER_CONTRACT_ADDRESS: '0x3157d422cd1be13AC4a7cb00957ed717e648DFf2', // v1 diff --git a/src/config/config.testnet.js b/src/config/config.testnet.js index f83fe8b68..306ae17a1 100644 --- a/src/config/config.testnet.js +++ b/src/config/config.testnet.js @@ -8,8 +8,8 @@ const CONFIG = { // eslint-disable-line no-unused-vars ROOT_REDIRECT: 'https://wallet.nimiq-testnet.com', POLYGON_CHAIN_ID: 80001, - USDC_CONTRACT_ADDRESS: '0x0FA8781a83E46826621b3BC094Ea2A0212e71B23', - USDC_HTLC_CONTRACT_ADDRESS: '0x2EB7cd7791b947A25d629219ead941fCd8f364BF', + BRIDGED_USDC_CONTRACT_ADDRESS: '0x0FA8781a83E46826621b3BC094Ea2A0212e71B23', + BRIDGED_USDC_HTLC_CONTRACT_ADDRESS: '0x2EB7cd7791b947A25d629219ead941fCd8f364BF', NATIVE_USDC_CONTRACT_ADDRESS: '0x9999f7Fea5938fD3b1E26A12c3f2fb024e194f97', NATIVE_USDC_TRANSFER_CONTRACT_ADDRESS: '0x5D101A320547f8D640c44fDfe5d1f35224f00B8B', // v1 diff --git a/src/lib/polygon/PolygonContractABIs.full.js.txt b/src/lib/polygon/PolygonContractABIs.full.js.txt index 73c2ef07b..275215d27 100644 --- a/src/lib/polygon/PolygonContractABIs.full.js.txt +++ b/src/lib/polygon/PolygonContractABIs.full.js.txt @@ -1,6 +1,6 @@ /* eslint-disable max-len */ const PolygonContractABIsFull = { // eslint-disable-line no-unused-vars - USDC_CONTRACT_ABI: [ + BRIDGED_USDC_CONTRACT_ABI: [ 'event Approval(address indexed owner, address indexed spender, uint256 value)', 'event AuthorizationCanceled(address indexed authorizer, bytes32 indexed nonce)', 'event AuthorizationUsed(address indexed authorizer, bytes32 indexed nonce)', @@ -74,7 +74,7 @@ const PolygonContractABIsFull = { // eslint-disable-line no-unused-vars 'function withdrawWithAuthorization(address owner, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 nonce, uint8 v, bytes32 r, bytes32 s)', ], - USDC_HTLC_CONTRACT_ABI: [ + BRIDGED_USDC_HTLC_CONTRACT_ABI: [ 'constructor()', 'event DomainRegistered(bytes32 indexed domainSeparator, bytes domainValue)', 'event Open(bytes32 indexed id, address token, uint256 amount, address recipient, bytes32 hash, uint256 timeout)', diff --git a/src/lib/polygon/PolygonContractABIs.js b/src/lib/polygon/PolygonContractABIs.js index 3c5e869dd..767c59967 100644 --- a/src/lib/polygon/PolygonContractABIs.js +++ b/src/lib/polygon/PolygonContractABIs.js @@ -1,10 +1,10 @@ /* eslint-disable max-len */ const PolygonContractABIs = { // eslint-disable-line no-unused-vars - USDC_CONTRACT_ABI: [ + BRIDGED_USDC_CONTRACT_ABI: [ 'function approve(address spender, uint256 amount) returns (bool)', ], - USDC_HTLC_CONTRACT_ABI: [ + BRIDGED_USDC_HTLC_CONTRACT_ABI: [ 'function open(bytes32 id, address token, uint256 amount, address refundAddress, address recipientAddress, bytes32 hash, uint256 timeout, uint256 fee)', 'function openWithApproval(bytes32 id, address token, uint256 amount, address refundAddress, address recipientAddress, bytes32 hash, uint256 timeout, uint256 fee, uint256 approval, bytes32 sigR, bytes32 sigS, uint8 sigV)', 'function redeem(bytes32 id, address target, bytes32 secret, uint256 fee)', diff --git a/src/lib/polygon/PolygonKey.js b/src/lib/polygon/PolygonKey.js index 3ea2c81f7..9f0e6efed 100644 --- a/src/lib/polygon/PolygonKey.js +++ b/src/lib/polygon/PolygonKey.js @@ -65,7 +65,7 @@ class PolygonKey { // eslint-disable-line no-unused-vars const domain = { name: 'USD Coin (PoS)', // This is currently the same for testnet and mainnet version: '1', // This is currently the same for testnet and mainnet - verifyingContract: CONFIG.USDC_CONTRACT_ADDRESS, + verifyingContract: CONFIG.BRIDGED_USDC_CONTRACT_ADDRESS, salt: ethers.utils.hexZeroPad(ethers.utils.hexlify(CONFIG.POLYGON_CHAIN_ID), 32), }; diff --git a/src/request/sign-polygon-transaction/SignPolygonTransaction.js b/src/request/sign-polygon-transaction/SignPolygonTransaction.js index 44515c5f9..2e1aeb567 100644 --- a/src/request/sign-polygon-transaction/SignPolygonTransaction.js +++ b/src/request/sign-polygon-transaction/SignPolygonTransaction.js @@ -164,8 +164,8 @@ class SignPolygonTransaction { const { sigR, sigS, sigV } = await polygonKey.signUsdcApproval( request.keyPath, new ethers.Contract( - CONFIG.USDC_CONTRACT_ADDRESS, - PolygonContractABIs.USDC_CONTRACT_ABI, + CONFIG.BRIDGED_USDC_CONTRACT_ADDRESS, + PolygonContractABIs.BRIDGED_USDC_CONTRACT_ABI, ), transferContract, request.description.args.approval, diff --git a/src/request/sign-polygon-transaction/SignPolygonTransactionApi.js b/src/request/sign-polygon-transaction/SignPolygonTransactionApi.js index 22b8f0be2..ff6669726 100644 --- a/src/request/sign-polygon-transaction/SignPolygonTransactionApi.js +++ b/src/request/sign-polygon-transaction/SignPolygonTransactionApi.js @@ -95,10 +95,10 @@ class SignPolygonTransactionApi extends PolygonRequestParserMixin(TopLevelApi) { if (!['transfer', 'transferWithPermit'].includes(description.name)) { throw new Errors.InvalidRequestError('Requested Polygon contract method is invalid'); } - } else if (forwardRequest.to === CONFIG.USDC_HTLC_CONTRACT_ADDRESS) { + } else if (forwardRequest.to === CONFIG.BRIDGED_USDC_HTLC_CONTRACT_ADDRESS) { const usdcHtlcContract = new ethers.Contract( - CONFIG.USDC_HTLC_CONTRACT_ADDRESS, - PolygonContractABIs.USDC_HTLC_CONTRACT_ABI, + CONFIG.BRIDGED_USDC_HTLC_CONTRACT_ADDRESS, + PolygonContractABIs.BRIDGED_USDC_HTLC_CONTRACT_ABI, ); /** @type {PolygonRefundDescription} */ @@ -122,7 +122,7 @@ class SignPolygonTransactionApi extends PolygonRequestParserMixin(TopLevelApi) { value: forwardRequest.value, })); - if (description.args.token !== CONFIG.USDC_CONTRACT_ADDRESS) { + if (description.args.token !== CONFIG.BRIDGED_USDC_CONTRACT_ADDRESS) { throw new Errors.InvalidRequestError('Invalid USDC token contract in request data'); } diff --git a/src/request/sign-swap/SignSwap.js b/src/request/sign-swap/SignSwap.js index a180f7826..4047c7c3b 100644 --- a/src/request/sign-swap/SignSwap.js +++ b/src/request/sign-swap/SignSwap.js @@ -549,10 +549,10 @@ class SignSwap { const { sigR, sigS, sigV } = await polygonKey.signUsdcApproval( request.fund.keyPath, new ethers.Contract( - CONFIG.USDC_CONTRACT_ADDRESS, - PolygonContractABIs.USDC_CONTRACT_ABI, + CONFIG.BRIDGED_USDC_CONTRACT_ADDRESS, + PolygonContractABIs.BRIDGED_USDC_CONTRACT_ABI, ), - CONFIG.USDC_HTLC_CONTRACT_ADDRESS, + CONFIG.BRIDGED_USDC_HTLC_CONTRACT_ADDRESS, request.fund.description.args.approval, // Has been validated to be defined when function called is `openWithApproval` /** @type {{ tokenNonce: number }} */ (request.fund.approval).tokenNonce, @@ -560,8 +560,8 @@ class SignSwap { ); const htlcContract = new ethers.Contract( - CONFIG.USDC_HTLC_CONTRACT_ADDRESS, - PolygonContractABIs.USDC_HTLC_CONTRACT_ABI, + CONFIG.BRIDGED_USDC_HTLC_CONTRACT_ADDRESS, + PolygonContractABIs.BRIDGED_USDC_HTLC_CONTRACT_ABI, ); request.fund.request.data = htlcContract.interface.encodeFunctionData(request.fund.description.name, [ diff --git a/src/request/sign-swap/SignSwapApi.js b/src/request/sign-swap/SignSwapApi.js index 6b593ab40..3baa8329e 100644 --- a/src/request/sign-swap/SignSwapApi.js +++ b/src/request/sign-swap/SignSwapApi.js @@ -320,13 +320,13 @@ class SignSwapApi extends PolygonRequestParserMixin(BitcoinRequestParserMixin(To parseOpenGsnForwardRequest(request, allowedMethods) { const forwardRequest = this.parseOpenGsnForwardRequestRoot(request.request); - if (forwardRequest.to !== CONFIG.USDC_HTLC_CONTRACT_ADDRESS) { + if (forwardRequest.to !== CONFIG.BRIDGED_USDC_HTLC_CONTRACT_ADDRESS) { throw new Errors.InvalidRequestError('request.to address is not allowed'); } const usdcHtlcContract = new ethers.Contract( - CONFIG.USDC_HTLC_CONTRACT_ADDRESS, - PolygonContractABIs.USDC_HTLC_CONTRACT_ABI, + CONFIG.BRIDGED_USDC_HTLC_CONTRACT_ADDRESS, + PolygonContractABIs.BRIDGED_USDC_HTLC_CONTRACT_ABI, ); // eslint-disable-next-line operator-linebreak @@ -345,7 +345,7 @@ class SignSwapApi extends PolygonRequestParserMixin(BitcoinRequestParserMixin(To } if (description.name === 'open' || description.name === 'openWithApproval') { - if (description.args.token !== CONFIG.USDC_CONTRACT_ADDRESS) { + if (description.args.token !== CONFIG.BRIDGED_USDC_CONTRACT_ADDRESS) { throw new Errors.InvalidRequestError('Invalid USDC token contract in request data'); } diff --git a/src/request/swap-iframe/SwapIFrameApi.js b/src/request/swap-iframe/SwapIFrameApi.js index f55d48789..5f02cc55d 100644 --- a/src/request/swap-iframe/SwapIFrameApi.js +++ b/src/request/swap-iframe/SwapIFrameApi.js @@ -87,8 +87,8 @@ class SwapIFrameApi extends BitcoinRequestParserMixin(RequestParser) { // eslint } if (storedRawRequest.fund.type === 'USDC') { const usdcHtlcContract = new ethers.Contract( - CONFIG.USDC_HTLC_CONTRACT_ADDRESS, - PolygonContractABIs.USDC_HTLC_CONTRACT_ABI, + CONFIG.BRIDGED_USDC_HTLC_CONTRACT_ADDRESS, + PolygonContractABIs.BRIDGED_USDC_HTLC_CONTRACT_ABI, ); storedRawRequest.fund.description = usdcHtlcContract.interface.parseTransaction({ @@ -102,8 +102,8 @@ class SwapIFrameApi extends BitcoinRequestParserMixin(RequestParser) { // eslint } if (storedRawRequest.redeem.type === 'USDC') { const usdcHtlcContract = new ethers.Contract( - CONFIG.USDC_HTLC_CONTRACT_ADDRESS, - PolygonContractABIs.USDC_HTLC_CONTRACT_ABI, + CONFIG.BRIDGED_USDC_HTLC_CONTRACT_ADDRESS, + PolygonContractABIs.BRIDGED_USDC_HTLC_CONTRACT_ABI, ); storedRawRequest.redeem.description = usdcHtlcContract.interface.parseTransaction({ @@ -226,8 +226,8 @@ class SwapIFrameApi extends BitcoinRequestParserMixin(RequestParser) { // eslint if (request.fund.type === 'USDC' && storedRequest.fund.type === 'USDC') { const usdcHtlcContract = new ethers.Contract( - CONFIG.USDC_HTLC_CONTRACT_ADDRESS, - PolygonContractABIs.USDC_HTLC_CONTRACT_ABI, + CONFIG.BRIDGED_USDC_HTLC_CONTRACT_ADDRESS, + PolygonContractABIs.BRIDGED_USDC_HTLC_CONTRACT_ABI, ); const description = /** @type {PolygonOpenDescription} */ (usdcHtlcContract.interface.parseTransaction({ @@ -243,7 +243,7 @@ class SwapIFrameApi extends BitcoinRequestParserMixin(RequestParser) { // eslint } // Verify already known parts of the data - if (description.args.token !== CONFIG.USDC_CONTRACT_ADDRESS) { + if (description.args.token !== CONFIG.BRIDGED_USDC_CONTRACT_ADDRESS) { throw new Errors.InvalidRequestError('Invalid USDC token contract in HTLC data'); } @@ -546,8 +546,8 @@ class SwapIFrameApi extends BitcoinRequestParserMixin(RequestParser) { // eslint if (parsedRequest.fund.type === 'USDC' && storedRequest.fund.type === 'USDC') { const usdcHtlcContract = new ethers.Contract( - CONFIG.USDC_HTLC_CONTRACT_ADDRESS, - PolygonContractABIs.USDC_HTLC_CONTRACT_ABI, + CONFIG.BRIDGED_USDC_HTLC_CONTRACT_ADDRESS, + PolygonContractABIs.BRIDGED_USDC_HTLC_CONTRACT_ABI, ); // Place contract details into existing function call data @@ -572,10 +572,14 @@ class SwapIFrameApi extends BitcoinRequestParserMixin(RequestParser) { // eslint ], ); - const typedData = new OpenGSN.TypedRequestData(CONFIG.POLYGON_CHAIN_ID, CONFIG.USDC_HTLC_CONTRACT_ADDRESS, { - request: storedRequest.fund.request, - relayData: storedRequest.fund.relayData, - }); + const typedData = new OpenGSN.TypedRequestData( + CONFIG.POLYGON_CHAIN_ID, + CONFIG.BRIDGED_USDC_HTLC_CONTRACT_ADDRESS, + { + request: storedRequest.fund.request, + relayData: storedRequest.fund.relayData, + }, + ); const { EIP712Domain, ...cleanedTypes } = typedData.types; @@ -695,8 +699,8 @@ class SwapIFrameApi extends BitcoinRequestParserMixin(RequestParser) { // eslint if (parsedRequest.redeem.type === 'USDC' && storedRequest.redeem.type === 'USDC') { const usdcHtlcContract = new ethers.Contract( - CONFIG.USDC_HTLC_CONTRACT_ADDRESS, - PolygonContractABIs.USDC_HTLC_CONTRACT_ABI, + CONFIG.BRIDGED_USDC_HTLC_CONTRACT_ADDRESS, + PolygonContractABIs.BRIDGED_USDC_HTLC_CONTRACT_ABI, ); // Place contract details into existing function call data @@ -712,10 +716,14 @@ class SwapIFrameApi extends BitcoinRequestParserMixin(RequestParser) { // eslint ], ); - const typedData = new OpenGSN.TypedRequestData(CONFIG.POLYGON_CHAIN_ID, CONFIG.USDC_HTLC_CONTRACT_ADDRESS, { - request: storedRequest.redeem.request, - relayData: storedRequest.redeem.relayData, - }); + const typedData = new OpenGSN.TypedRequestData( + CONFIG.POLYGON_CHAIN_ID, + CONFIG.BRIDGED_USDC_HTLC_CONTRACT_ADDRESS, + { + request: storedRequest.redeem.request, + relayData: storedRequest.redeem.relayData, + }, + ); const { EIP712Domain, ...cleanedTypes } = typedData.types; From 16b571b77f021a5bdc14cba06d44513d8a0a4c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren?= Date: Mon, 4 Mar 2024 12:37:57 +0100 Subject: [PATCH 6/6] Update USDC swap contract address for testnet --- src/config/config.local.js | 2 +- src/config/config.testnet.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/config.local.js b/src/config/config.local.js index 8371066c9..d0902ddfd 100644 --- a/src/config/config.local.js +++ b/src/config/config.local.js @@ -23,5 +23,5 @@ const CONFIG = { // eslint-disable-line no-unused-vars NATIVE_USDC_CONTRACT_ADDRESS: '0x9999f7Fea5938fD3b1E26A12c3f2fb024e194f97', NATIVE_USDC_TRANSFER_CONTRACT_ADDRESS: '0x5D101A320547f8D640c44fDfe5d1f35224f00B8B', // v1 - USDC_SWAP_CONTRACT_ADDRESS: '0x72e64Cff5cfFD4BFbC5b8d4fB081B33B9EE3e30e', + USDC_SWAP_CONTRACT_ADDRESS: '0xf4a619F6561CeE543BDa9BBA0cAC68758B607714', }; diff --git a/src/config/config.testnet.js b/src/config/config.testnet.js index 306ae17a1..0a344811c 100644 --- a/src/config/config.testnet.js +++ b/src/config/config.testnet.js @@ -14,5 +14,5 @@ const CONFIG = { // eslint-disable-line no-unused-vars NATIVE_USDC_CONTRACT_ADDRESS: '0x9999f7Fea5938fD3b1E26A12c3f2fb024e194f97', NATIVE_USDC_TRANSFER_CONTRACT_ADDRESS: '0x5D101A320547f8D640c44fDfe5d1f35224f00B8B', // v1 - USDC_SWAP_CONTRACT_ADDRESS: '0x72e64Cff5cfFD4BFbC5b8d4fB081B33B9EE3e30e', + USDC_SWAP_CONTRACT_ADDRESS: '0xf4a619F6561CeE543BDa9BBA0cAC68758B607714', };