UNPKG

@paulstinchcombe/kami721c-sdk

Version:

SDK for interacting with KAMI721C NFT contracts

240 lines (219 loc) 9.17 kB
import { ContractFactory, ContractRunner, ethers, Interface, Signer, BaseContract } from 'ethers'; // import KAMI721CABI from '../abis/KAMI721C.json'; import { KAMI721C } from '../contracts/KAMI721C'; // Import ABIs for implementation and proxy import implementationCompiledContract from '../abis/KAMI721CUpgradeable/KAMI721CUpgradeable.json'; import proxyCompiledContract from '../abis/TransparentUpgradeableProxy/KAMITransparentUpgradeableProxy.json'; /** * Factory class for deploying KAMI721C contracts (Standard and Upgradeable via Proxy) */ export class KAMI721CFactory { private implementationFactory: ContractFactory; private proxyFactory: ContractFactory; private runner: ContractRunner; /** * Creates a new instance of the KAMI721C factory * @param runner A signer or provider with deployment permissions */ constructor(runner: ContractRunner) { this.runner = runner; // Create factory for the implementation contract this.implementationFactory = new ContractFactory( implementationCompiledContract.abi, implementationCompiledContract.bytecode, runner ); // Create factory for the proxy contract this.proxyFactory = new ContractFactory(proxyCompiledContract.abi, proxyCompiledContract.bytecode, runner); } /** * Deploy a new KAMI721C contract (Upgradeable via Transparent Proxy) * @param usdcAddress The address of the USDC token contract * @param name The name of the NFT collection * @param symbol The symbol of the NFT collection * @param baseURI The base URI for token metadata * @param initialMintPrice The initial mint price in USDC (with 6 decimals) * @param platformAddress The address that will receive platform commissions (also becomes proxy admin) * @param platformCommissionPercentage The platform commission percentage in basis points (e.g., 500 = 5%) * @param ownerAddress The address to grant the OWNER_ROLE to initially * @returns The deployed contract instance, interacting with the proxy */ async deployUpgradeable( usdcAddress: string, name: string, symbol: string, baseURI: string, initialMintPrice: bigint | string = 1000000n, // Default 1 USDC (6 decimals) platformAddress?: string, platformCommissionPercentage: number = 500, // Default 5% ownerAddress?: string ): Promise<KAMI721C> { let finalPlatformAddress = platformAddress; let finalOwnerAddress = ownerAddress; // Determine deployer address if needed let deployerAddress: string | undefined; if (this.runner && 'getAddress' in this.runner) { deployerAddress = await (this.runner as Signer).getAddress(); } else { // If runner is not a signer, addresses must be provided if (!finalPlatformAddress || !finalOwnerAddress) { throw new Error('platformAddress and ownerAddress are required when using a provider'); } } // If addresses not provided, use the deployer's address if (!finalPlatformAddress && deployerAddress) { finalPlatformAddress = deployerAddress; console.log(`Using deployer address ${deployerAddress} as platform address and proxy admin.`); } if (!finalOwnerAddress && deployerAddress) { finalOwnerAddress = deployerAddress; console.log(`Using deployer address ${deployerAddress} as initial owner.`); } // Ensure addresses are set if (!finalPlatformAddress || !finalOwnerAddress) { throw new Error('Could not determine platformAddress or ownerAddress.'); } console.log('Deploying KAMI721CUpgradeable implementation...'); try { const implementationContract = await this.implementationFactory.deploy({ gasLimit: 5000000 }); await implementationContract.waitForDeployment(); const implementationAddress = await implementationContract.getAddress(); console.log('Implementation contract deployed at:', implementationAddress); // Verify deployment const provider = this.runner.provider; if (!provider) { throw new Error('Runner does not have a provider.'); } const code = await provider.getCode(implementationAddress); if (!code || code === '0x') { throw new Error('Implementation deployment failed - no code at address'); } // Prepare initialization calldata const implementationInterface = new Interface(implementationCompiledContract.abi); const initializeData = implementationInterface.encodeFunctionData('initialize', [ usdcAddress, name, symbol, baseURI, initialMintPrice, finalPlatformAddress, platformCommissionPercentage, finalOwnerAddress, ]); console.log('Prepared initialization calldata.'); // Deploy the proxy contract console.log('Deploying KAMITransparentUpgradeableProxy...'); const proxyContract = await this.proxyFactory.deploy( implementationAddress, finalPlatformAddress, // Use platformAddress as proxy admin initializeData, { gasLimit: 2000000 } // Gas limit for proxy deployment ); await proxyContract.waitForDeployment(); const proxyAddress = await proxyContract.getAddress(); console.log('Proxy contract deployed at:', proxyAddress); // Verify proxy deployment const proxyCode = await provider.getCode(proxyAddress); if (!proxyCode || proxyCode === '0x') { throw new Error('Proxy deployment failed - no code at address'); } // Return a contract instance attached to the proxy address, using the implementation ABI console.log(`Returning contract instance attached to proxy address ${proxyAddress}`); return new KAMI721C(this.runner, proxyAddress, implementationCompiledContract.abi); } catch (error: any) { console.error('Deployment failed:', { error: error.message, reason: error.reason, code: error.code, data: error.data, transaction: error.transaction, }); throw error; } } // Keep the old deploy method for standard (non-upgradeable) deployment if needed, // or remove/deprecate it. /** * Deploy a new KAMI721C contract (Standard Non-Upgradeable Version) * @deprecated Use deployUpgradeable instead for the proxy-based version. * @param usdcAddress The address of the USDC token contract * @param name The name of the NFT collection * @param symbol The symbol of the NFT collection * @param baseURI The base URI for token metadata * @param initialMintPrice The initial mint price in USDC (with 6 decimals) * @param platformAddress The address that will receive platform commissions * @param platformCommissionPercentage The platform commission percentage in basis points (e.g., 500 = 5%) * @returns The deployed contract instance */ async deployStandard( usdcAddress: string, name: string, symbol: string, baseURI: string, initialMintPrice: bigint | string = 1000000n, // Default 1 USDC (6 decimals) platformAddress?: string, platformCommissionPercentage: number = 500 // Default 5% ): Promise<KAMI721C> { console.warn('Deploying standard non-upgradeable KAMI721C. Use deployUpgradeable for proxy deployment.'); let finalPlatformAddress = platformAddress; // If platform address not provided, use the deployer's address if (!finalPlatformAddress) { if (this.runner && 'getAddress' in this.runner) { finalPlatformAddress = await (this.runner as Signer).getAddress(); } else { throw new Error('Platform address is required when deployer address cannot be determined'); } } console.log('Deploying standard contract with parameters:', { usdcAddress, name, symbol, baseURI, initialMintPrice, finalPlatformAddress, platformCommissionPercentage, }); // Use the original KAMI721C ABI/Bytecode for standard deployment // Assuming the old ABI is still needed and available const standardCompiledContract = await import('../abis/KAMI721C/KAMI721C.json'); const standardFactory = new ContractFactory(standardCompiledContract.abi, standardCompiledContract.bytecode, this.runner); try { console.log('Creating standard deployment transaction...'); const contract = (await standardFactory.deploy( usdcAddress, name, symbol, baseURI, initialMintPrice, finalPlatformAddress, platformCommissionPercentage, { gasLimit: 5000000 } )) as BaseContract; console.log('Waiting for standard deployment transaction to be mined...'); await contract.waitForDeployment(); const address = await contract.getAddress(); console.log('Standard contract deployed at address:', address); // Verify the contract was deployed successfully console.log('Verifying standard contract deployment...'); const provider = this.runner.provider; if (!provider) { throw new Error('Runner does not have a provider.'); } const code = await provider.getCode(address); if (!code || code === '0x') { throw new Error('Standard contract deployment failed - no code at contract address'); } console.log('Standard contract code verified successfully'); return new KAMI721C(this.runner, address, standardCompiledContract.abi); } catch (error: any) { console.error('Standard deployment failed:', { error: error.message, reason: error.reason, code: error.code, data: error.data, transaction: error.transaction, }); throw error; } } }