import { defaultAbiCoder } from '@ethersproject/abi' import { Signer } from '@ethersproject/abstract-signer' import { keccak256 as solidityKeccak256 } from '@ethersproject/solidity' import { FNSArgs } from '..' import { CombinedFuseInput, encodeFuses } from '../utils/fuses' import { hexEncodeName } from '../utils/hexEncodedName' import { checkIsDotFtm } from '../utils/validation' import { Expiry, wrappedLabelLengthCheck } from '../utils/wrapper' async function wrapFTM( { contracts }: FNSArgs<'contracts'>, labels: string[], wrappedOwner: string, decodedFuses: number, resolverAddress: string, signer: Signer, address: string, ) { const nameWrapper = await contracts?.getNameWrapper()! const baseRegistrar = (await contracts!.getBaseRegistrar()!).connect(signer) const labelhash = solidityKeccak256(['string'], [labels[0]]) const data = defaultAbiCoder.encode( ['string', 'address', 'uint16', 'address'], [labels[0], wrappedOwner, decodedFuses, resolverAddress], ) return baseRegistrar.populateTransaction[ 'safeTransferFrom(address,address,uint256,bytes)' ](address, nameWrapper.address, labelhash, data) } async function wrapOther( { contracts }: FNSArgs<'contracts'>, name: string, wrappedOwner: string, resolverAddress: string, address: string, signer: Signer, ) { const nameWrapper = (await contracts!.getNameWrapper()!).connect(signer) const registry = await contracts?.getRegistry()! const hasApproval = await registry.isApprovedForAll( address, nameWrapper.address, ) if (!hasApproval) { throw new Error( 'NameWrapper must have approval to wrap a name from this address.', ) } return nameWrapper.populateTransaction.wrap( hexEncodeName(name), wrappedOwner, resolverAddress, ) } export default async function ( { contracts, signer }: FNSArgs<'contracts' | 'signer'>, name: string, { wrappedOwner, fuseOptions, expiry, resolverAddress, }: { wrappedOwner: string fuseOptions?: Partial | number expiry?: Expiry resolverAddress?: string }, ) { const address = await signer.getAddress() let decodedFuses: number const publicResolver = await contracts?.getPublicResolver()! if (!resolverAddress) resolverAddress = publicResolver.address const labels = name.split('.') wrappedLabelLengthCheck(labels[0]) if (checkIsDotFtm(labels)) { switch (typeof fuseOptions) { case 'object': { decodedFuses = encodeFuses(fuseOptions) break } case 'number': { decodedFuses = fuseOptions break } case 'undefined': { decodedFuses = 0 break } default: { throw new Error(`Invalid fuseOptions type: ${typeof fuseOptions}`) } } return wrapFTM( { contracts }, labels, wrappedOwner, decodedFuses, resolverAddress, signer, address, ) } if (fuseOptions) throw new Error( 'Fuses can not be initially set when wrapping a non .ftm name', ) if (expiry) throw new Error( 'Expiry can not be initially set when wrapping a non .ftm name', ) return wrapOther( { contracts }, name, wrappedOwner, resolverAddress, address, signer, ) }