UNPKG

@paulstinchcombe/kami721c-sdk

Version:

SDK for interacting with KAMI721C NFT contracts

473 lines (472 loc) 17.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.KAMI721C = void 0; const ethers_1 = require("ethers"); const KAMI721C_json_1 = __importDefault(require("../abis/KAMI721C/KAMI721C.json")); const console_colors_1 = require("../utils/console-colors"); const ethers_2 = require("ethers"); /** * KAMI721C contract wrapper class */ class KAMI721C { /** * Creates a new instance of the KAMI721C contract wrapper * @param runner An ethers.js ContractRunner (Provider or Signer) * @param contractAddress The address of the KAMI721C contract * @param contractAbi Optional ABI to use (defaults to standard KAMI721C ABI) */ constructor(runner, contractAddress, contractAbi) { // Use the provided ABI or default to the standard KAMI721C ABI const abi = contractAbi || KAMI721C_json_1.default.abi; this.contract = new ethers_1.Contract(contractAddress, abi, runner); } /** * Connect a signer to the contract * @param signer The signer to connect * @returns A new instance of the KAMI721C contract with the connected signer */ connect(signer) { // Pass the current ABI when creating a connected instance return new KAMI721C(signer, this.contract.target, this.contract.interface.fragments); } /** * Get the contract address * @returns The contract address */ getAddress() { return this.contract.target; } /** * Get the contract name * @returns The name of the NFT collection */ async name() { return await this.contract.name(); } /** * Get the contract symbol * @returns The symbol of the NFT collection */ async symbol() { return await this.contract.symbol(); } /** * Get the total supply of tokens * @returns The total number of tokens minted */ async totalSupply() { try { // Try to call totalSupply directly first return await this.contract.totalSupply(); } catch (error) { try { // If totalSupply is not available, estimate using token counter // In the new contract, we can check the current token ID counter const tokenIdCounter = await this.contract._tokenIdCounter(); return tokenIdCounter; } catch (error) { // If both methods fail, return 0 as no tokens have been minted yet return 0n; } } } /** * Get the token URI for a specific token ID * @param tokenId The ID of the token to query * @returns The token URI */ async tokenURI(tokenId) { return await this.contract.tokenURI(tokenId); } /** * Get the owner of a specific token * @param tokenId The ID of the token to query * @returns The address of the token owner */ async ownerOf(tokenId) { return await this.contract.ownerOf(tokenId); } /** * Get the balance of an address * @param owner The address to query * @returns The number of tokens owned by the address */ async balanceOf(owner) { return await this.contract.balanceOf(owner); } /** * Approve another address to transfer a specific token * @param spender The address to approve * @param tokenId The ID of the token to approve * @returns The transaction */ async approve(spender, tokenId) { return await this.contract.approve(spender, tokenId); } /** * Get the approved address for a specific token * @param tokenId The ID of the token * @returns The approved address, or the zero address if none is set */ async getApproved(tokenId) { return await this.contract.getApproved(tokenId); } /** * Check if an operator is approved for all tokens of an owner * @param owner The owner address * @param operator The operator address * @returns True if the operator is approved, false otherwise */ async isApprovedForAll(owner, operator) { return await this.contract.isApprovedForAll(owner, operator); } /** * Set or unset approval for an operator for all tokens of the caller * @param operator The operator address * @param approved True to approve, false to revoke * @returns The transaction */ async setApprovalForAll(operator, approved) { return await this.contract.setApprovalForAll(operator, approved); } /** * Get the current mint price * @returns The mint price in USDC (with 6 decimals) */ async mintPrice() { return await this.contract.mintPrice(); } /** * Set the mint price (requires OWNER_ROLE) * @param newMintPrice The new mint price in USDC (with 6 decimals) * @returns The transaction */ async setMintPrice(newMintPrice) { return await this.contract.setMintPrice(newMintPrice); } /** * Mint a new token (requires USDC approval) * @returns The transaction */ async mint() { return await this.contract.mint(); } /** * Set royalties for all newly minted tokens (requires OWNER_ROLE) * @param royalties Array of royalty receivers and fee numerators * @returns The transaction */ async setMintRoyalties(royalties) { return await this.contract.setMintRoyalties(royalties); } /** * Set royalties for a specific token's mint event (requires OWNER_ROLE) * @param tokenId The ID of the token to set royalties for * @param royalties Array of royalty receivers and fee numerators * @returns The transaction */ async setTokenMintRoyalties(tokenId, royalties) { return await this.contract.setTokenMintRoyalties(tokenId, royalties); } /** * Set global transfer royalties for all tokens (requires OWNER_ROLE) * @param royalties Array of royalty receivers and fee numerators * @returns The transaction */ async setTransferRoyalties(royalties) { return await this.contract.setTransferRoyalties(royalties); } /** * Set transfer royalties for a specific token (requires OWNER_ROLE) * @param tokenId The ID of the token to set royalties for * @param royalties Array of royalty receivers and fee numerators * @returns The transaction */ async setTokenTransferRoyalties(tokenId, royalties) { return await this.contract.setTokenTransferRoyalties(tokenId, royalties); } /** * Get the current royalty percentage for transfers * @returns The royalty percentage in basis points (e.g., 1000 = 10%) */ async royaltyPercentage() { return await this.contract.royaltyPercentage(); } /** * Set the royalty percentage for transfers (requires OWNER_ROLE) * @param newRoyaltyPercentage New royalty percentage in basis points (e.g., 1000 = 10%) * @returns The transaction */ async setRoyaltyPercentage(newRoyaltyPercentage) { return await this.contract.setRoyaltyPercentage(newRoyaltyPercentage); } /** * Get the platform commission details * @returns The platform commission percentage and address */ async getPlatformCommission() { const percentage = await this.contract.platformCommissionPercentage(); const address = await this.contract.platformAddress(); return { percentage, address }; } /** * Set the platform commission details (requires OWNER_ROLE) * @param newPercentage New commission percentage in basis points (e.g., 500 = 5%) * @param newAddress New platform address to receive commission * @returns The transaction */ async setPlatformCommission(newPercentage, newAddress) { return await this.contract.setPlatformCommission(newPercentage, newAddress); } /** * Sell a token to another address with royalties handled automatically * @param to The buyer address * @param tokenId The token ID to sell * @param salePrice The sale price in USDC * @returns The transaction */ async sellToken(to, tokenId, salePrice) { try { // Verify the caller owns the token const owner = await this.ownerOf(tokenId); const signerAddress = await this.contract.runner.getAddress(); if (owner.toLowerCase() !== signerAddress.toLowerCase()) { console_colors_1.colorLog.error(`Error: Only the token owner can sell. Current owner: ${console_colors_1.logStyles.address(owner)}, Caller: ${console_colors_1.logStyles.address(signerAddress)}`); throw new Error('Only the token owner can sell this token'); } // Verify that the contract is approved to transfer the token const isApproved = await this.contract.isApprovedForAll(signerAddress, this.getAddress()); if (!isApproved) { console_colors_1.colorLog.warning(`Contract is not approved to transfer tokens. Please call setApprovalForAll first.`); } // Verify USDC allowance for the buyer try { const usdcAddress = await this.contract.usdcToken(); const usdcABI = [ 'function allowance(address owner, address spender) external view returns (uint256)', 'function balanceOf(address owner) external view returns (uint256)', ]; const usdc = new ethers_2.ethers.Contract(usdcAddress, usdcABI, this.contract.runner); const allowance = await usdc.allowance(to, this.getAddress()); if (allowance < salePrice) { console_colors_1.colorLog.warning(`Buyer has insufficient USDC allowance. Required: ${ethers_2.ethers.formatUnits(salePrice, 6)}, Current: ${ethers_2.ethers.formatUnits(allowance, 6)}`); } const balance = await usdc.balanceOf(to); if (balance < salePrice) { console_colors_1.colorLog.warning(`Buyer has insufficient USDC balance. Required: ${ethers_2.ethers.formatUnits(salePrice, 6)}, Current: ${ethers_2.ethers.formatUnits(balance, 6)}`); } } catch (error) { console_colors_1.colorLog.warning(`Could not verify USDC allowance: ${error}`); } // Now call the sellToken function console_colors_1.colorLog.info(`Calling sellToken with parameters: to=${console_colors_1.logStyles.address(to)}, tokenId=${console_colors_1.logStyles.value(tokenId.toString())}, salePrice=${console_colors_1.logStyles.value(salePrice.toString())}`); return await this.contract.sellToken(to, tokenId, salePrice); } catch (error) { console_colors_1.colorLog.error(`sellToken failed: ${error.message}`); throw error; } } /** * Get royalty information for a token sale * @param tokenId The ID of the token being sold * @param salePrice The sale price * @returns The royalty receiver address and amount */ async royaltyInfo(tokenId, salePrice) { const [receiver, royaltyAmount] = await this.contract.royaltyInfo(tokenId, salePrice); return { receiver, royaltyAmount }; } /** * Get mint royalty receivers for a token * @param tokenId The ID of the token * @returns Array of royalty data */ async getMintRoyaltyReceivers(tokenId) { return await this.contract.getMintRoyaltyReceivers(tokenId); } /** * Get transfer royalty receivers for a token * @param tokenId The ID of the token * @returns Array of royalty data */ async getTransferRoyaltyReceivers(tokenId) { return await this.contract.getTransferRoyaltyReceivers(tokenId); } /** * Check if an address has a specific role * @param role The role to check (OWNER_ROLE, PLATFORM_ROLE, or RENTER_ROLE) * @param address The address to check * @returns True if the address has the role */ async hasRole(role, address) { return await this.contract.hasRole(role, address); } /** * Grant a role to an address (requires DEFAULT_ADMIN_ROLE) * @param role The role to grant (OWNER_ROLE, PLATFORM_ROLE, or RENTER_ROLE) * @param address The address to grant the role to * @returns The transaction */ async grantRole(role, address) { return await this.contract.grantRole(role, address); } /** * Revoke a role from an address (requires DEFAULT_ADMIN_ROLE) * @param role The role to revoke (OWNER_ROLE, PLATFORM_ROLE, or RENTER_ROLE) * @param address The address to revoke the role from * @returns The transaction */ async revokeRole(role, address) { return await this.contract.revokeRole(role, address); } /** * Get the OWNER_ROLE constant * @returns The OWNER_ROLE bytes32 value */ async OWNER_ROLE() { return await this.contract.OWNER_ROLE(); } /** * Get the PLATFORM_ROLE constant * @returns The PLATFORM_ROLE bytes32 value */ async PLATFORM_ROLE() { return await this.contract.PLATFORM_ROLE(); } /** * Get the RENTER_ROLE constant * @returns The RENTER_ROLE bytes32 value */ async RENTER_ROLE() { return await this.contract.RENTER_ROLE(); } /** * Set the base URI for tokens (requires OWNER_ROLE) * @param baseURI The new base URI * @returns The transaction */ async setBaseURI(baseURI) { return await this.contract.setBaseURI(baseURI); } /** * Burn a token (requires token owner permission) * @param tokenId The ID of the token to burn * @returns The transaction */ async burn(tokenId) { return await this.contract.burn(tokenId); } /** * Set the security policy for the contract (requires OWNER_ROLE) * @param securityLevel The security level * @param operatorWhitelistId The operator whitelist ID * @param permittedContractReceiversAllowlistId The permitted contract receivers allowlist ID * @returns The transaction */ async setSecurityPolicy(securityLevel, operatorWhitelistId, permittedContractReceiversAllowlistId) { return await this.contract.setSecurityPolicy(securityLevel, operatorWhitelistId, permittedContractReceiversAllowlistId); } /** * Rent a token (requires USDC approval) * @param tokenId The ID of the token to rent * @param duration The rental duration in seconds * @param rentalPrice The rental price in USDC * @returns The transaction */ async rentToken(tokenId, duration, rentalPrice) { return await this.contract.rentToken(tokenId, duration, rentalPrice); } /** * End a rental early (can be called by either the owner or the renter) * @param tokenId The ID of the token to end rental for * @returns The transaction */ async endRental(tokenId) { return await this.contract.endRental(tokenId); } /** * Extend a rental period * @param tokenId The ID of the token to extend rental for * @param additionalDuration The additional duration in seconds * @param additionalPayment The additional payment in USDC * @returns The transaction */ async extendRental(tokenId, additionalDuration, additionalPayment) { return await this.contract.extendRental(tokenId, additionalDuration, additionalPayment); } /** * Check if a token is currently rented * @param tokenId The ID of the token to check * @returns Whether the token is rented */ async isRented(tokenId) { return await this.contract.isRented(tokenId); } /** * Get rental information for a token * @param tokenId The ID of the token to get rental info for * @returns The rental information */ async getRentalInfo(tokenId) { const [renter, startTime, endTime, rentalPrice, active] = await this.contract.getRentalInfo(tokenId); return { renter, startTime, endTime, rentalPrice, active }; } /** * Check if a user has any active rentals * @param user The user address to check * @returns Whether the user has active rentals */ async hasActiveRentals(user) { return await this.contract.hasActiveRentals(user); } /** * Get the USDC token address * @returns The address of the USDC token contract */ async getUsdcTokenAddress() { return await this.contract.usdcToken(); } /** * Get the platform commission percentage * @returns The platform commission percentage in basis points (e.g., 500 = 5%) */ async getPlatformCommissionPercentage() { return await this.contract.platformCommissionPercentage(); } /** * Get the platform address * @returns The address that receives platform commission */ async getPlatformAddress() { return await this.contract.platformAddress(); } /** * Check if the contract is paused * @returns Whether the contract is paused */ async paused() { return await this.contract.paused(); } /** * Pause the contract (requires OWNER_ROLE) * @returns The transaction */ async pause() { return await this.contract.pause(); } /** * Unpause the contract (requires OWNER_ROLE) * @returns The transaction */ async unpause() { return await this.contract.unpause(); } } exports.KAMI721C = KAMI721C;