Skip to content
This repository has been archived by the owner on May 16, 2024. It is now read-only.

Commit

Permalink
CORE-2034 add register and complete withdraw workflow (#438)
Browse files Browse the repository at this point in the history
* add register and complete withdraw workflow

* changelog and version
  • Loading branch information
kaihirota authored Feb 28, 2024
1 parent aa22f69 commit 7b33e2d
Show file tree
Hide file tree
Showing 8 changed files with 267 additions and 7 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## [3.5.0] - 2024-02-28

### Added

- Update `completeWithdrawal`:
- If the user has only v4 balance, `completeWithdrawal` will withdraw v4 balance.
- If the user has v3 balance, `completeWithdrawal` will try to withdraw both v3 and v4 balance.
- If the user has v3 balance, and is not registered on-chain, `completeWithdrawal` will try to register the user and then withdraw both v3 and v4 balance.
- If the v3 balance is not zero for an NFT, `completeWithdrawal` will only try to withdraw v3 balance.
- v3 balance refers to withdrawal prepared using /v1/withdrawal API.
- v4 balance refers to withdrawal prepared using /v2/withdrawal API.

## [3.4.0] - 2024-02-27

### Added
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@imtbl/core-sdk",
"version": "3.4.0",
"version": "3.5.0",
"description": "Immutable Core SDK",
"main": "dist/index.cjs.js",
"module": "dist/index.es.js",
Expand Down
37 changes: 36 additions & 1 deletion src/workflows/withdrawal/completeERC20Withdrawal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import {
Registration__factory,
RegistrationV4__factory,
} from '../../contracts';
import { ERC20Token } from '../../types';
import { ERC20Token, WalletConnection } from '../../types';
import {
getSignableRegistrationOnchain,
isRegisteredOnChainWorkflow,
signRegisterEthAddress,
} from '../registration';
import { getEncodeAssetInfo } from './getEncodeAssetInfo';

Expand Down Expand Up @@ -153,3 +154,37 @@ export async function completeAllERC20WithdrawalWorkflow(

return signer.sendTransaction(populatedTransaction);
}

export async function registerAndCompleteAllERC20WithdrawalWorkflow(
walletConnection: WalletConnection,
ethAddress: string,
starkPublicKey: string,
token: ERC20Token,
encodingApi: EncodingApi,
config: ImmutableXConfiguration,
): Promise<TransactionResponse> {
const assetType = await getEncodeAssetInfo('asset', 'ERC20', encodingApi, {
token_address: token.tokenAddress,
});

const registrationContract = RegistrationV4__factory.connect(
config.ethConfiguration.registrationContractAddress,
walletConnection.ethSigner,
);

const starkSignature = await signRegisterEthAddress(
walletConnection.starkSigner,
ethAddress,
starkPublicKey,
);

const populatedTransaction =
await registrationContract.populateTransaction.registerAndWithdrawAll(
ethAddress,
starkPublicKey,
starkSignature,
assetType.asset_id,
);

return walletConnection.ethSigner.sendTransaction(populatedTransaction);
}
129 changes: 127 additions & 2 deletions src/workflows/withdrawal/completeERC721Withdrawal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@ import { EncodingApi, MintsApi, UsersApi } from '../../api';
import {
Core,
Core__factory,
CoreV4__factory,
Registration,
Registration__factory,
CoreV4__factory,
RegistrationV4__factory,
} from '../../contracts';
import * as encUtils from 'enc-utils';
import { ERC721Token } from '../../types';
import { ERC721Token, WalletConnection } from '../../types';
import { getEncodeAssetInfo } from './getEncodeAssetInfo';
import {
getSignableRegistrationOnchain,
isRegisteredOnChainWorkflow,
signRegisterEthAddress,
} from '../registration';
import { TransactionResponse } from '@ethersproject/providers';
import { ImmutableXConfiguration } from '../../config';
Expand Down Expand Up @@ -330,6 +332,72 @@ async function completeERC721WithdrawalV2(
return signer.sendTransaction(populatedTransaction);
}

async function registerAndCompleteMintableERC721WithdrawalV2(
signer: Signer,
ethAddress: string,
starkPublicKey: string,
starkSignature: string,
token: MintableERC721Withdrawal,
encodingApi: EncodingApi,
config: ImmutableXConfiguration,
) {
const assetType = await getEncodeAssetInfo(
'mintable-asset',
'ERC721',
encodingApi,
{
id: token.data.id,
token_address: token.data.tokenAddress,
...(token.data.blueprint && { blueprint: token.data.blueprint }),
},
);
const mintingBlob = getMintingBlob(token);
const contract = RegistrationV4__factory.connect(
config.ethConfiguration.registrationContractAddress,
signer,
);

const populatedTransaction =
await contract.populateTransaction.registerWithdrawAndMint(
ethAddress,
starkPublicKey,
starkSignature,
assetType.asset_type,
mintingBlob,
);
return signer.sendTransaction(populatedTransaction);
}

async function registerAndCompleteERC721WithdrawalV2(
signer: Signer,
ethAddress: string,
starkPublicKey: string,
starkSignature: string,
token: ERC721Token,
encodingApi: EncodingApi,
config: ImmutableXConfiguration,
) {
const assetType = await getEncodeAssetInfo('asset', 'ERC721', encodingApi, {
token_id: token.tokenId,
token_address: token.tokenAddress,
});

const contract = RegistrationV4__factory.connect(
config.ethConfiguration.registrationContractAddress,
signer,
);

const populatedTransaction =
await contract.populateTransaction.registerAndWithdrawNft(
ethAddress,
starkPublicKey,
starkSignature,
assetType.asset_type,
token.tokenId,
);
return signer.sendTransaction(populatedTransaction);
}

export async function completeERC721WithdrawalV2Workflow(
signer: Signer,
ownerKey: string,
Expand Down Expand Up @@ -375,3 +443,60 @@ export async function completeERC721WithdrawalV2Workflow(
throw error; // unable to recover from any other kind of error
});
}

