kamiweb3-sdk
Version:
TypeScript SDK for KAMI721-C, KAMI721-AC, and KAMI1155-C smart contracts
534 lines • 20.9 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.KAMI721CWrapper = void 0;
const ethers_1 = require("ethers");
const utils_1 = require("ethers/lib/utils");
const KAMI721C_json_1 = __importDefault(require("../abis/KAMI721C.json"));
/**
* Wraps an instance of the KAMI721C contract (standard or upgradeable proxy) to provide typed methods.
*/
class KAMI721CWrapper {
/**
* Creates an instance of KAMI721CWrapper.
* @param address The address of the standard contract or the proxy contract.
* @param signerOrProvider A Signer (for transactions) or Provider (for read-only).
* @param contractAbi (Optional) The ABI to use. Defaults to the standard KAMI721C ABI. Provide the KAMI721CUpgradeable ABI when attaching to a proxy.
*/
constructor(address, signerOrProvider, contractAbi) {
// Use provided ABI or default to standard KAMI721C ABI
this.abi = contractAbi || KAMI721C_json_1.default.abi;
if (!this.abi || this.abi.length === 0) {
// Check if the default was attempted and failed
if (!contractAbi && (!KAMI721C_json_1.default || !KAMI721C_json_1.default.abi)) {
throw new Error('Default KAMI721C ABI not found or invalid.');
}
else {
throw new Error('Provided ABI is invalid or ABI not found.');
}
}
this.contract = new ethers_1.Contract(address.toString(), this.abi, signerOrProvider);
this.address = address.toString();
}
// === Core ERC721 Functions ===
/**
* Returns the number of tokens in `owner`'s account.
* @throws {Error} If owner is the zero address.
*/
async balanceOf(owner) {
if (owner === '0x0000000000000000000000000000000000000000')
throw new Error('ERC721: balance query for the zero address');
return this.contract.balanceOf(owner);
}
/**
* Returns the owner of the `tokenId` token.
* @throws {Error} If the token does not exist.
*/
async ownerOf(tokenId) {
return this.contract.ownerOf(tokenId);
}
/**
* Safely transfers `tokenId` token from `from` to `to`.
* @throws {Error} If caller is not owner nor approved, or if `to` is zero address.
*/
async safeTransferFrom(from, to, tokenId, data = '0x', overrides = {}) {
this.requireSigner();
if (to === '0x0000000000000000000000000000000000000000')
throw new Error('ERC721: transfer to the zero address');
// Ensure correct overload is called (based on presence/absence of data argument)
if (data && data !== '0x' && (0, utils_1.arrayify)(data).length > 0) {
return this.contract['safeTransferFrom(address,address,uint256,bytes)'](from, to, tokenId, data, overrides);
}
else {
return this.contract['safeTransferFrom(address,address,uint256)'](from, to, tokenId, overrides);
}
}
/**
* Transfers `tokenId` token from `from` to `to`.
* Note: Usage of this method is discouraged, use `safeTransferFrom` whenever possible.
* @throws {Error} If caller is not owner nor approved, or if `to` is zero address.
*/
async transferFrom(from, to, tokenId, overrides = {}) {
this.requireSigner();
if (to === '0x0000000000000000000000000000000000000000')
throw new Error('ERC721: transfer to the zero address');
return this.contract.transferFrom(from, to, tokenId, overrides);
}
/**
* Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
* @throws {Error} If `to` is the zero address.
*/
async approve(to, tokenId, overrides = {}) {
this.requireSigner();
if (to === '0x0000000000000000000000000000000000000000')
throw new Error('ERC721: approve to the zero address');
return this.contract.approve(to, tokenId, overrides);
}
/**
* Returns the account approved for `tokenId` token.
* @throws {Error} If the token does not exist.
*/
async getApproved(tokenId) {
return this.contract.getApproved(tokenId);
}
/**
* Approve or remove `operator` as an operator for the caller.
*/
async setApprovalForAll(operator, approved, overrides = {}) {
this.requireSigner();
return this.contract.setApprovalForAll(operator, approved, overrides);
}
/**
* Returns if the `operator` is allowed to manage all of the assets of `owner`.
*/
async isApprovedForAll(owner, operator) {
return this.contract.isApprovedForAll(owner, operator);
}
/**
* Returns the token collection name.
*/
async name() {
return this.contract.name();
}
/**
* Returns the token collection symbol.
*/
async symbol() {
return this.contract.symbol();
}
/**
* Returns the Uniform Resource Identifier (URI) for `tokenId` token.
* @throws {Error} If the token does not exist.
*/
async tokenURI(tokenId) {
return this.contract.tokenURI(tokenId);
}
// === ERC721Enumerable Functions ===
/**
* Returns the total amount of tokens stored by the contract.
*/
async totalSupply() {
const result = await this.contract.totalSupply();
return BigInt(result.toString());
}
/**
* Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
* @throws {Error} If `index` >= `balanceOf(owner)` or `owner` is zero address.
*/
async tokenOfOwnerByIndex(owner, index) {
if (owner === '0x0000000000000000000000000000000000000000')
throw new Error('Enumerable: owner index query for the zero address');
return this.contract.tokenOfOwnerByIndex(owner, index);
}
/**
* Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
* @throws {Error} If `index` >= `totalSupply()`.
*/
async tokenByIndex(index) {
return this.contract.tokenByIndex(index);
}
// === ERC2981 Royalty Standard ===
/**
* Returns royalty information for a given token and sale price.
* @param tokenId The token ID to get royalty information for.
* @param salePrice The sale price to calculate royalties for.
* @returns RoyaltyInfo object containing receiver address and royalty amount.
*/
async royaltyInfo(tokenId, salePrice) {
const result = await this.contract.royaltyInfo(tokenId, salePrice);
return {
receiver: result[0],
royaltyAmount: result[1],
};
}
// === KAMI721C Specific Functions ===
/**
* Mints a new token to the caller.
* @throws {Error} If caller doesn't have sufficient USDC or approval.
*/
async mint(overrides = {}) {
this.requireSigner();
return this.contract.mint(overrides);
}
/**
* Sells a token to a buyer for a specified price.
* @param to The address to sell the token to.
* @param tokenId The ID of the token to sell.
* @param salePrice The price to sell the token for.
* @throws {Error} If caller is not owner nor approved, or if buyer doesn't have sufficient USDC.
*/
async sellToken(to, tokenId, salePrice, overrides = {}) {
this.requireSigner();
return this.contract.sellToken(to, tokenId, salePrice, overrides);
}
/**
* Rents a token for a specified duration and price.
* @param tokenId The ID of the token to rent.
* @param duration The duration of the rental in seconds.
* @param rentalPrice The price for the rental.
* @throws {Error} If caller doesn't have sufficient USDC or approval.
*/
async rentToken(tokenId, duration, rentalPrice, overrides = {}) {
this.requireSigner();
return this.contract.rentToken(tokenId, duration, rentalPrice, overrides);
}
/**
* Ends a rental for a token.
* @param tokenId The ID of the token to end the rental for.
* @throws {Error} If caller is not the renter or rental has already ended.
*/
async endRental(tokenId, overrides = {}) {
this.requireSigner();
return this.contract.endRental(tokenId, overrides);
}
/**
* Extends a rental for a token with additional duration and payment.
* @param tokenId The ID of the token to extend the rental for.
* @param additionalDuration The additional duration in seconds.
* @param additionalPayment The additional payment for the extension.
* @throws {Error} If caller is not the renter or doesn't have sufficient USDC.
*/
async extendRental(tokenId, additionalDuration, additionalPayment, overrides = {}) {
this.requireSigner();
return this.contract.extendRental(tokenId, additionalDuration, additionalPayment, overrides);
}
/**
* Gets rental details for a specific token.
* @param tokenId The ID of the token to get rental details for.
* @returns A promise that resolves to the rental details.
*/
async getRentalDetails(tokenId) {
const result = await this.contract.getRentalInfo(tokenId);
return {
renter: result[0],
startTime: BigInt(result[1].toString()),
endTime: BigInt(result[2].toString()),
rentalPrice: BigInt(result[3].toString()),
active: result[4],
};
}
/**
* Checks if a user has active rentals.
* @param user The address to check for active rentals.
* @returns True if the user has active rentals, false otherwise.
*/
async hasActiveRentals(user) {
return this.contract.hasActiveRentals(user);
}
// === Royalty Management ===
/**
* Sets mint royalties for the contract.
* @param royalties Array of RoyaltyData objects.
* @throws {Error} If caller doesn't have OWNER_ROLE.
*/
async setMintRoyalties(royalties, overrides = {}) {
this.requireSigner();
return this.contract.setMintRoyalties(royalties, overrides);
}
/**
* Sets transfer royalties for the contract.
* @param royalties Array of RoyaltyData objects.
* @throws {Error} If caller doesn't have OWNER_ROLE.
*/
async setTransferRoyalties(royalties, overrides = {}) {
this.requireSigner();
return this.contract.setTransferRoyalties(royalties, overrides);
}
/**
* Sets mint royalties for a specific token.
* @param tokenId The ID of the token to set royalties for.
* @param royalties Array of RoyaltyData objects.
* @throws {Error} If caller doesn't have OWNER_ROLE.
*/
async setTokenMintRoyalties(tokenId, royalties, overrides = {}) {
this.requireSigner();
return this.contract.setTokenMintRoyalties(tokenId, royalties, overrides);
}
/**
* Sets transfer royalties for a specific token.
* @param tokenId The ID of the token to set royalties for.
* @param royalties Array of RoyaltyData objects.
* @throws {Error} If caller doesn't have OWNER_ROLE.
*/
async setTokenTransferRoyalties(tokenId, royalties, overrides = {}) {
this.requireSigner();
return this.contract.setTokenTransferRoyalties(tokenId, royalties, overrides);
}
/**
* Gets mint royalty receivers for a token.
* @param tokenId The ID of the token to get royalty receivers for.
* @returns Array of RoyaltyData objects.
*/
async getMintRoyaltyReceivers(tokenId) {
const result = await this.contract.getMintRoyaltyReceivers(tokenId);
console.log('DEBUG: getMintRoyaltyReceivers result:', result);
console.log('DEBUG: result type:', typeof result);
console.log('DEBUG: result length:', result.length);
console.log('DEBUG: result[0]:', result[0]);
// Handle different possible response formats
if (Array.isArray(result)) {
if (result.length === 0) {
return [];
}
// Check if it's already in the expected format
if (typeof result[0] === 'object' && result[0].receiver) {
return result.map((item) => ({
receiver: item.receiver,
feeNumerator: BigInt(item.feeNumerator.toString()),
}));
}
// Try the split format: [receiver1, receiver2, ..., fee1, fee2, ...]
const halfLength = result.length / 2;
const receivers = result.slice(0, halfLength);
const fees = result.slice(halfLength);
return receivers.map((receiver, index) => ({
receiver,
feeNumerator: BigInt(fees[index].toString()),
}));
}
// Fallback: return empty array
return [];
}
/**
* Gets transfer royalty receivers for a token.
* @param tokenId The ID of the token to get royalty receivers for.
* @returns Array of RoyaltyData objects.
*/
async getTransferRoyaltyReceivers(tokenId) {
const result = await this.contract.getTransferRoyaltyReceivers(tokenId);
console.log('DEBUG: getTransferRoyaltyReceivers result:', result);
console.log('DEBUG: result type:', typeof result);
console.log('DEBUG: result length:', result.length);
console.log('DEBUG: result[0]:', result[0]);
// Handle different possible response formats
if (Array.isArray(result)) {
if (result.length === 0) {
return [];
}
// Check if it's already in the expected format
if (typeof result[0] === 'object' && result[0].receiver) {
return result.map((item) => ({
receiver: item.receiver,
feeNumerator: BigInt(item.feeNumerator.toString()),
}));
}
// Try the split format: [receiver1, receiver2, ..., fee1, fee2, ...]
const halfLength = result.length / 2;
const receivers = result.slice(0, halfLength);
const fees = result.slice(halfLength);
return receivers.map((receiver, index) => ({
receiver,
feeNumerator: BigInt(fees[index].toString()),
}));
}
// Fallback: return empty array
return [];
}
// === Configuration Functions ===
/**
* Sets the mint price for the contract.
* @param newMintPrice The new mint price in USDC.
* @throws {Error} If caller doesn't have OWNER_ROLE.
*/
async setMintPrice(newMintPrice, overrides = {}) {
this.requireSigner();
return this.contract.setMintPrice(newMintPrice, overrides);
}
/**
* Gets the current mint price.
* @returns The current mint price in USDC.
*/
async getMintPrice() {
const result = await this.contract.mintPrice();
return BigInt(result.toString());
}
/**
* Sets the platform commission percentage and address.
* @param newPercentage The new commission percentage in basis points.
* @param newPlatformAddress The new platform address.
* @throws {Error} If caller doesn't have OWNER_ROLE.
*/
async setPlatformCommission(newPercentage, newPlatformAddress, overrides = {}) {
this.requireSigner();
return this.contract.setPlatformCommission(newPercentage, newPlatformAddress, overrides);
}
/**
* Gets the platform address.
* @returns The platform address.
*/
async getPlatformAddress() {
return this.contract.platformAddress();
}
/**
* Gets the platform commission percentage.
* @returns The platform commission percentage in basis points.
*/
async getPlatformCommissionPercentage() {
const result = await this.contract.platformCommissionPercentage();
return BigInt(result.toString());
}
/**
* Sets the base URI for token metadata.
* @param baseURI The new base URI.
* @throws {Error} If caller doesn't have OWNER_ROLE.
*/
async setBaseURI(baseURI, overrides = {}) {
this.requireSigner();
return this.contract.setBaseURI(baseURI, overrides);
}
/**
* Gets the base URI for token metadata.
* @returns The base URI.
*/
async getBaseURI() {
return this.contract.getBaseURI();
}
/**
* Gets the USDC token address.
* @returns The USDC token address.
*/
async usdc() {
return this.contract.usdc();
}
// === Pausable Functions ===
/**
* Pauses the contract.
* @throws {Error} If caller doesn't have PAUSER_ROLE.
*/
async pause(overrides = {}) {
this.requireSigner();
return this.contract.pause(overrides);
}
/**
* Checks if the contract is paused.
* @returns True if the contract is paused, false otherwise.
*/
async paused() {
return this.contract.paused();
}
/**
* Unpauses the contract.
* @throws {Error} If caller doesn't have PAUSER_ROLE.
*/
async unpause(overrides = {}) {
this.requireSigner();
return this.contract.unpause(overrides);
}
// === Burning ===
/**
* Burns a token.
* @param tokenId The ID of the token to burn.
* @throws {Error} If caller is not owner nor approved.
*/
async burn(tokenId, overrides = {}) {
this.requireSigner();
return this.contract.burn(tokenId, overrides);
}
// === Access Control ===
/**
* Checks if an account has a specific role.
* @param role The role to check.
* @param account The account to check.
* @returns True if the account has the role, false otherwise.
*/
async hasRole(role, account) {
return this.contract.hasRole(role, account);
}
/**
* Gets the admin role for a specific role.
* @param role The role to get the admin for.
* @returns The admin role.
*/
async getRoleAdmin(role) {
return this.contract.getRoleAdmin(role);
}
/**
* Grants a role to an account.
* @param role The role to grant.
* @param account The account to grant the role to.
* @throws {Error} If caller doesn't have the admin role.
*/
async grantRole(role, account, overrides = {}) {
this.requireSigner();
return this.contract.grantRole(role, account, overrides);
}
/**
* Revokes a role from an account.
* @param role The role to revoke.
* @param account The account to revoke the role from.
* @throws {Error} If caller doesn't have the admin role.
*/
async revokeRole(role, account, overrides = {}) {
this.requireSigner();
return this.contract.revokeRole(role, account, overrides);
}
/**
* Renounces a role from the caller.
* @param role The role to renounce.
* @throws {Error} If caller doesn't have the role.
*/
async renounceRole(role, overrides = {}) {
this.requireSigner();
return this.contract.renounceRole(role, overrides);
}
// === Utility Methods ===
/**
* Requires that the current signerOrProvider is a Signer.
* @throws {Error} If the current signerOrProvider is not a Signer.
*/
requireSigner() {
if (!this.contract.signer) {
throw new Error('This operation requires a signer');
}
return this.contract.signer;
}
/**
* Requires that the caller has a specific role.
* @param role The role to check.
* @param errorMessage The error message to throw if the caller doesn't have the role.
* @throws {Error} If the caller doesn't have the role.
*/
async requireRole(role, errorMessage) {
const signer = this.requireSigner();
const signerAddress = await signer.getAddress();
const hasRole = await this.hasRole(role, signerAddress);
if (!hasRole) {
throw new Error(errorMessage || `Caller doesn't have role ${role}`);
}
}
/**
* Creates a new wrapper instance connected to a different signer or provider.
* @param signerOrProvider The new signer or provider to connect to.
* @returns A new KAMI721CWrapper instance.
*/
connect(signerOrProvider) {
return new KAMI721CWrapper(this.address, signerOrProvider, this.abi);
}
}
exports.KAMI721CWrapper = KAMI721CWrapper;
//# sourceMappingURL=KAMI721CWrapper.js.map