diff --git a/packages/x-provider/src/signable-actions/withdrawal-actions/completeERC20Withdrawal.ts b/packages/x-provider/src/signable-actions/withdrawal-actions/completeERC20Withdrawal.ts index 7e71ceed9c..b07340dbef 100644 --- a/packages/x-provider/src/signable-actions/withdrawal-actions/completeERC20Withdrawal.ts +++ b/packages/x-provider/src/signable-actions/withdrawal-actions/completeERC20Withdrawal.ts @@ -1,11 +1,19 @@ +// Note that this file contains withdrawal functions that are shared +// by both ERC20 and ETH in completeERC20WithdrawalAction and completeEthWithdrawalAction import { Signer } from '@ethersproject/abstract-signer'; -import { ERC20Token, StarkSigner } from '@imtbl/x-client'; +import { TransactionResponse } from '@ethersproject/providers'; +import { + Contracts, + ERC20Token, + ImmutableXConfiguration, + StarkSigner, + signRegisterEthAddress, +} from '@imtbl/x-client'; import { isRegisteredOnChain } from '../registration'; import { getEncodeAssetInfo } from './getEncodeAssetInfo'; import { validateChain } from '../helpers'; import { ProviderConfiguration } from '../../config'; import { getWithdrawalBalances } from './getWithdrawalBalance'; -import { executeRegisterAndWithdrawAllFungible, executeWithdrawAllFungible } from './completeEthWithdrawal'; type CompleteERC20WithdrawalWorkflowParams = { ethSigner: Signer; @@ -17,6 +25,80 @@ type CompleteERC20WithdrawalWorkflowParams = { const ERC20TokenType = 'ERC20'; +export async function executeRegisterAndWithdrawAllFungible( + ethSigner: Signer, + starkSigner: StarkSigner, + starkPublicKey: string, + assetType: string, + config: ImmutableXConfiguration, +): Promise { + const etherKey = await ethSigner.getAddress(); + + const starkSignature = await signRegisterEthAddress( + starkSigner, + etherKey, + starkPublicKey, + ); + + // we use registration v4 contract as a wrapper for the core contract + // so that v3 and v4 withdrawals, AND on-chain registration can be executed in a single transaction + const contract = Contracts.RegistrationV4.connect( + config.ethConfiguration.registrationV4ContractAddress || config.ethConfiguration.registrationContractAddress, + ethSigner, + ); + + const populatedTransaction = await contract.populateTransaction.registerAndWithdrawAll( + etherKey, + starkPublicKey, + starkSignature, + assetType, + ); + + return ethSigner.sendTransaction(populatedTransaction); +} + +export async function executeWithdrawAllFungible( + ethSigner: Signer, + starkPublicKey: string, + assetType: string, + config: ImmutableXConfiguration, +): Promise { + // we use registration v4 contract as a wrapper for the core contract + // so that v3 and v4 withdrawals can be executed in a single transaction + // (if there are pending withdrawable funds for both) + const contract = Contracts.RegistrationV4.connect( + config.ethConfiguration.registrationV4ContractAddress || config.ethConfiguration.registrationContractAddress, + ethSigner, + ); + + const populatedTransaction = await contract.populateTransaction.withdrawAll( + await ethSigner.getAddress(), + starkPublicKey, + assetType, + ); + + return ethSigner.sendTransaction(populatedTransaction); +} + +export async function executeWithdrawFungible( + ethSigner: Signer, + starkPublicKey: string, + assetType: string, + config: ImmutableXConfiguration, +): Promise { + const contract = Contracts.CoreV4.connect( + config.ethConfiguration.coreContractAddress, + ethSigner, + ); + + const populatedTransaction = await contract.populateTransaction.withdraw( + await ethSigner.getAddress(), + assetType, + ); + + return ethSigner.sendTransaction(populatedTransaction); +} + // equivilant to Core SDK completeERC20WithdrawalV1Workflow // in src/workflows/withdrawal/completeERC20Withdrawal.ts export async function completeERC20WithdrawalAction({ @@ -42,28 +124,31 @@ export async function completeERC20WithdrawalAction({ config.immutableXConfig, ); - if (v3Balance.isZero() && v4Balance.isZero()) { - throw new Error('No balance to withdraw'); - } - - const isRegistered = await isRegisteredOnChain( - starkPublicKey, - ethSigner, - config, - ); - const assetType = await getEncodeAssetInfo('asset', ERC20TokenType, config.immutableXConfig, { token_address: token.tokenAddress, }); - if (isRegistered) { - return executeWithdrawAllFungible(ethSigner, starkPublicKey, assetType.asset_type, config.immutableXConfig); + if (!v3Balance.isZero() && !v3Balance.isNegative()) { + const isRegistered = await isRegisteredOnChain( + starkPublicKey, + ethSigner, + config, + ); + if (isRegistered) { + return executeWithdrawAllFungible(ethSigner, starkPublicKey, assetType.asset_type, config.immutableXConfig); + } + return executeRegisterAndWithdrawAllFungible( + ethSigner, + starkSigner, + starkPublicKey, + assetType.asset_type, + config.immutableXConfig, + ); } - return executeRegisterAndWithdrawAllFungible( - ethSigner, - starkSigner, - starkPublicKey, - assetType.asset_type, - config.immutableXConfig, - ); + + if (!v4Balance.isZero() && !v4Balance.isNegative()) { + return executeWithdrawFungible(ethSigner, starkPublicKey, assetType.asset_type, config.immutableXConfig); + } + + throw new Error('No balance to withdraw'); } diff --git a/packages/x-provider/src/signable-actions/withdrawal-actions/completeERC721Withdrawal.test.ts b/packages/x-provider/src/signable-actions/withdrawal-actions/completeERC721Withdrawal.test.ts index 95aaaa5b69..e62512feb1 100644 --- a/packages/x-provider/src/signable-actions/withdrawal-actions/completeERC721Withdrawal.test.ts +++ b/packages/x-provider/src/signable-actions/withdrawal-actions/completeERC721Withdrawal.test.ts @@ -2,6 +2,7 @@ import { Contracts } from '@imtbl/x-client'; import { imx } from '@imtbl/generated-clients'; import * as encUtils from 'enc-utils'; import { TransactionResponse } from '@ethersproject/providers'; +import { BigNumber } from '@ethersproject/bignumber'; import { getEncodeAssetInfo } from './getEncodeAssetInfo'; import { getSignableRegistrationOnchain, @@ -24,6 +25,7 @@ jest.mock('@imtbl/generated-clients'); async function act(): Promise { const signers = await generateSigners(privateKey1); + const mintsApi = new imx.MintsApi(testConfig.immutableXConfig.apiConfiguration); return await completeERC721WithdrawalAction({ ethSigner: signers.ethSigner, starkSigner: signers.starkSigner, @@ -34,11 +36,10 @@ async function act(): Promise { tokenId: '23', tokenAddress: '0x23cv1', }, - }); + }, mintsApi); } -// TODO fix MintsApi mocking so that getMintableTokenDetailsByClientTokenId does not return undefined -describe.skip('completeERC721Withdrawal action', () => { +describe('completeERC721Withdrawal action', () => { describe('when ERC721 is mintable', () => { const mintableErc721Token: imx.MintableTokenDetails = { token_id: '23', @@ -68,7 +69,8 @@ describe.skip('completeERC721Withdrawal action', () => { }); }); it('should complete ERC721 withdrawal with on-chain registered user', async () => { - (Contracts.Core.connect as jest.Mock).mockReturnValue({ + (Contracts.CoreV4.connect as jest.Mock).mockReturnValue({ + getWithdrawalBalance: jest.fn().mockReturnValue(BigNumber.from('1')), populateTransaction: { withdrawAndMint: jest.fn().mockResolvedValue(transactionResponse), }, @@ -80,9 +82,12 @@ describe.skip('completeERC721Withdrawal action', () => { await expect(response).toEqual(transactionResponse); }); it('should complete ERC721 withdrawal with unregistered user', async () => { - (Contracts.Registration.connect as jest.Mock).mockReturnValue({ + (Contracts.CoreV4.connect as jest.Mock).mockReturnValue({ + getWithdrawalBalance: jest.fn().mockReturnValue(BigNumber.from('1')), + }); + (Contracts.RegistrationV4.connect as jest.Mock).mockReturnValue({ populateTransaction: { - regsiterAndWithdrawAndMint: jest + registerWithdrawAndMint: jest .fn() .mockResolvedValue(transactionResponse), }, @@ -114,10 +119,18 @@ describe.skip('completeERC721Withdrawal action', () => { getMintableTokenDetailsByClientTokenId: jest .fn() .mockRejectedValue(error), + getMint: jest.fn(), + listMints: jest.fn(), + mintTokens: jest.fn(), + basePath: jest.fn(), + axios: jest.fn(), + configuration: jest.fn(), }); }); + it('should complete ERC721 withdrawal with on-chain registered user', async () => { - (Contracts.Core.connect as jest.Mock).mockReturnValue({ + (Contracts.CoreV4.connect as jest.Mock).mockReturnValue({ + getWithdrawalBalance: jest.fn().mockReturnValue(BigNumber.from('1')), populateTransaction: { withdrawNft: jest.fn().mockResolvedValue(transactionResponse), }, @@ -126,8 +139,12 @@ describe.skip('completeERC721Withdrawal action', () => { const response = await act(); await expect(response).toEqual(transactionResponse); }); + it('should complete ERC721 withdrawal with unregistered user', async () => { - (Contracts.Registration.connect as jest.Mock).mockReturnValue({ + (Contracts.CoreV4.connect as jest.Mock).mockReturnValue({ + getWithdrawalBalance: jest.fn().mockReturnValue(BigNumber.from('1')), + }); + (Contracts.RegistrationV4.connect as jest.Mock).mockReturnValue({ populateTransaction: { registerAndWithdrawNft: jest .fn() @@ -162,6 +179,7 @@ describe.skip('completeERC721Withdrawal action', () => { it('should throw error', async () => { const signers = await generateSigners(privateKey1); + const mintsApi = new imx.MintsApi(testConfig.immutableXConfig.apiConfiguration); await expect( completeERC721WithdrawalAction({ ethSigner: signers.ethSigner, @@ -173,7 +191,7 @@ describe.skip('completeERC721Withdrawal action', () => { tokenId: '23', tokenAddress: '0x23cv1', }, - }), + }, mintsApi), ).rejects.toThrowError(); }); }); diff --git a/packages/x-provider/src/signable-actions/withdrawal-actions/completeERC721Withdrawal.ts b/packages/x-provider/src/signable-actions/withdrawal-actions/completeERC721Withdrawal.ts index 1dc35bef9b..1eb82285e2 100644 --- a/packages/x-provider/src/signable-actions/withdrawal-actions/completeERC721Withdrawal.ts +++ b/packages/x-provider/src/signable-actions/withdrawal-actions/completeERC721Withdrawal.ts @@ -1,5 +1,4 @@ import { Signer } from '@ethersproject/abstract-signer'; -import { imx } from '@imtbl/generated-clients'; import { Contracts, ERC721Token, @@ -14,7 +13,7 @@ import { ProviderConfiguration } from '../../config'; import { getEncodeAssetInfo } from './getEncodeAssetInfo'; import { isRegisteredOnChain } from '../registration'; import { validateChain } from '../helpers'; -import { getWithdrawalBalances } from './getWithdrawalBalance'; +import { getWithdrawalBalancesERC721 } from './getWithdrawalBalance'; interface MintableERC721Withdrawal { type: 'ERC721'; @@ -253,53 +252,48 @@ export async function completeERC721WithdrawalAction({ starkPublicKey, token, config, -}: CompleteERC721WithdrawalActionParams) { +}: CompleteERC721WithdrawalActionParams, mintsApi: MintsApi) { await validateChain(ethSigner, config.immutableXConfig); - - const mintsApi = new imx.MintsApi(config.immutableXConfig.apiConfiguration); - + const ethAddress = await ethSigner.getAddress(); const { v3Balance, v4Balance, - } = await getWithdrawalBalances( + } = await getWithdrawalBalancesERC721( ethSigner, starkPublicKey, - await ethSigner.getAddress(), + ethAddress, { type: ERC721TokenType, tokenAddress: token.tokenAddress, tokenId: token.tokenId, }, config.immutableXConfig, + mintsApi, ); - - if (v3Balance.isZero() && v4Balance.isZero()) { - throw new Error('No balance to withdraw'); + if (!v3Balance.isZero() && !v3Balance.isNegative()) { + const isRegistered = await isRegisteredOnChain( + starkPublicKey, + ethSigner, + config, + ); + // if the user is already registered on-chain, we can withdraw using stark key as the owner key + if (isRegistered) { + return completeERC721Withdrawal(mintsApi, ethSigner, starkPublicKey, token, config.immutableXConfig); + } + // if not registered on-chain, we need to register the user on-chain using stark public key as the owner key + return completeERC721RegisterAndWithdrawal( + mintsApi, + ethSigner, + starkSigner, + token, + config.immutableXConfig, + ); } - const ethAddress = await ethSigner.getAddress(); - // if v4 balance is NOT zero, the withdrawal was prepared using eth address (using v2/withdrawals API) - if (!v4Balance.isZero()) { + if (!v4Balance.isZero() && !v4Balance.isNegative()) { return completeERC721Withdrawal(mintsApi, ethSigner, ethAddress, token, config.immutableXConfig); } - const isRegistered = await isRegisteredOnChain( - starkPublicKey, - ethSigner, - config, - ); - - // if the user is already registered on-chain, we can withdraw using stark key as the owner key - if (isRegistered) { - return completeERC721Withdrawal(mintsApi, ethSigner, starkPublicKey, token, config.immutableXConfig); - } - // if not registered on-chain, we need to register the user on-chain using stark public key as the owner key - return completeERC721RegisterAndWithdrawal( - mintsApi, - ethSigner, - starkSigner, - token, - config.immutableXConfig, - ); + throw new Error('No balance to withdraw'); } diff --git a/packages/x-provider/src/signable-actions/withdrawal-actions/completeEthWithdrawal.ts b/packages/x-provider/src/signable-actions/withdrawal-actions/completeEthWithdrawal.ts index f87e17702d..59e89687b9 100644 --- a/packages/x-provider/src/signable-actions/withdrawal-actions/completeEthWithdrawal.ts +++ b/packages/x-provider/src/signable-actions/withdrawal-actions/completeEthWithdrawal.ts @@ -1,13 +1,18 @@ import { Signer } from '@ethersproject/abstract-signer'; import { TransactionResponse } from '@ethersproject/providers'; import { - Contracts, ImmutableXConfiguration, signRegisterEthAddress, StarkSigner, + StarkSigner, } from '@imtbl/x-client'; import { ProviderConfiguration } from '../../config'; import { isRegisteredOnChain } from '../registration'; import { getEncodeAssetInfo } from './getEncodeAssetInfo'; import { validateChain } from '../helpers'; import { getWithdrawalBalances } from './getWithdrawalBalance'; +import { + executeRegisterAndWithdrawAllFungible, + executeWithdrawAllFungible, + executeWithdrawFungible, +} from './completeERC20Withdrawal'; type CompleteEthWithdrawalActionParams = { ethSigner: Signer; @@ -18,62 +23,6 @@ type CompleteEthWithdrawalActionParams = { const EthTokenType = 'ETH'; -// works with ETH or ERC20 -export async function executeRegisterAndWithdrawAllFungible( - ethSigner: Signer, - starkSigner: StarkSigner, - starkPublicKey: string, - assetType: string, - config: ImmutableXConfiguration, -): Promise { - const etherKey = await ethSigner.getAddress(); - - const starkSignature = await signRegisterEthAddress( - starkSigner, - etherKey, - starkPublicKey, - ); - - // we use registration v4 contract as a wrapper for the core contract - // so that v3 and v4 withdrawals, AND on-chain registration can be executed in a single transaction - const contract = Contracts.RegistrationV4.connect( - config.ethConfiguration.registrationV4ContractAddress || config.ethConfiguration.registrationContractAddress, - ethSigner, - ); - - const populatedTransaction = await contract.populateTransaction.registerAndWithdrawAll( - etherKey, - starkPublicKey, - starkSignature, - assetType, - ); - - return ethSigner.sendTransaction(populatedTransaction); -} - -export async function executeWithdrawAllFungible( - ethSigner: Signer, - starkPublicKey: string, - assetType: string, - config: ImmutableXConfiguration, -): Promise { - // we use registration v4 contract as a wrapper for the core contract - // so that v3 and v4 withdrawals can be executed in a single transaction - // (if there are pending withdrawable funds for both) - const contract = Contracts.RegistrationV4.connect( - config.ethConfiguration.registrationV4ContractAddress || config.ethConfiguration.registrationContractAddress, - ethSigner, - ); - - const populatedTransaction = await contract.populateTransaction.withdrawAll( - await ethSigner.getAddress(), - starkPublicKey, - assetType, - ); - - return ethSigner.sendTransaction(populatedTransaction); -} - export async function completeEthWithdrawalAction({ ethSigner, starkSigner, @@ -94,26 +43,27 @@ export async function completeEthWithdrawalAction({ config.immutableXConfig, ); - if (v3Balance.isZero() && v4Balance.isZero()) { - throw new Error('No balance to withdraw'); - } - - const isRegistered = await isRegisteredOnChain( - starkPublicKey, - ethSigner, - config, - ); - const assetType = await getEncodeAssetInfo('asset', EthTokenType, config.immutableXConfig); - if (isRegistered) { - return executeWithdrawAllFungible(ethSigner, starkPublicKey, assetType.asset_type, config.immutableXConfig); + if (!v3Balance.isZero() && !v3Balance.isNegative()) { + const isRegistered = await isRegisteredOnChain( + starkPublicKey, + ethSigner, + config, + ); + if (isRegistered) { + return executeWithdrawAllFungible(ethSigner, starkPublicKey, assetType.asset_type, config.immutableXConfig); + } + return executeRegisterAndWithdrawAllFungible( + ethSigner, + starkSigner, + starkPublicKey, + assetType.asset_type, + config.immutableXConfig, + ); } - return executeRegisterAndWithdrawAllFungible( - ethSigner, - starkSigner, - starkPublicKey, - assetType.asset_type, - config.immutableXConfig, - ); + if (!v4Balance.isZero() && !v4Balance.isNegative()) { + return executeWithdrawFungible(ethSigner, starkPublicKey, assetType.asset_type, config.immutableXConfig); + } + throw new Error('No balance to withdraw'); } diff --git a/packages/x-provider/src/signable-actions/withdrawal-actions/getWithdrawalBalance.ts b/packages/x-provider/src/signable-actions/withdrawal-actions/getWithdrawalBalance.ts index cb8cb4c105..55e2a8f47e 100644 --- a/packages/x-provider/src/signable-actions/withdrawal-actions/getWithdrawalBalance.ts +++ b/packages/x-provider/src/signable-actions/withdrawal-actions/getWithdrawalBalance.ts @@ -63,6 +63,7 @@ async function getERC721WithdrawalBalance( tokenAddress: token.tokenAddress, tokenId: token.tokenId, }); + const assetType = await getEncodeAssetInfo( 'mintable-asset', 'ERC721', @@ -81,26 +82,26 @@ async function getERC721WithdrawalBalance( assetType.asset_id, config, ); - } catch (e: any) { - if (!e.response || !(e.response && e.response.status !== 404)) { - throw e; + } catch (error: any) { + if (error.response?.status === 404) { + // token is not a mintable ERC721 token + const assetType = await getEncodeAssetInfo( + 'asset', + 'ERC721', + config, + { + token_id: token.tokenId, + token_address: token.tokenAddress, + }, + ); + return await getWithdrawalBalance( + signer, + ownerKey, + assetType.asset_id, + config, + ); } - // token is not a mintable ERC721 token - const assetType = await getEncodeAssetInfo( - 'asset', - 'ERC721', - config, - { - token_id: token.tokenId, - token_address: token.tokenAddress, - }, - ); - return await getWithdrawalBalance( - signer, - ownerKey, - assetType.asset_id, - config, - ); + throw error; // unable to recover from any other kind of error } } @@ -171,3 +172,37 @@ export async function getWithdrawalBalances( v4Balance, }; } + +export async function getWithdrawalBalancesERC721( + signer: Signer, + starkPublicKey: string, + ethAddress: string, + token: AnyToken, + config: ImmutableXConfiguration, + mintsApi: MintsApi, +): Promise<{ v3Balance: BigNumber; v4Balance: BigNumber }> { + const encodingApi = new EncodingApi(config.apiConfiguration); + + const v3Balance = await getWithdrawalBalanceWorkflow( + signer, + starkPublicKey, + token, + encodingApi, + mintsApi, + config, + ); + + const v4Balance = await getWithdrawalBalanceWorkflow( + signer, + ethAddress, + token, + encodingApi, + mintsApi, + config, + ); + + return { + v3Balance, + v4Balance, + }; +} diff --git a/packages/x-provider/src/signable-actions/withdrawal-actions/prepareWithdrawal.test.ts b/packages/x-provider/src/signable-actions/withdrawal-actions/prepareWithdrawal.test.ts index 39d98b3d76..e184a97246 100644 --- a/packages/x-provider/src/signable-actions/withdrawal-actions/prepareWithdrawal.test.ts +++ b/packages/x-provider/src/signable-actions/withdrawal-actions/prepareWithdrawal.test.ts @@ -13,15 +13,20 @@ describe('prepareWithdrawal', () => { describe('prepareWithdrawal action', () => { let getSignableWithdrawalMock: jest.Mock; let createWithdrawalMock: jest.Mock; - const getSignableWithdrawalResponse: imx.GetSignableWithdrawalResponse = { - signable_message: 'hello', - payload_hash: 'hash', - nonce: 0, - stark_key: '0x10c', - vault_id: 123, - amount: '1', + + const getSignableWithdrawalResponse: imx.GetSignableWithdrawalResponseV2 = { + sender_stark_key: '0x10c', + sender_vault_id: 123, + receiver_stark_key: '0xabc', + receiver_vault_id: 0, asset_id: '22', + amount: '1', + quantized_amount: '1', + expiration_timestamp: 999, + nonce: 0, + payload_hash: 'hash', readable_transaction: '', + signable_message: 'hello', verification_signature: '', }; const createWithdrawalResponse: imx.CreateWithdrawalResponse = { @@ -41,8 +46,8 @@ describe('prepareWithdrawal', () => { }); (imx.WithdrawalsApi as jest.Mock).mockReturnValue({ - getSignableWithdrawal: getSignableWithdrawalMock, - createWithdrawal: createWithdrawalMock, + getSignableWithdrawalV2: getSignableWithdrawalMock, + createWithdrawalV2: createWithdrawalMock, }); }); @@ -63,7 +68,8 @@ describe('prepareWithdrawal', () => { tokenId: '1', tokenAddress: 'asd', }; - const resposne = await prepareWithdrawalAction(request); + const withdrawalsApi = new imx.WithdrawalsApi(testConfig.immutableXConfig.apiConfiguration); + const resposne = await prepareWithdrawalAction(request, withdrawalsApi); expect(resposne).toEqual(createWithdrawalResponse); expect(getSignableWithdrawalMock).toHaveBeenCalledWith({ @@ -74,14 +80,17 @@ describe('prepareWithdrawal', () => { }, }); expect(createWithdrawalMock).toHaveBeenCalledWith({ - createWithdrawalRequest: { - stark_key: getSignableWithdrawalResponse.stark_key, + createWithdrawalRequestV2: { + sender_stark_key: getSignableWithdrawalResponse.sender_stark_key, + sender_vault_id: getSignableWithdrawalResponse.sender_vault_id, + receiver_stark_key: getSignableWithdrawalResponse.receiver_stark_key, + receiver_vault_id: getSignableWithdrawalResponse.receiver_vault_id, amount: '1', asset_id: getSignableWithdrawalResponse.asset_id, - vault_id: getSignableWithdrawalResponse.vault_id, nonce: getSignableWithdrawalResponse.nonce, stark_signature: `${getSignableWithdrawalResponse.payload_hash}STX${privateKey1}`, + expiration_timestamp: getSignableWithdrawalResponse.expiration_timestamp, }, xImxEthAddress: ethKey, xImxEthSignature: 'raw-eth-signature', @@ -105,7 +114,8 @@ describe('prepareWithdrawal', () => { amount: '1.02', tokenAddress: 'asd', }; - const resposne = await prepareWithdrawalAction(request); + const withdrawalsApi = new imx.WithdrawalsApi(testConfig.immutableXConfig.apiConfiguration); + const resposne = await prepareWithdrawalAction(request, withdrawalsApi); expect(resposne).toEqual(createWithdrawalResponse); expect(getSignableWithdrawalMock).toHaveBeenCalledWith({ @@ -116,14 +126,17 @@ describe('prepareWithdrawal', () => { }, }); expect(createWithdrawalMock).toHaveBeenCalledWith({ - createWithdrawalRequest: { - stark_key: getSignableWithdrawalResponse.stark_key, + createWithdrawalRequestV2: { + sender_stark_key: getSignableWithdrawalResponse.sender_stark_key, + sender_vault_id: getSignableWithdrawalResponse.sender_vault_id, + receiver_stark_key: getSignableWithdrawalResponse.receiver_stark_key, + receiver_vault_id: getSignableWithdrawalResponse.receiver_vault_id, amount: request.amount, asset_id: getSignableWithdrawalResponse.asset_id, - vault_id: getSignableWithdrawalResponse.vault_id, nonce: getSignableWithdrawalResponse.nonce, stark_signature: `${getSignableWithdrawalResponse.payload_hash}STX${privateKey1}`, + expiration_timestamp: getSignableWithdrawalResponse.expiration_timestamp, }, xImxEthAddress: ethKey, xImxEthSignature: 'raw-eth-signature', diff --git a/packages/x-provider/src/signable-actions/withdrawal-actions/prepareWithdrawal.ts b/packages/x-provider/src/signable-actions/withdrawal-actions/prepareWithdrawal.ts index 65fd234103..4d4793bccd 100644 --- a/packages/x-provider/src/signable-actions/withdrawal-actions/prepareWithdrawal.ts +++ b/packages/x-provider/src/signable-actions/withdrawal-actions/prepareWithdrawal.ts @@ -19,57 +19,12 @@ export type PrepareWithdrawalWorkflowParams = TokenAmount & { export async function prepareWithdrawalAction( params: PrepareWithdrawalWorkflowParams, + withdrawalsApi: imx.WithdrawalsApi, ): Promise { const { signers: { ethSigner, starkSigner }, - type, - config, } = params; await validateChain(ethSigner, params.config); - const withdrawalsApi = new imx.WithdrawalsApi(config.apiConfiguration); - const withdrawalAmount = type === 'ERC721' ? '1' : params.amount; - const signableWithdrawalResult = await withdrawalsApi.getSignableWithdrawal({ - getSignableWithdrawalRequest: { - user: await ethSigner.getAddress(), - token: convertToSignableToken(params), - amount: withdrawalAmount, - }, - }); - - const { signable_message: signableMessage, payload_hash: payloadHash } = signableWithdrawalResult.data; - - const starkSignature = await starkSigner.signMessage(payloadHash); - - const { ethAddress, ethSignature } = await signMessage( - signableMessage, - ethSigner, - ); - - const prepareWithdrawalResponse = await withdrawalsApi.createWithdrawal({ - createWithdrawalRequest: { - stark_key: assertIsDefined(signableWithdrawalResult.data.stark_key), - amount: withdrawalAmount, - asset_id: assertIsDefined(signableWithdrawalResult.data.asset_id), - vault_id: assertIsDefined(signableWithdrawalResult.data.vault_id), - nonce: assertIsDefined(signableWithdrawalResult.data.nonce), - stark_signature: starkSignature, - }, - xImxEthAddress: ethAddress, - xImxEthSignature: ethSignature, - }); - - return prepareWithdrawalResponse.data; -} - -export async function prepareWithdrawalV2Action( - params: PrepareWithdrawalWorkflowParams, -): Promise { - const { - signers: { ethSigner, starkSigner }, - config, - } = params; - await validateChain(ethSigner, params.config); - const withdrawalsApi = new imx.WithdrawalsApi(config.apiConfiguration); const withdrawalAmount = params.type === 'ERC721' ? '1' : params.amount; const signableWithdrawalResult = await withdrawalsApi.getSignableWithdrawalV2( { diff --git a/packages/x-provider/src/signable-actions/withdrawal.ts b/packages/x-provider/src/signable-actions/withdrawal.ts index a948576b4c..dd33bf5c71 100644 --- a/packages/x-provider/src/signable-actions/withdrawal.ts +++ b/packages/x-provider/src/signable-actions/withdrawal.ts @@ -1,3 +1,4 @@ +import { imx } from '@imtbl/generated-clients'; import { AnyToken, TokenAmount } from '@imtbl/x-client'; import { ProviderConfiguration } from '../config'; import { Signers } from './types'; @@ -5,7 +6,7 @@ import { completeEthWithdrawalAction, completeERC20WithdrawalAction, completeERC721WithdrawalAction, - prepareWithdrawalV2Action, + prepareWithdrawalAction, } from './withdrawal-actions'; type CompleteWithdrawalParams = { @@ -26,11 +27,12 @@ export async function prepareWithdrawal({ withdrawal, config, }: PrepareWithdrawalParams) { - return prepareWithdrawalV2Action({ + const withdrawalsApi = new imx.WithdrawalsApi(config.immutableXConfig.apiConfiguration); + return prepareWithdrawalAction({ signers, config: config.immutableXConfig, ...withdrawal, - }); + }, withdrawalsApi); } // TODO: remove once fixed @@ -41,6 +43,8 @@ export async function completeWithdrawal({ token, config, }: CompleteWithdrawalParams) { + const mintsApi = new imx.MintsApi(config.immutableXConfig.apiConfiguration); + // eslint-disable-next-line default-case switch (token.type) { case 'ETH': @@ -62,6 +66,6 @@ export async function completeWithdrawal({ starkPublicKey, token, config, - }); + }, mintsApi); } }