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

[WT-969] V2 Workflows for ImmutableProvider #263

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29,502 changes: 29,502 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
"release": "release-it",
"typecheck": "tsc --noEmit",
"typecheck-staged": "tsc-files --noEmit",
"lint": "eslint ./src/utils/*.ts ./src/workflows/*.ts ./src/types/*.ts ./src/config/*.ts ./examples/*.ts --max-warnings=0",
"lint-fix": "eslint ./src/utils/*.ts ./src/workflows/*.ts ./src/types/*.ts ./src/config/*.ts ./examples/*.ts --fix --max-warnings=0",
"lint": "eslint ./src/utils/*.ts ./src/workflows/*.ts ./src/types/*.ts ./src/config/*.ts ./examples/*.ts ./src/workflows_v2/** --max-warnings=0",
"lint-fix": "eslint ./src/utils/*.ts ./src/workflows/*.ts ./src/types/*.ts ./src/config/*.ts ./examples/*.ts ./src/workflows_v2/** --fix --max-warnings=0",
"prepare": "husky install",
"docs:build": "yarn typedoc --cleanOutputDir ./src/ImmutableX.ts ./src/index.ts --excludePrivate --excludeProtected",
"docs:serve": "http-server -c-1 ./docs"
Expand Down Expand Up @@ -63,7 +63,7 @@
"@types/jest": "^27.4.1",
"@typescript-eslint/eslint-plugin": "^5.20.0",
"@typescript-eslint/parser": "^5.20.0",
"babel-jest": "^27.5.1",
"babel-jest": "^28.0.0",
"dts-bundle-generator": "^6.12.0",
"eslint": "^8.13.0",
"eslint-config-prettier": "^8.5.0",
Expand All @@ -90,6 +90,7 @@
"@ethersproject/bytes": "^5.0.0",
"@ethersproject/providers": "^5.0.0",
"@imtbl/core-sdk": "^1.0.0",
"@imtbl/provider-sdk-web": "^0.0.10",
"axios": "^0.26.1",
"bn.js": "^5.2.0",
"elliptic": "^6.5.4",
Expand Down
12 changes: 12 additions & 0 deletions src/api/models/get-signable-cancel-order-response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,17 @@ export interface GetSignableCancelOrderResponse {
* @memberof GetSignableCancelOrderResponse
*/
'signable_message': string;
/**
* An EIP-712 encoded JSON payload that represents the transaction
* @type {string}
* @memberof GetSignableCancelOrderResponse
*/
'readable_transaction': string;
/**
* A signature that can be used to verify that the readable_transaction and payload_hash match
* @type {string}
* @memberof GetSignableCancelOrderResponse
*/
'verification_signature': string;
}

12 changes: 12 additions & 0 deletions src/api/models/get-signable-order-response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,17 @@ export interface GetSignableOrderResponse {
* @memberof GetSignableOrderResponse
*/
'vault_id_sell': number;
/**
* An EIP-712 encoded JSON payload that represents the transaction
* @type {string}
* @memberof GetSignableCancelOrderResponse
*/
'readable_transaction': string;
/**
* A signature that can be used to verify that the readable_transaction and payload_hash match
* @type {string}
* @memberof GetSignableCancelOrderResponse
*/
'verification_signature': string;
}

12 changes: 12 additions & 0 deletions src/api/models/get-signable-registration-offchain-response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,17 @@ export interface GetSignableRegistrationOffchainResponse {
* @memberof GetSignableRegistrationOffchainResponse
*/
'signable_message': string;
/**
* An EIP-712 encoded JSON payload that represents the transaction
* @type {string}
* @memberof GetSignableCancelOrderResponse
*/
'readable_transaction': string;
/**
* A signature that can be used to verify that the readable_transaction and payload_hash match
* @type {string}
* @memberof GetSignableCancelOrderResponse
*/
'verification_signature': string;
}

12 changes: 12 additions & 0 deletions src/api/models/get-signable-trade-response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,17 @@ export interface GetSignableTradeResponse {
* @memberof GetSignableTradeResponse
*/
'vault_id_sell': number;
/**
* An EIP-712 encoded JSON payload that represents the transaction
* @type {string}
* @memberof GetSignableCancelOrderResponse
*/
'readable_transaction': string;
/**
* A signature that can be used to verify that the readable_transaction and payload_hash match
* @type {string}
* @memberof GetSignableCancelOrderResponse
*/
'verification_signature': string;
}

12 changes: 12 additions & 0 deletions src/api/models/get-signable-transfer-response-v1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,17 @@ export interface GetSignableTransferResponseV1 {
* @memberof GetSignableTransferResponseV1
*/
'signable_message': string;
/**
* An EIP-712 encoded JSON payload that represents the transaction
* @type {string}
* @memberof GetSignableCancelOrderResponse
*/
'readable_transaction': string;
/**
* A signature that can be used to verify that the readable_transaction and payload_hash match
* @type {string}
* @memberof GetSignableCancelOrderResponse
*/
'verification_signature': string;
}

12 changes: 12 additions & 0 deletions src/api/models/get-signable-transfer-response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,17 @@ export interface GetSignableTransferResponse {
* @memberof GetSignableTransferResponse
*/
'signable_responses': Array<SignableTransferResponseDetails>;
/**
* An EIP-712 encoded JSON payload that represents the transaction
* @type {string}
* @memberof GetSignableCancelOrderResponse
*/
'readable_transaction': string;
/**
* A signature that can be used to verify that the readable_transaction and payload_hash match
* @type {string}
* @memberof GetSignableCancelOrderResponse
*/
'verification_signature': string;
}

