From e0b5ea52b22ec0526d2d4f220ecfbb9030f96e67 Mon Sep 17 00:00:00 2001 From: BJ Vicks Date: Wed, 11 Oct 2023 18:25:36 -0700 Subject: [PATCH] allow 1155 transfers using transferNFT to set amount, add 1155 tests --- .changeset/sixty-steaks-exist.md | 5 + packages/sdk/package.json | 2 +- packages/sdk/src/TokenboundClient.ts | 25 ++--- packages/sdk/src/test/TestAll.test.ts | 148 +++++++++++++++----------- packages/sdk/src/test/config/mints.ts | 7 +- packages/sdk/src/types/params.ts | 1 + 6 files changed, 108 insertions(+), 80 deletions(-) create mode 100644 .changeset/sixty-steaks-exist.md diff --git a/.changeset/sixty-steaks-exist.md b/.changeset/sixty-steaks-exist.md new file mode 100644 index 0000000..685c2fc --- /dev/null +++ b/.changeset/sixty-steaks-exist.md @@ -0,0 +1,5 @@ +--- +'@tokenbound/sdk': patch +--- + +allow 1155 transfers using transferNFT to set amount, add 1155 tests diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 461f619..a9b25e5 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@tokenbound/sdk", - "version": "0.3.11", + "version": "0.3.12", "type": "module", "files": [ "dist" diff --git a/packages/sdk/src/TokenboundClient.ts b/packages/sdk/src/TokenboundClient.ts index 7bf57c6..1783e73 100644 --- a/packages/sdk/src/TokenboundClient.ts +++ b/packages/sdk/src/TokenboundClient.ts @@ -383,6 +383,7 @@ class TokenboundClient { * @param {string} params.tokenContract The address of the token contract * @param {string} params.tokenId The token ID * @param {string} params.recipientAddress The address to which the token should be transferred + * @param {string} params.amount The amount of tokens to transfer, (eg. 1 NFT = 1) * @returns a Promise that resolves to the transaction hash of the executed call */ public async transferNFT(params: NFTTransferParams): Promise<`0x${string}`> { @@ -391,30 +392,24 @@ class TokenboundClient { tokenType, tokenContract, tokenId, + amount = 1, recipientAddress, } = params const is1155: boolean = tokenType === NFTTokenType.ERC1155 + if (!is1155 && amount !== 1) { + throw new Error('ERC721 transfers can only transfer one token at a time.') + } + try { const recipient = await resolvePossibleENS(this.publicClient, recipientAddress) // Configure required args based on token type - const transferArgs: unknown[] = is1155 - ? [ - // ERC1155: safeTransferFrom(address,address,uint256,uint256,bytes) - tbAccountAddress, - recipient, - tokenId, - 1, - '0x', - ] - : [ - // ERC721: safeTransferFrom(address,address,uint256) - tbAccountAddress, - recipient, - tokenId, - ] + // ERC1155: safeTransferFrom(address,address,uint256,uint256,bytes) + // ERC721: safeTransferFrom(address,address,uint256) + const sharedArgs = [tbAccountAddress, recipient, tokenId] + const transferArgs: unknown[] = is1155 ? [...sharedArgs, amount, '0x'] : sharedArgs const transferCallData = encodeFunctionData({ abi: is1155 ? erc1155Abi : erc721Abi, diff --git a/packages/sdk/src/test/TestAll.test.ts b/packages/sdk/src/test/TestAll.test.ts index 0c29ebe..190f8b9 100644 --- a/packages/sdk/src/test/TestAll.test.ts +++ b/packages/sdk/src/test/TestAll.test.ts @@ -1,8 +1,8 @@ -// This test suite is for testing the SDK methods with -// viem walletClient + publicClient and with Ethers 5/6. +// This test suite is for testing SDK methods with +// viem walletClient + publicClient and Ethers 5/6. import { zora } from 'viem/chains' -import { describe, expect, it, vi } from 'vitest' +import { describe, beforeAll, afterAll, test, expect, it, vi } from 'vitest' import { providers } from 'ethers' import { waitFor } from './mockWallet' import { createAnvil } from '@viem/anvil' @@ -17,8 +17,8 @@ import { parseUnits, formatEther, getContract, - // encodeAbiParameters, - // parseAbiParameters, + encodeAbiParameters, + parseAbiParameters, } from 'viem' import { privateKeyToAccount } from 'viem/accounts' import { CreateAccountParams, TokenboundClient } from '@tokenbound/sdk' @@ -38,20 +38,11 @@ import { getPublicClient, getWETHBalance, // debugTransaction, - // getZora1155Balance, + getZora1155Balance, getZora721Balance, } from './utils' -import { - ANVIL_CONFIG, - CREATE_ANVIL_OPTIONS, - zora721, - // zora1155 -} from './config' -import { - wethABI, - // zora1155ABI -} from './wagmi-cli-hooks/generated' -import { getEnsAddress } from 'viem/ens' +import { ANVIL_CONFIG, CREATE_ANVIL_OPTIONS, zora721, zora1155 } from './config' +import { wethABI } from './wagmi-cli-hooks/generated' const TIMEOUT = 60000 // default 10000 const ANVIL_USER_0 = getAddress(ANVIL_ACCOUNTS[0].address) @@ -461,7 +452,22 @@ function runTxTests({ }) }) - it('can transferNFT with the TBA', async () => { + it('will not allow transferNFT 721 with an amount other than 1', async () => { + vi.spyOn(console, 'error') + + await expect(() => + tokenboundClient.transferNFT({ + account: ZORA721_TBA_ADDRESS, + tokenType: 'ERC721', + tokenContract: zora721.proxyContractAddress, + tokenId: TOKENID1_IN_TBA, + recipientAddress: ANVIL_USER_1, + amount: 2, + }) + ).rejects.toThrowError() + }) + + it('can transferNFT a 721 with the TBA', async () => { const transferNFTHash = await tokenboundClient.transferNFT({ account: ZORA721_TBA_ADDRESS, tokenType: 'ERC721', @@ -531,46 +537,69 @@ function runTxTests({ }) }) - // it('can mint an 1155 with the TBA', async () => { - // const mintingAccount: `0x${string}` = ZORA721_TBA_ADDRESS - // // const mintAddress: `0x${string}` = ANVIL_USER_0 - - // const minterArguments: `0x${string}` = encodeAbiParameters( - // parseAbiParameters('address'), - // [mintingAccount] - // ) - - // const mint1155TxHash = await tokenboundClient.executeCall({ - // account: mintingAccount, - // to: zora1155.proxyContractAddress, - // value: zora1155.mintFee * zora1155.quantity, - // data: encodeFunctionData({ - // abi: zora1155ABI, - // functionName: 'mint', - // args: [ - // zora1155.fixedPriceSalesStrategy, - // zora1155.tokenId, - // zora1155.quantity, - // minterArguments, - // ], - // }), - // }) - - // await debugTransaction({ publicClient, hash: mint1155TxHash }) - - // const zora1155BalanceInTBA = await getZora1155Balance({ - // publicClient, - // walletAddress: mintingAccount, - // }) - - // console.log('1155 Balance', zora1155BalanceInTBA) - - // await waitFor(() => { - // expect(mint1155TxHash).toMatch(ADDRESS_REGEX) - // expect(zora1155BalanceInTBA).toBe(5n) - // expect(true).toBe(true) - // }) - // }) + it('can mint an 1155 with the TBA', async () => { + const mintingAccount: `0x${string}` = ZORA721_TBA_ADDRESS + + const minterArguments: `0x${string}` = encodeAbiParameters( + parseAbiParameters('address'), + [mintingAccount] + ) + + const data = encodeFunctionData({ + abi: zora1155.abi, + functionName: 'mint', + args: [ + zora1155.fixedPriceSalesStrategy, // IMinter1155 + zora1155.tokenId, // uint256 + zora1155.quantity, // uint256 + minterArguments, // bytes + ], + }) + + const mint1155TxHash = await tokenboundClient.executeCall({ + account: mintingAccount, + to: zora1155.proxyContractAddress, + value: zora1155.mintFee * zora1155.quantity, + data, + }) + + const zora1155BalanceInTBA = await getZora1155Balance({ + publicClient, + walletAddress: mintingAccount, + }) + + console.log('1155 Balance', zora1155BalanceInTBA) + + await waitFor(() => { + expect(mint1155TxHash).toMatch(ADDRESS_REGEX) + expect(zora1155BalanceInTBA).toBe(5n) + }) + }) + + it('can transferNFT an 1155 with the TBA', async () => { + const transferAmount = 2 + + const transferNFTHash = await tokenboundClient.transferNFT({ + account: ZORA721_TBA_ADDRESS, + tokenType: 'ERC1155', + tokenContract: zora1155.proxyContractAddress, + tokenId: zora1155.tokenId.toString(), + recipientAddress: ANVIL_USER_1, + amount: transferAmount, + }) + + const anvilAccount1_1155Balance = await getZora1155Balance({ + publicClient, + walletAddress: ANVIL_USER_1, + }) + + console.log('1155 Balance', anvilAccount1_1155Balance) + + await waitFor(() => { + expect(transferNFTHash).toMatch(ADDRESS_REGEX) + expect(anvilAccount1_1155Balance).toBe(BigInt(transferAmount)) + }) + }) // Test signing in viem only. // Ethers 5/6 don't appear to support signing messages via personal_sign with this testing configuration. @@ -763,9 +792,6 @@ function runTxTests({ expect(ensWETHBalance).toBe(transferWeiValue) }) }) - - test.todo('can transferNFT with an 1155', async () => {}) - test.todo('can transfer with ENS', async () => {}) }) } diff --git a/packages/sdk/src/test/config/mints.ts b/packages/sdk/src/test/config/mints.ts index 75c326c..3e6b681 100644 --- a/packages/sdk/src/test/config/mints.ts +++ b/packages/sdk/src/test/config/mints.ts @@ -1,6 +1,6 @@ import { getAddress } from 'viem' import { ethToWei } from '../utils' -import { zora721DropABI } from '../wagmi-cli-hooks/generated' +import { zora721DropABI, zora1155ABI } from '../wagmi-cli-hooks/generated' // Zora Webb's First Deep Field: https://zora.co/collect/eth:0x28ee638f2fcb66b4106acab7efd225aeb2bd7e8d export const zora721 = { @@ -12,9 +12,10 @@ export const zora721 = { // https://zora.co/collect/eth:0x373075bab7d668ed2473d8233ebdebcf49eb758e/1 export const zora1155 = { - fixedPriceSalesStrategy: getAddress('0x8A1DBE9b1CeB1d17f92Bebf10216FCFAb5C3fbA7'), // IMinter1155 minter contract from https://github.com/ourzora/zora-1155-contracts/blob/main/addresses/1.json + abi: zora1155ABI, + fixedPriceSalesStrategy: getAddress('0x5Ff5a77dD2214d863aCA809C0168941052d9b180'), // Zora IMinter1155 from https://etherscan.io/address/0x5Ff5a77dD2214d863aCA809C0168941052d9b180 proxyContractAddress: getAddress('0x373075bab7d668ed2473d8233ebdebcf49eb758e'), // proxied Zora 1155 contract tokenId: BigInt(1), - mintFee: ethToWei(0.000777), // 0.000777 ETH + mintFee: ethToWei(0.000777), quantity: BigInt(5), } diff --git a/packages/sdk/src/types/params.ts b/packages/sdk/src/types/params.ts index 5aae058..038a1d1 100644 --- a/packages/sdk/src/types/params.ts +++ b/packages/sdk/src/types/params.ts @@ -30,6 +30,7 @@ export type NFTTransferParams = Prettify< NFTParams & { recipientAddress: PossibleENSAddress account: `0x${string}` + amount?: number } >