|
// story-protocol-sdk.ts |
|
|
|
import { ethers } from 'ethers'; |
|
|
|
// Types |
|
export interface SPGNFTConfig { |
|
address: string; |
|
provider: ethers.providers.Provider; |
|
} |
|
|
|
export interface WorkflowConfig { |
|
groupingWorkflowsAddress: string; |
|
licenseAttachmentWorkflowsAddress: string; |
|
registrationWorkflowsAddress: string; |
|
derivativeWorkflowsAddress: string; |
|
provider: ethers.providers.Provider; |
|
} |
|
|
|
export namespace WorkflowStructs { |
|
export interface IPMetadata { |
|
ipMetadataURI: string; |
|
ipMetadataHash: string; |
|
nftMetadataURI: string; |
|
nftMetadataHash: string; |
|
} |
|
|
|
export interface SignatureData { |
|
signer: string; |
|
deadline: ethers.BigNumber; |
|
signature: string; |
|
} |
|
|
|
export interface MakeDerivative { |
|
parentIpIds: string[]; |
|
licenseTemplate: string; |
|
licenseTermsIds: number[]; |
|
royaltyContext: string; |
|
} |
|
} |
|
|
|
export interface PILTerms { |
|
// Define the structure of PILTerms based on the smart contract |
|
[key: string]: any; |
|
} |
|
|
|
export const ADMIN_ROLE = ethers.utils.hexZeroPad('0x01', 32); |
|
export const MINTER_ROLE = ethers.utils.hexZeroPad('0x01', 32); |
|
|
|
// Errors |
|
export class StoryProtocolError extends Error { |
|
constructor(message: string) { |
|
super(message); |
|
this.name = 'StoryProtocolError'; |
|
} |
|
} |
|
|
|
export class SPGError extends StoryProtocolError { |
|
static CallerNotMinterRole = class extends SPGError { |
|
constructor() { |
|
super('Caller does not have the minter role'); |
|
} |
|
}; |
|
} |
|
|
|
export class RegistrationWorkflowsError extends StoryProtocolError { |
|
static ZeroAddressParam = class extends RegistrationWorkflowsError { |
|
constructor() { |
|
super('Zero address provided as a param to the RegistrationWorkflows'); |
|
} |
|
}; |
|
} |
|
|
|
export class LicenseAttachmentWorkflowsError extends StoryProtocolError { |
|
static ZeroAddressParam = class extends LicenseAttachmentWorkflowsError { |
|
constructor() { |
|
super('Zero address provided as a param to the LicenseAttachmentWorkflows'); |
|
} |
|
}; |
|
} |
|
|
|
export class DerivativeWorkflowsError extends StoryProtocolError { |
|
static ZeroAddressParam = class extends DerivativeWorkflowsError { |
|
constructor() { |
|
super('Zero address provided as a param to the DerivativeWorkflows'); |
|
} |
|
}; |
|
|
|
static EmptyLicenseTokens = class extends DerivativeWorkflowsError { |
|
constructor() { |
|
super('License token list is empty'); |
|
} |
|
}; |
|
|
|
static CallerAndNotTokenOwner = class extends DerivativeWorkflowsError { |
|
constructor(tokenId: string, caller: string, actualTokenOwner: string) { |
|
super(`Caller ${caller} is not the owner of the license token ${tokenId}. Actual owner: ${actualTokenOwner}`); |
|
} |
|
}; |
|
} |
|
|
|
export class GroupingWorkflowsError extends StoryProtocolError { |
|
static ZeroAddressParam = class extends GroupingWorkflowsError { |
|
constructor() { |
|
super('Zero address provided as a param to the GroupingWorkflows'); |
|
} |
|
}; |
|
} |
|
|
|
export class SPGNFTError extends StoryProtocolError { |
|
static ZeroAddressParam = class extends SPGNFTError { |
|
constructor() { |
|
super('Zero address provided as a param'); |
|
} |
|
}; |
|
|
|
static ZeroMaxSupply = class extends SPGNFTError { |
|
constructor() { |
|
super('Zero max supply provided'); |
|
} |
|
}; |
|
|
|
static MaxSupplyReached = class extends SPGNFTError { |
|
constructor() { |
|
super('Max mint supply reached'); |
|
} |
|
}; |
|
|
|
static MintingDenied = class extends SPGNFTError { |
|
constructor() { |
|
super('Minting is denied. Public minting is false and caller does not have the minter role'); |
|
} |
|
}; |
|
|
|
static CallerNotFeeRecipient = class extends SPGNFTError { |
|
constructor() { |
|
super('Caller is not the fee recipient'); |
|
} |
|
}; |
|
|
|
static MintingClosed = class extends SPGNFTError { |
|
constructor() { |
|
super('Minting is closed'); |
|
} |
|
}; |
|
|
|
static CallerNotPeripheryContract = class extends SPGNFTError { |
|
constructor() { |
|
super('Caller is not one of the periphery contracts'); |
|
} |
|
}; |
|
} |
|
|
|
// SPGNFT |
|
export class SPGNFT { |
|
private contract: ethers.Contract; |
|
|
|
constructor(address: string, signer: ethers.Signer) { |
|
this.contract = new ethers.Contract(address, [ |
|
'function initialize(string,string,uint32,uint256,address,address,address,bool,bool)', |
|
'function totalSupply() view returns (uint256)', |
|
'function mintFee() view returns (uint256)', |
|
'function mintFeeToken() view returns (address)', |
|
'function mintFeeRecipient() view returns (address)', |
|
'function mintOpen() view returns (bool)', |
|
'function publicMinting() view returns (bool)', |
|
'function setMintFee(uint256)', |
|
'function setMintFeeToken(address)', |
|
'function setMintFeeRecipient(address)', |
|
'function setMintOpen(bool)', |
|
'function setPublicMinting(bool)', |
|
'function mint(address,string) returns (uint256)', |
|
'function mintByPeriphery(address,address,string) returns (uint256)', |
|
'function withdrawToken(address)' |
|
], signer); |
|
} |
|
|
|
async initialize( |
|
name: string, |
|
symbol: string, |
|
maxSupply: number, |
|
mintFee: ethers.BigNumber, |
|
mintFeeToken: string, |
|
mintFeeRecipient: string, |
|
owner: string, |
|
mintOpen: boolean, |
|
isPublicMinting: boolean |
|
): Promise<void> { |
|
return this.contract.initialize(name, symbol, maxSupply, mintFee, mintFeeToken, mintFeeRecipient, owner, mintOpen, isPublicMinting); |
|
} |
|
|
|
async totalSupply(): Promise<number> { |
|
return this.contract.totalSupply(); |
|
} |
|
|
|
async mintFee(): Promise<ethers.BigNumber> { |
|
return this.contract.mintFee(); |
|
} |
|
|
|
async mintFeeToken(): Promise<string> { |
|
return this.contract.mintFeeToken(); |
|
} |
|
|
|
async mintFeeRecipient(): Promise<string> { |
|
return this.contract.mintFeeRecipient(); |
|
} |
|
|
|
async mintOpen(): Promise<boolean> { |
|
return this.contract.mintOpen(); |
|
} |
|
|
|
async publicMinting(): Promise<boolean> { |
|
return this.contract.publicMinting(); |
|
} |
|
|
|
async setMintFee(fee: ethers.BigNumber): Promise<void> { |
|
return this.contract.setMintFee(fee); |
|
} |
|
|
|
async setMintFeeToken(token: string): Promise<void> { |
|
return this.contract.setMintFeeToken(token); |
|
} |
|
|
|
async setMintFeeRecipient(newFeeRecipient: string): Promise<void> { |
|
try { |
|
return await this.contract.setMintFeeRecipient(newFeeRecipient); |
|
} catch (error) { |
|
if (error.message.includes('SPGNFT__CallerNotFeeRecipient')) { |
|
throw new SPGNFTError.CallerNotFeeRecipient(); |
|
} |
|
throw error; |
|
} |
|
} |
|
|
|
async setMintOpen(mintOpen: boolean): Promise<void> { |
|
return this.contract.setMintOpen(mintOpen); |
|
} |
|
|
|
async setPublicMinting(isPublicMinting: boolean): Promise<void> { |
|
return this.contract.setPublicMinting(isPublicMinting); |
|
} |
|
|
|
async mint(to: string, nftMetadataURI: string): Promise<ethers.ContractTransaction> { |
|
try { |
|
return await this.contract.mint(to, nftMetadataURI); |
|
} catch (error) { |
|
if (error.message.includes('SPGNFT__MintingDenied')) { |
|
throw new SPGNFTError.MintingDenied(); |
|
} |
|
if (error.message.includes('SPGNFT__MintingClosed')) { |
|
throw new SPGNFTError.MintingClosed(); |
|
} |
|
if (error.message.includes('SPGNFT__MaxSupplyReached')) { |
|
throw new SPGNFTError.MaxSupplyReached(); |
|
} |
|
throw error; |
|
} |
|
} |
|
|
|
async mintByPeriphery(to: string, payer: string, nftMetadataURI: string): Promise<ethers.ContractTransaction> { |
|
return this.contract.mintByPeriphery(to, payer, nftMetadataURI); |
|
} |
|
|
|
async withdrawToken(token: string): Promise<void> { |
|
return this.contract.withdrawToken(token); |
|
} |
|
} |
|
|
|
// Base Workflow |
|
export abstract class BaseWorkflow { |
|
protected contract: ethers.Contract; |
|
|
|
constructor(address: string, signer: ethers.Signer) { |
|
this.contract = new ethers.Contract(address, [], signer); |
|
} |
|
} |
|
|
|
// Registration Workflows |
|
export class RegistrationWorkflows extends BaseWorkflow { |
|
constructor(address: string, signer: ethers.Signer) { |
|
super(address, signer); |
|
this.contract = new ethers.Contract(address, [ |
|
'function createCollection(string,string,uint32,uint256,address,address,address,bool,bool) returns (address)', |
|
'function mintAndRegisterIp(address,address,tuple(string,bytes32,string,bytes32)) returns (address,uint256)', |
|
'function registerIp(address,uint256,tuple(string,bytes32,string,bytes32),tuple(address,uint256,bytes)) returns (address)' |
|
], signer); |
|
} |
|
|
|
async createCollection( |
|
name: string, |
|
symbol: string, |
|
maxSupply: number, |
|
mintFee: ethers.BigNumber, |
|
mintFeeToken: string, |
|
mintFeeRecipient: string, |
|
owner: string, |
|
mintOpen: boolean, |
|
isPublicMinting: boolean |
|
): Promise<string> { |
|
return this.contract.createCollection( |
|
name, |
|
symbol, |
|
maxSupply, |
|
mintFee, |
|
mintFeeToken, |
|
mintFeeRecipient, |
|
owner, |
|
mintOpen, |
|
isPublicMinting |
|
); |
|
} |
|
|
|
async mintAndRegisterIp( |
|
spgNftContract: string, |
|
recipient: string, |
|
ipMetadata: WorkflowStructs.IPMetadata |
|
): Promise<{ ipId: string; tokenId: number }> { |
|
const result = await this.contract.mintAndRegisterIp(spgNftContract, recipient, ipMetadata); |
|
return { ipId: result[0], tokenId: result[1].toNumber() }; |
|
} |
|
|
|
async registerIp( |
|
nftContract: string, |
|
tokenId: number, |
|
ipMetadata: WorkflowStructs.IPMetadata, |
|
sigMetadata: WorkflowStructs.SignatureData |
|
): Promise<string> { |
|
return this.contract.registerIp(nftContract, tokenId, ipMetadata, sigMetadata); |
|
} |
|
} |
|
|
|
// License Attachment Workflows |
|
export class LicenseAttachmentWorkflows extends BaseWorkflow { |
|
constructor(address: string, signer: ethers.Signer) { |
|
super(address, signer); |
|
this.contract = new ethers.Contract(address, [ |
|
'function registerPILTermsAndAttach(address,tuple) returns (uint256)', |
|
'function mintAndRegisterIpAndAttachPILTerms(address,address,tuple(string,bytes32,string,bytes32),tuple) returns (address,uint256,uint256)', |
|
'function registerIpAndAttachPILTerms(address,uint256,tuple(string,bytes32,string,bytes32),tuple,tuple(address,uint256,bytes),tuple(address,uint256,bytes)) returns (address,uint256)' |
|
], signer); |
|
} |
|
|
|
async registerPILTermsAndAttach(ipId: string, terms: PILTerms): Promise<number> { |
|
const result = await this.contract.registerPILTermsAndAttach(ipId, terms); |
|
return result.toNumber(); |
|
} |
|
|
|
async mintAndRegisterIpAndAttachPILTerms( |
|
spgNftContract: string, |
|
recipient: string, |
|
ipMetadata: WorkflowStructs.IPMetadata, |
|
terms: PILTerms |
|
): Promise<{ ipId: string; tokenId: number; licenseTermsId: number }> { |
|
const result = await this.contract.mintAndRegisterIpAndAttachPILTerms(spgNftContract, recipient, ipMetadata, terms); |
|
return { ipId: result[0], tokenId: result[1].toNumber(), licenseTermsId: result[2].toNumber() }; |
|
} |
|
|
|
async registerIpAndAttachPILTerms( |
|
nftContract: string, |
|
tokenId: number, |
|
ipMetadata: WorkflowStructs.IPMetadata, |
|
terms: PILTerms, |
|
sigMetadata: WorkflowStructs.SignatureData, |
|
sigAttach: WorkflowStructs.SignatureData |
|
): Promise<{ ipId: string; licenseTermsId: number }> { |
|
const result = await this.contract.registerIpAndAttachPILTerms(nftContract, tokenId, ipMetadata, terms, sigMetadata, sigAttach); |
|
return { ipId: result[0], licenseTermsId: result[1].toNumber() }; |
|
} |
|
} |
|
|
|
// Grouping Workflows |
|
export class GroupingWorkflows extends BaseWorkflow { |
|
constructor(address: string, signer: ethers.Signer) { |
|
super(address, signer); |
|
this.contract = new ethers.Contract(address, [ |
|
'function mintAndRegisterIpAndAttachLicenseAndAddToGroup(address,address,address,address,uint256,tuple(string,bytes32,string,bytes32),tuple(address,uint256,bytes)) returns (address,uint256)', |
|
'function registerIpAndAttachLicenseAndAddToGroup(address,uint256,address,address,uint256,tuple(string,bytes32,string,bytes32),tuple(address,uint256,bytes),tuple(address,uint256,bytes)) returns (address)', |
|
'function registerGroupAndAttachLicenseAndAddIps(address,address[],address,uint256) returns (address)' |
|
], signer); |
|
} |
|
|
|
async mintAndRegisterIpAndAttachLicenseAndAddToGroup( |
|
spgNftContract: string, |
|
groupId: string, |
|
recipient: string, |
|
licenseTemplate: string, |
|
licenseTermsId: number, |
|
ipMetadata: WorkflowStructs.IPMetadata, |
|
sigAddToGroup: WorkflowStructs.SignatureData |
|
): Promise<{ ipId: string; tokenId: number }> { |
|
const result = await this.contract.mintAndRegisterIpAndAttachLicenseAndAddToGroup( |
|
spgNftContract, |
|
groupId, |
|
recipient, |
|
licenseTemplate, |
|
licenseTermsId, |
|
ipMetadata, |
|
sigAddToGroup |
|
); |
|
return { ipId: result[0], tokenId: result[1].toNumber() }; |
|
} |
|
|
|
async registerIpAndAttachLicenseAndAddToGroup( |
|
nftContract: string, |
|
tokenId: number, |
|
groupId: string, |
|
licenseTemplate: string, |
|
licenseTermsId: number, |
|
ipMetadata: WorkflowStructs.IPMetadata, |
|
sigMetadataAndAttach: WorkflowStructs.SignatureData, |
|
sigAddToGroup: WorkflowStructs.SignatureData |
|
): Promise<string> { |
|
return this.contract.registerIpAndAttachLicenseAndAddToGroup( |
|
nftContract, |
|
tokenId, |
|
groupId, |
|
licenseTemplate, |
|
licenseTermsId, |
|
ipMetadata, |
|
sigMetadataAndAttach, |
|
sigAddToGroup |
|
); |
|
} |
|
|
|
async registerGroupAndAttachLicenseAndAddIps( |
|
groupPool: string, |
|
ipIds: string[], |
|
licenseTemplate: string, |
|
licenseTermsId: number |
|
): Promise<string> { |
|
return this.contract.registerGroupAndAttachLicenseAndAddIps( |
|
groupPool, |
|
ipIds, |
|
licenseTemplate, |
|
licenseTermsId |
|
); |
|
} |
|
} |
|
|
|
// Derivative Workflows |
|
export class DerivativeWorkflows extends BaseWorkflow { |
|
constructor(address: string, signer: ethers.Signer) { |
|
super(address, signer); |
|
this.contract = new ethers.Contract(address, [ |
|
'function mintAndRegisterIpAndMakeDerivative(address,tuple(address[],address,uint256[],bytes),tuple(string,bytes32,string,bytes32),address) returns (address,uint256)', |
|
'function registerIpAndMakeDerivative(address,uint256,tuple(address[],address,uint256[],bytes),tuple(string,bytes32,string,bytes32),tuple(address,uint256,bytes),tuple(address,uint256,bytes)) returns (address)', |
|
'function mintAndRegisterIpAndMakeDerivativeWithLicenseTokens(address,uint256[],bytes,tuple(string,bytes32,string,bytes32),address) returns (address,uint256)', |
|
'function registerIpAndMakeDerivativeWithLicenseTokens(address,uint256,uint256[],bytes,tuple(string,bytes32,string,bytes32),tuple(address,uint256,bytes),tuple(address,uint256,bytes)) returns (address)' |
|
], signer); |
|
} |
|
|
|
async mintAndRegisterIpAndMakeDerivative( |
|
spgNftContract: string, |
|
derivData: WorkflowStructs.MakeDerivative, |
|
ipMetadata: WorkflowStructs.IPMetadata, |
|
recipient: string |
|
): Promise<{ ipId: string; tokenId: number }> { |
|
try { |
|
const result = await this.contract.mintAndRegisterIpAndMakeDerivative( |
|
spgNftContract, |
|
derivData, |
|
ipMetadata, |
|
recipient |
|
); |
|
return { ipId: result[0], tokenId: result[1].toNumber() }; |
|
} catch (error) { |
|
if (error.message.includes('DerivativeWorkflows__ZeroAddressParam')) { |
|
throw new DerivativeWorkflowsError.ZeroAddressParam(); |
|
} |
|
throw error; |
|
} |
|
} |
|
|
|
async registerIpAndMakeDerivative( |
|
nftContract: string, |
|
tokenId: number, |
|
derivData: WorkflowStructs.MakeDerivative, |
|
ipMetadata: WorkflowStructs.IPMetadata, |
|
sigMetadata: WorkflowStructs.SignatureData, |
|
sigRegister: WorkflowStructs.SignatureData |
|
): Promise<string> { |
|
try { |
|
return await this.contract.registerIpAndMakeDerivative( |
|
nftContract, |
|
tokenId, |
|
derivData, |
|
ipMetadata, |
|
sigMetadata, |
|
sigRegister |
|
); |
|
} catch (error) { |
|
if (error.message.includes('DerivativeWorkflows__ZeroAddressParam')) { |
|
throw new DerivativeWorkflowsError.ZeroAddressParam(); |
|
} |
|
throw error; |
|
} |
|
} |
|
|
|
async mintAndRegisterIpAndMakeDerivativeWithLicenseTokens( |
|
spgNftContract: string, |
|
licenseTokenIds: number[], |
|
royaltyContext: string, |
|
ipMetadata: WorkflowStructs.IPMetadata, |
|
recipient: string |
|
): Promise<{ ipId: string; tokenId: number }> { |
|
try { |
|
const result = await this.contract.mintAndRegisterIpAndMakeDerivativeWithLicenseTokens( |
|
spgNftContract, |
|
licenseTokenIds, |
|
royaltyContext, |
|
ipMetadata, |
|
recipient |
|
); |
|
return { ipId: result[0], tokenId: result[1].toNumber() }; |
|
} catch (error) { |
|
if (error.message.includes('DerivativeWorkflows__EmptyLicenseTokens')) { |
|
throw new DerivativeWorkflowsError.EmptyLicenseTokens(); |
|
} |
|
if (error.message.includes('DerivativeWorkflows__CallerAndNotTokenOwner')) { |
|
const match = error.message.match(/(\d+), (0x[a-fA-F0-9]{40}), (0x[a-fA-F0-9]{40})/); |
|
if (match) { |
|
throw new DerivativeWorkflowsError.CallerAndNotTokenOwner(match[1], match[2], match[3]); |
|
} |
|
} |
|
throw error; |
|
} |
|
} |
|
|
|
async registerIpAndMakeDerivativeWithLicenseTokens( |
|
nftContract: string, |
|
tokenId: number, |
|
licenseTokenIds: number[], |
|
royaltyContext: string, |
|
ipMetadata: WorkflowStructs.IPMetadata, |
|
sigMetadata: WorkflowStructs.SignatureData, |
|
sigRegister: WorkflowStructs.SignatureData |
|
): Promise<string> { |
|
try { |
|
return await this.contract.registerIpAndMakeDerivativeWithLicenseTokens( |
|
nftContract, |
|
tokenId, |
|
licenseTokenIds, |
|
royaltyContext, |
|
ipMetadata, |
|
sigMetadata, |
|
sigRegister |
|
); |
|
} catch (error) { |
|
if (error.message.includes('DerivativeWorkflows__EmptyLicenseTokens')) { |
|
throw new DerivativeWorkflowsError.EmptyLicenseTokens(); |
|
} |
|
if (error.message.includes('DerivativeWorkflows__CallerAndNotTokenOwner')) { |
|
const match = error.message.match(/(\d+), (0x[a-fA-F0-9]{40}), (0x[a-fA-F0-9]{40})/); |
|
if (match) { |
|
throw new DerivativeWorkflowsError.CallerAndNotTokenOwner(match[1], match[2], match[3]); |
|
} |
|
} |
|
throw error; |
|
} |
|
} |
|
} |
|
|
|
// Helper functions |
|
export class PermissionHelper { |
|
static async setPermissionForModule( |
|
ipId: string, |
|
module: string, |
|
accessController: string, |
|
selector: string, |
|
sigData: WorkflowStructs.SignatureData, |
|
signer: ethers.Signer |
|
): Promise<ethers.ContractTransaction> { |
|
const ipAccount = new ethers.Contract(ipId, ['function executeWithSig(address,uint256,bytes,address,uint256,bytes)'], signer); |
|
return ipAccount.executeWithSig( |
|
accessController, |
|
0, |
|
ethers.utils.defaultAbiCoder.encode( |
|
['address', 'address', 'address', 'bytes4', 'uint8'], |
|
[ipId, await signer.getAddress(), module, selector, 1] // 1 represents AccessPermission.ALLOW |
|
), |
|
sigData.signer, |
|
sigData.deadline, |
|
sigData.signature |
|
); |
|
} |
|
|
|
static async setBatchPermissionForModules( |
|
ipId: string, |
|
accessController: string, |
|
modules: string[], |
|
selectors: string[], |
|
sigData: WorkflowStructs.SignatureData, |
|
signer: ethers.Signer |
|
): Promise<ethers.ContractTransaction> { |
|
const ipAccount = new ethers.Contract(ipId, ['function executeWithSig(address,uint256,bytes,address,uint256,bytes)'], signer); |
|
const permissionList = modules.map((module, index) => ({ |
|
ipAccount: ipId, |
|
signer: await signer.getAddress(), |
|
to: module, |
|
func: selectors[index], |
|
permission: 1 // AccessPermission.ALLOW |
|
})); |
|
return ipAccount.executeWithSig( |
|
accessController, |
|
0, |
|
ethers.utils.defaultAbiCoder.encode(['tuple(address,address,address,bytes4,uint8)[]'], [permissionList]), |
|
sigData.signer, |
|
sigData.deadline, |
|
sigData.signature |
|
); |
|
} |
|
} |
|
|
|
export class MetadataHelper { |
|
static async setMetadataWithSig( |
|
ipId: string, |
|
coreMetadataModule: string, |
|
accessController: string, |
|
ipMetadata: WorkflowStructs.IPMetadata, |
|
sigData: WorkflowStructs.SignatureData, |
|
signer: ethers.Signer |
|
): Promise<ethers.ContractTransaction> { |
|
if (sigData.signer !== ethers.constants.AddressZero && !sigData.deadline.isZero() && sigData.signature !== '0x') { |
|
await PermissionHelper.setPermissionForModule( |
|
ipId, |
|
coreMetadataModule, |
|
accessController, |
|
'0x12345678', // Replace with actual selector for setAll |
|
sigData, |
|
signer |
|
); |
|
} |
|
return this.setMetadata(ipId, coreMetadataModule, ipMetadata, signer); |
|
} |
|
|
|
static async setMetadata( |
|
ipId: string, |
|
coreMetadataModule: string, |
|
ipMetadata: WorkflowStructs.IPMetadata, |
|
signer: ethers.Signer |
|
): Promise<ethers.ContractTransaction> { |
|
const metadataModuleContract = new ethers.Contract( |
|
coreMetadataModule, |
|
['function setAll(address,string,bytes32,bytes32)'], |
|
signer |
|
); |
|
return metadataModuleContract.setAll( |
|
ipId, |
|
ipMetadata.ipMetadataURI, |
|
ipMetadata.ipMetadataHash, |
|
ipMetadata.nftMetadataHash |
|
); |
|
} |
|
} |
|
|
|
export class LicensingHelper { |
|
static async registerPILTermsAndAttach( |
|
ipId: string, |
|
pilTemplate: string, |
|
licensingModule: string, |
|
licenseRegistry: string, |
|
terms: PILTerms, |
|
signer: ethers.Signer |
|
): Promise<{ licenseTermsId: number; tx: ethers.ContractTransaction }> { |
|
const pilTemplateContract = new ethers.Contract( |
|
pilTemplate, |
|
['function registerLicenseTerms((uint256,string,string,uint256,uint256,bytes32,bytes32))'], |
|
signer |
|
); |
|
const licenseTermsId = await pilTemplateContract.callStatic.registerLicenseTerms(terms); |
|
const tx = await pilTemplateContract.registerLicenseTerms(terms); |
|
await this.attachLicenseTerms(ipId, licensingModule, licenseRegistry, pilTemplate, licenseTermsId, signer); |
|
return { licenseTermsId, tx }; |
|
} |
|
|
|
static async attachLicenseTerms( |
|
ipId: string, |
|
licensingModule: string, |
|
licenseRegistry: string, |
|
licenseTemplate: string, |
|
licenseTermsId: number, |
|
signer: ethers.Signer |
|
): Promise<ethers.ContractTransaction | undefined> { |
|
const licenseRegistryContract = new ethers.Contract( |
|
licenseRegistry, |
|
['function hasIpAttachedLicenseTerms(address,address,uint256)'], |
|
signer |
|
); |
|
const isAttached = await licenseRegistryContract.hasIpAttachedLicenseTerms(ipId, licenseTemplate, licenseTermsId); |
|
if (!isAttached) { |
|
const licensingModuleContract = new ethers.Contract( |
|
licensingModule, |
|
['function attachLicenseTerms(address,address,uint256)'], |
|
signer |
|
); |
|
return licensingModuleContract.attachLicenseTerms(ipId, licenseTemplate, licenseTermsId); |
|
} |
|
} |
|
} |
|
|
|
// Export all components |
|
export { |
|
SPGNFT, |
|
RegistrationWorkflows, |
|
LicenseAttachmentWorkflows, |
|
GroupingWorkflows, |
|
DerivativeWorkflows, |
|
PermissionHelper, |
|
MetadataHelper, |
|
LicensingHelper |
|
}; |