import { Address, erc20Abi, isAddressEqual, maxUint256 } from 'viem'; import { Permit, PERMIT2_MAP } from '@prex0/prex-structs'; import { PrexUser } from '../types'; import { PrexSigner } from '../core/sign'; import { PrexApiService } from '../api'; import { PrexClient } from '../prex-client'; import { getTokenName } from '../evm-api/token-detail'; const AN_HOUR_IN_SECONDS = 60 * 60; export class ApproveAction { constructor( private client: PrexClient, private user: PrexUser, private signer: PrexSigner, private apiService: PrexApiService ) {} async approve({ token, amount = maxUint256, from, }: { token: Address; amount?: bigint; from?: Address; }) { if (this.user.walletId === '') { // Use permit if it is not a smart wallet const name = await getTokenName(this.client.evmChainClient, token); const deadline = getDeadline(); const permit = new Permit( { owner: this.user.address, spender: PERMIT2_MAP[this.apiService.chainId], value: amount, nonce: await this.client.updatePermitNonce(token), deadline, }, name, getVersion(token), this.apiService.chainId, token ); const { domain, types, message } = permit.permitData(); const signature = await this.signer.signTypedData({ domain, types, message, primaryType: 'Permit', }); await this.apiService.permit({ owner: message.owner, spender: message.spender, value: message.value.toString(), deadline: message.deadline.toString(), signature, address: token, }); } else { await this.client.executeOperation( { address: token, abi: erc20Abi, functionName: 'approve', args: [PERMIT2_MAP[this.apiService.chainId], amount], }, from ); } await this.client.fetchBalance(token); } } function getVersion(address: Address) { // Native USDC in Arbitrum if (isAddressEqual(address, '0xaf88d065e77c8cc2239327c5edb3a432268e5831')) { return '2'; } return '1'; } function getDeadline() { return BigInt(Math.floor(Date.now() / 1000 + AN_HOUR_IN_SECONDS)); }