diff --git a/examples/contracts/contract-interaction-with-viem/batch-mint-erc721-by-id.ts b/examples/contracts/contract-interaction-with-viem/batch-mint-erc721-by-id.ts index c8287f5b5d..65bdb35e50 100644 --- a/examples/contracts/contract-interaction-with-viem/batch-mint-erc721-by-id.ts +++ b/examples/contracts/contract-interaction-with-viem/batch-mint-erc721-by-id.ts @@ -2,6 +2,25 @@ import { getContract, http, createWalletClient, defineChain } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; import { ImmutableERC721Abi } from '@imtbl/contracts'; +const PRIVATE_KEY = '0xYOUR_PRIVATE_KEY'; // should be read from environment variable, should be of type `0x${string}` +const CONTRACT_ADDRESS = '0xYOUR_CONTRACT_ADDRESS'; // should be of type `0x${string}` +const TOKEN_ID_1 = BigInt(1); +const TOKEN_ID_2 = BigInt(2); +const TOKEN_ID_3 = BigInt(3); +const TOKEN_ID_4 = BigInt(4); +const ACCOUNT_ADDRESS_1: `0x${string}` = '0xACCOUNT_ADDRESS_1'; // should be of type `0x${string}` +const ACCOUNT_ADDRESS_2: `0x${string}` = '0xACCOUNT_ADDRESS_2'; // should be of type `0x${string}` +const REQUESTS = [ + { + to: ACCOUNT_ADDRESS_1, + tokenIds: [TOKEN_ID_1, TOKEN_ID_2], + }, + { + to: ACCOUNT_ADDRESS_2, + tokenIds: [TOKEN_ID_3, TOKEN_ID_4], + }, +]; + export const batchMintERC721ByID = async ( privateKey: `0x${string}`, contractAddress: `0x${string}`, @@ -56,3 +75,5 @@ export const batchMintERC721ByID = async ( console.log(`txHash: ${txHash}`); return txHash; }; + +batchMintERC721ByID(PRIVATE_KEY, CONTRACT_ADDRESS, REQUESTS); diff --git a/examples/contracts/contract-interaction-with-viem/batch-mint-erc721-by-quantity.ts b/examples/contracts/contract-interaction-with-viem/batch-mint-erc721-by-quantity.ts new file mode 100644 index 0000000000..d825b913db --- /dev/null +++ b/examples/contracts/contract-interaction-with-viem/batch-mint-erc721-by-quantity.ts @@ -0,0 +1,75 @@ +import { getContract, http, createWalletClient, defineChain } from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; +import { ImmutableERC721Abi } from '@imtbl/contracts'; + +const PRIVATE_KEY = '0xYOUR_PRIVATE_KEY'; // should be read from environment variable, should be of type `0x${string}` +const CONTRACT_ADDRESS = '0xYOUR_CONTRACT_ADDRESS'; // should be of type `0x${string}` +const ACCOUNT_ADDRESS_1: `0x${string}` = '0xACCOUNT_ADDRESS_1'; // should be of type `0x${string}` +const ACCOUNT_ADDRESS_2: `0x${string}` = '0xACCOUNT_ADDRESS_2'; // should be of type `0x${string}` +const MINTS = [ + { + to: ACCOUNT_ADDRESS_1, + quantity: BigInt(3), + }, + { + to: ACCOUNT_ADDRESS_2, + quantity: BigInt(3), + }, +]; + +export const batchMintERC721ByQuantity = async ( + privateKey: `0x${string}`, + contractAddress: `0x${string}`, + mints: { + to: `0x${string}`; + quantity: bigint; + }[], +): Promise => { + const immutableTestnet = defineChain({ + id: 13473, + name: 'imtbl-zkevm-testnet', + nativeCurrency: { name: 'IMX', symbol: 'IMX', decimals: 18 }, + rpcUrls: { + default: { + http: ['https://rpc.testnet.immutable.com'], + }, + }, + }); + + const walletClient = createWalletClient({ + chain: immutableTestnet, + transport: http(), + account: privateKeyToAccount(privateKey), + }); + + // Bound contract instance + const contract = getContract({ + address: contractAddress, + abi: ImmutableERC721Abi, + client: walletClient, + }); + + // We can use the read function hasRole to check if the intended signer + // has sufficient permissions to mint before we send the transaction + const minterRole = await contract.read.MINTER_ROLE(); + + const hasMinterRole = await contract.read.hasRole([ + minterRole, + walletClient.account.address, + ]); + + if (!hasMinterRole) { + // Handle scenario without permissions... + console.log('Account doesnt have permissions to mint.'); + return Promise.reject( + new Error('Account doesnt have permissions to mint.'), + ); + } + + const txHash = await contract.write.mintBatchByQuantity([mints]); + + console.log(`txHash: ${txHash}`); + return txHash; +}; + +batchMintERC721ByQuantity(PRIVATE_KEY, CONTRACT_ADDRESS, MINTS); diff --git a/examples/contracts/contract-interaction-with-viem/index.ts b/examples/contracts/contract-interaction-with-viem/index.ts index 95fe67b953..65e52ac3b5 100644 --- a/examples/contracts/contract-interaction-with-viem/index.ts +++ b/examples/contracts/contract-interaction-with-viem/index.ts @@ -1,3 +1,4 @@ import { batchMintERC721ByID } from './batch-mint-erc721-by-id'; +import { batchMintERC721ByQuantity } from './batch-mint-erc721-by-quantity'; -export { batchMintERC721ByID }; +export { batchMintERC721ByID, batchMintERC721ByQuantity }; diff --git a/examples/contracts/test/contracts.test.ts b/examples/contracts/test/contracts.test.ts index 635795aeb5..3f43b37912 100644 --- a/examples/contracts/test/contracts.test.ts +++ b/examples/contracts/test/contracts.test.ts @@ -1,5 +1,8 @@ import { describe, expect, test } from '@jest/globals'; -import { batchMintERC721ByID } from '../contract-interaction-with-viem'; +import { + batchMintERC721ByID, + batchMintERC721ByQuantity, +} from '../contract-interaction-with-viem'; const MINT_CONTRACT_ADDRESS = 'YOUR_MINT_CONTRACT_ADDRESS' as `0x${string}`; const MINT_RECIPIENT = 'YOUR_MINT_RECIPIENT' as `0x${string}`; @@ -23,4 +26,22 @@ describe('ImmutableERC721', () => { expect(txHash).not.toBe(''); }); }); + + describe('batchMintERC721ByQuantity', () => { + // Write methods are not yet tested as part of our CI system for simplification of testing on-chain + // calls that require gas payment idempotently, however are added here for testing locally. + test.skip('returns a valid transaction hash', async () => { + const txHash = await batchMintERC721ByQuantity( + MINT_PRIVATE_KEY, + MINT_CONTRACT_ADDRESS, + [ + { + to: MINT_RECIPIENT, + quantity: BigInt(10), + }, + ], + ); + expect(txHash).not.toBe(''); + }); + }); });