12 changes: 12 additions & 0 deletions src/api/models/get-signable-withdrawal-response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,17 @@ export interface GetSignableWithdrawalResponse {
* @memberof GetSignableWithdrawalResponse
*/
'vault_id': number;
/**
* An EIP-712 encoded JSON payload that represents the transaction
* @type {string}
* @memberof GetSignableCancelOrderResponse
*/
'readable_transaction': string;
/**
* A signature that can be used to verify that the readable_transaction and payload_hash match
* @type {string}
* @memberof GetSignableCancelOrderResponse
*/
'verification_signature': string;
}

12 changes: 12 additions & 0 deletions src/api/models/signable-transfer-response-details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,17 @@ export interface SignableTransferResponseDetails {
* @memberof SignableTransferResponseDetails
*/
'token': SignableToken;
/**
* An EIP-712 encoded JSON payload that represents the transaction
* @type {string}
* @memberof GetSignableCancelOrderResponse
*/
'readable_transaction': string;
/**
* A signature that can be used to verify that the readable_transaction and payload_hash match
* @type {string}
* @memberof GetSignableCancelOrderResponse
*/
'verification_signature': string;
}

12 changes: 12 additions & 0 deletions src/types/signers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Signer as EthSigner } from '@ethersproject/abstract-signer';
import { StarkExSigner } from '@imtbl/provider-sdk-web';

export { EthSigner };

Expand Down Expand Up @@ -33,3 +34,14 @@ export interface WalletConnection {
*/
starkSigner: StarkSigner;
}

export interface ResolvedSigners {
/**
* The L1 signer
*/
ethSigner: EthSigner;
/**
* The L2 signer
*/
starkExSigner: StarkExSigner;
}
168 changes: 168 additions & 0 deletions src/workflows_v2/deposit/depositERC20.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import { Signer } from '@ethersproject/abstract-signer';
import { TransactionResponse } from '@ethersproject/providers';
import { DepositsApi, EncodingApi, TokensApi, UsersApi } from '../../api';
import { parseUnits } from '@ethersproject/units';
import {
Core,
Core__factory,
IERC20__factory,
Registration__factory,
} from '../../contracts';
import {
getSignableRegistrationOnchain,
isRegisteredOnChainWorkflow,
} from '../registration';
import { ERC20Amount } from '../../types';
import { BigNumber } from '@ethersproject/bignumber';
import { ImmutableXConfiguration } from '../../config';

interface ERC20TokenData {
decimals: number;
token_address: string;
}

async function executeDepositERC20(
signer: Signer,
quantizedAmount: BigNumber,
assetType: string,
starkPublicKey: string,
vaultId: number,
contract: Core,
): Promise<TransactionResponse> {
const populatedTransaction = await contract.populateTransaction.depositERC20(
starkPublicKey,
assetType,
vaultId,
quantizedAmount,
);

return signer.sendTransaction(populatedTransaction);
}

async function executeRegisterAndDepositERC20(
signer: Signer,
quantizedAmount: BigNumber,
assetType: string,
starkPublicKey: string,
vaultId: number,
contract: Core,
usersApi: UsersApi,
): Promise<TransactionResponse> {
const etherKey = await signer.getAddress();

const signableResult = await getSignableRegistrationOnchain(
etherKey,
starkPublicKey,
usersApi,
);

const populatedTransaction =
await contract.populateTransaction.registerAndDepositERC20(
etherKey,
starkPublicKey,
signableResult.operator_signature,
assetType,
vaultId,
quantizedAmount,
);

return signer.sendTransaction(populatedTransaction);
}

export async function depositERC20Workflow(
signer: Signer,
deposit: ERC20Amount,
depositsApi: DepositsApi,
usersApi: UsersApi,
tokensApi: TokensApi,
encodingApi: EncodingApi,
config: ImmutableXConfiguration,
): Promise<TransactionResponse> {
const user = await signer.getAddress();

// Get decimals for this specific ERC20
const token = await tokensApi.getToken({ address: deposit.tokenAddress });
const decimals = parseInt(token.data.decimals);

const data: ERC20TokenData = {
decimals,
token_address: deposit.tokenAddress,
};

const amount = parseUnits(deposit.amount, 0); // 0 to always use undecimalized value

// Approve whether an amount of token from an account can be spent by a third-party account
const tokenContract = IERC20__factory.connect(deposit.tokenAddress, signer);
const approveTransaction = await tokenContract.populateTransaction.approve(
config.ethConfiguration.coreContractAddress,
amount,
);
await signer.sendTransaction(approveTransaction);

const getSignableDepositRequest = {
user,
token: {
type: deposit.type,
data,
},
amount: amount.toString(),
};

const signableDepositResult = await depositsApi.getSignableDeposit({
getSignableDepositRequest,
});

// Perform encoding on asset details to get an assetType (required for stark contract request)
const encodingResult = await encodingApi.encodeAsset({
assetType: 'asset',
encodeAssetRequest: {
token: {
type: deposit.type,
data: {
token_address: deposit.tokenAddress,
},
},
},
});

const assetType = encodingResult.data.asset_type;
const starkPublicKey = signableDepositResult.data.stark_key;
const vaultId = signableDepositResult.data.vault_id;
const quantizedAmount = BigNumber.from(signableDepositResult.data.amount);

const coreContract = Core__factory.connect(
config.ethConfiguration.coreContractAddress,
signer,
);

const registrationContract = Registration__factory.connect(
config.ethConfiguration.registrationContractAddress,
signer,
);

const isRegistered = await isRegisteredOnChainWorkflow(
starkPublicKey,
registrationContract,
);

if (!isRegistered) {
return executeRegisterAndDepositERC20(
signer,
quantizedAmount,
assetType,
starkPublicKey,
vaultId,
coreContract,
usersApi,
);
} else {
return executeDepositERC20(
signer,
quantizedAmount,
assetType,
starkPublicKey,
vaultId,
coreContract,
);
}
}
Loading