export async function registerAndCompleteERC721WithdrawalWorkflow(
walletConnection: WalletConnection,
ethAddress: string,
starkPublicKey: string,
token: ERC721Token,
encodingApi: EncodingApi,
mintsApi: MintsApi,
config: ImmutableXConfiguration,
): Promise<TransactionResponse> {
const starkSignature = await signRegisterEthAddress(
walletConnection.starkSigner,
ethAddress,
starkPublicKey,
);
const tokenAddress = token.tokenAddress;
const tokenId = token.tokenId;

return await mintsApi
.getMintableTokenDetailsByClientTokenId({
tokenAddress,
tokenId,
})
.then(async mintableToken =>
registerAndCompleteMintableERC721WithdrawalV2(
walletConnection.ethSigner,
ethAddress,
starkPublicKey,
starkSignature,
{
type: 'ERC721',
data: {
id: tokenId,
tokenAddress: tokenAddress,
blueprint: mintableToken.data.blueprint,
},
},
encodingApi,
config,
),
)
.catch(error => {
if (error.response?.status === 404) {
// token is already minted on L1
return registerAndCompleteERC721WithdrawalV2(
walletConnection.ethSigner,
ethAddress,
starkPublicKey,
starkSignature,
token,
encodingApi,
config,
);
}
throw error; // unable to recover from any other kind of error
});
}
33 changes: 33 additions & 0 deletions src/workflows/withdrawal/completeEthWithdrawal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ import {
import {
getSignableRegistrationOnchain,
isRegisteredOnChainWorkflow,
signRegisterEthAddress,
} from '../registration';
import { getEncodeAssetInfo } from './getEncodeAssetInfo';
import { WalletConnection } from 'src/types';

async function executeRegisterAndWithdrawEth(
signer: Signer,
Expand Down Expand Up @@ -143,3 +145,34 @@ export async function completeAllEthWithdrawalWorkflow(

return signer.sendTransaction(populatedTransaction);
}

export async function registerAndCompleteAllEthWithdrawalWorkflow(
walletConnection: WalletConnection,
ethAddress: string,
starkPublicKey: string,
encodingApi: EncodingApi,
config: ImmutableXConfiguration,
): Promise<TransactionResponse> {
const assetType = await getEncodeAssetInfo('asset', 'ETH', encodingApi);

const registrationContract = RegistrationV4__factory.connect(
config.ethConfiguration.registrationContractAddress,
walletConnection.ethSigner,
);

const starkSignature = await signRegisterEthAddress(
walletConnection.starkSigner,
ethAddress,
starkPublicKey,
);

const populatedTransaction =
await registrationContract.populateTransaction.registerAndWithdrawAll(
ethAddress,
starkPublicKey,
starkSignature,
assetType.asset_id,
);

return walletConnection.ethSigner.sendTransaction(populatedTransaction);
}
46 changes: 45 additions & 1 deletion src/workflows/withdrawal/completeWithdrawal.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import { Signer } from '@ethersproject/abstract-signer';
import { TransactionResponse } from '@ethersproject/providers';
import { AnyToken } from 'src/types';
import { AnyToken, WalletConnection } from 'src/types';
import { EncodingApi, MintsApi, UsersApi } from 'src/api';
import { ImmutableXConfiguration } from 'src/config';
import {
completeAllEthWithdrawalWorkflow,
completeEthWithdrawalV1Workflow,
completeEthWithdrawalV2Workflow,
registerAndCompleteAllEthWithdrawalWorkflow,
} from './completeEthWithdrawal';
import {
completeAllERC20WithdrawalWorkflow,
completeERC20WithdrawalV1Workflow,
completeERC20WithdrawalV2Workflow,
registerAndCompleteAllERC20WithdrawalWorkflow,
} from './completeERC20Withdrawal';
import {
completeERC721WithdrawalV1Workflow,
completeERC721WithdrawalV2Workflow,
registerAndCompleteERC721WithdrawalWorkflow,
} from './completeERC721Withdrawal';

export async function completeWithdrawalV1Workflow(
Expand Down Expand Up @@ -124,3 +127,44 @@ export async function completeAllWithdrawalWorkflow(
);
}
}

export async function registerAndCompleteAllWithdrawalWorkflow(
walletConnection: WalletConnection,
ethAddress: string,
starkPublicKey: string,
token: AnyToken,
encodingApi: EncodingApi,
mintsApi: MintsApi,
config: ImmutableXConfiguration,
): Promise<TransactionResponse> {
switch (token.type) {
case 'ETH':
return registerAndCompleteAllEthWithdrawalWorkflow(
walletConnection,
ethAddress,
starkPublicKey,
encodingApi,
config,
);
case 'ERC20':
return registerAndCompleteAllERC20WithdrawalWorkflow(
walletConnection,
ethAddress,
starkPublicKey,
token,
encodingApi,
config,
);
case 'ERC721':
// for ERC721, if the v3 balance > 0, then the v4 balance is 0
return registerAndCompleteERC721WithdrawalWorkflow(
walletConnection,
ethAddress,
starkPublicKey,
token,
encodingApi,
mintsApi,
config,
);
}
}
2 changes: 2 additions & 0 deletions src/workflows/withdrawal/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export * from './prepareWithdrawal';
export * from './completeWithdrawal';
export * from './completeERC20Withdrawal';
export * from './completeERC721Withdrawal';
export * from './completeEthWithdrawal';
export * from './getWithdrawalBalance';
12 changes: 10 additions & 2 deletions src/workflows/workflows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ import {
completeAllWithdrawalWorkflow,
completeWithdrawalV1Workflow,
completeWithdrawalV2Workflow,
registerAndCompleteAllWithdrawalWorkflow,
} from './withdrawal/completeWithdrawal';
import { BigNumber } from 'ethers';
import { getWithdrawalBalanceWorkflow } from './withdrawal/getWithdrawalBalance';
Expand Down Expand Up @@ -311,7 +312,6 @@ export class Workflows {
const starkPublicKey = await walletConnection.starkSigner.getAddress();

if (majorContractVersion === 3) {
const starkPublicKey = await walletConnection.starkSigner.getAddress();
return completeWithdrawalV1Workflow(
walletConnection.ethSigner,
starkPublicKey,
Expand Down Expand Up @@ -359,7 +359,15 @@ export class Workflows {
this.config,
);
}
throw new Error('User unregistered');
return registerAndCompleteAllWithdrawalWorkflow(
walletConnection,
ethAddress,
starkPublicKey,
token,
this.encodingApi,
this.mintsApi,
this.config,
);
}
if (v4Balance.gt(0)) {
return completeWithdrawalV2Workflow(
Expand Down

0 comments on commit 7b33e2d

Please sign in to comment.