import { TypedDataSigner } from '@ethersproject/abstract-signer'; import { Seaport as ParaSpaceSeaport } from '@paraspace/seaport-js'; import { ethers, providers } from 'ethers'; import { convertSignatureToEIP2098, getDomainSeparator, } from '../commons/utils'; const CREDIT_TYPE = { Credit: [ { name: 'token', type: 'address' }, { name: 'amount', type: 'uint256' }, { name: 'orderId', type: 'bytes' }, ], }; export class SeaportService { private readonly instance: ParaSpaceSeaport; private readonly provider: providers.JsonRpcProvider; private readonly poolAddress: string; constructor( provider: providers.JsonRpcProvider, { poolAddress, seaportAddress, conduitAddress, conduitKey, }: { poolAddress: string; seaportAddress: string; conduitAddress: string; conduitKey: string; }, ) { this.poolAddress = poolAddress; this.provider = provider; this.instance = new ParaSpaceSeaport(provider, { overrides: { contractAddress: seaportAddress, }, conduitKeyToConduit: { [conduitKey]: conduitAddress, }, balanceAndApprovalChecksOnOrderCreation: false, }); } public getSDKInstance() { return this.instance; } public async signPayLaterPayload( signer: TypedDataSigner, { token, amount, orderSignature, }: { token: string; amount: string; orderSignature: string; }, ) { const domainSeparator = await getDomainSeparator( this.provider, this.poolAddress, '1.1', ); const orderId = ethers.utils.arrayify(orderSignature); const credit = { token, amount, orderId, }; /** * https://eips.ethereum.org/EIPS/eip-712 * 1. domain separator to avoid sign reusing * 2. solidity type of the struct * 3. actual value of the struct */ const signature = await signer._signTypedData( domainSeparator, CREDIT_TYPE, credit, ); const vrs = ethers.utils.splitSignature( convertSignatureToEIP2098(signature), ); const { v, r, s } = vrs; return { ...credit, orderId: orderSignature, vrs: { v: `${v}`, r, s, }, }; } public async verifyPayLaterPayload( signerAddr: string, { token, amount, orderSignature, }: { token: string; amount: string; orderSignature: string; }, signature: string, ) { const domainSeparator = await getDomainSeparator( this.provider, this.poolAddress, '1.1', ); const orderId = ethers.utils.arrayify(orderSignature); const credit = { token, amount, orderId, }; /** * https://eips.ethereum.org/EIPS/eip-712 * 1. domain separator to avoid sign reusing * 2. solidity type of the struct * 3. actual value of the struct */ return ( ethers.utils.verifyTypedData( domainSeparator, CREDIT_TYPE, credit, signature, ) === signerAddr ); } }