@paulstinchcombe/kami721c-sdk
Version:
SDK for interacting with KAMI721C NFT contracts
435 lines (434 loc) • 16.4 kB
JavaScript
"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
*/
constructor(runner, contractAddress) {
// Use the ABI directly from the imported JSON
this.contract = new ethers_1.Contract(contractAddress, KAMI721C_json_1.default.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) {
return new KAMI721C(signer, this.contract.target);
}
/**
* 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);
}
/**
* 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;