'use strict'; var viem = require('viem'); var trustedHintRegistry = require('@spherity/trusted-hint-registry'); function getDeployment(client, type) { const chainId = client.chain?.id; if (!chainId) { throw new Error(`No chainId found in provided readClient`); } const deployment = trustedHintRegistry.deployments.find((d) => d.chainId === chainId && d.type === type); if (!deployment) { throw new Error(`No deployment found for chainId ${chainId} and type ${type}`); } return deployment; } var SignedDataType = /* @__PURE__ */ ((SignedDataType2) => { SignedDataType2[SignedDataType2["SetHintSigned"] = 0] = "SetHintSigned"; SignedDataType2[SignedDataType2["SetHintSignedMetadata"] = 1] = "SetHintSignedMetadata"; SignedDataType2[SignedDataType2["SetHintsSigned"] = 2] = "SetHintsSigned"; SignedDataType2[SignedDataType2["SetHintsSignedMetadata"] = 3] = "SetHintsSignedMetadata"; SignedDataType2[SignedDataType2["SetHintDelegatedSigned"] = 4] = "SetHintDelegatedSigned"; SignedDataType2[SignedDataType2["SetHintDelegatedSignedMetadata"] = 5] = "SetHintDelegatedSignedMetadata"; SignedDataType2[SignedDataType2["SetHintsDelegatedSigned"] = 6] = "SetHintsDelegatedSigned"; SignedDataType2[SignedDataType2["SetHintsDelegatedSignedMetadata"] = 7] = "SetHintsDelegatedSignedMetadata"; SignedDataType2[SignedDataType2["AddListDelegateSigned"] = 8] = "AddListDelegateSigned"; SignedDataType2[SignedDataType2["RemoveListDelegateSigned"] = 9] = "RemoveListDelegateSigned"; SignedDataType2[SignedDataType2["SetListStatusSigned"] = 10] = "SetListStatusSigned"; SignedDataType2[SignedDataType2["SetListOwnerSigned"] = 11] = "SetListOwnerSigned"; SignedDataType2[SignedDataType2["SetMetadataSigned"] = 12] = "SetMetadataSigned"; SignedDataType2[SignedDataType2["SetMetadataDelegatedSigned"] = 13] = "SetMetadataDelegatedSigned"; return SignedDataType2; })(SignedDataType || {}); function getSignedDataType(type) { switch (type) { case 0 /* SetHintSigned */: return { SetHintSigned: [ { name: "namespace", type: "address" }, { name: "list", type: "bytes32" }, { name: "key", type: "bytes32" }, { name: "value", type: "bytes32" }, { name: "signer", type: "address" }, { name: "nonce", type: "uint256" } ] }; case 1 /* SetHintSignedMetadata */: return { SetHintSigned: [ { name: "namespace", type: "address" }, { name: "list", type: "bytes32" }, { name: "key", type: "bytes32" }, { name: "value", type: "bytes32" }, { name: "metadata", type: "bytes" }, { name: "signer", type: "address" }, { name: "nonce", type: "uint256" } ] }; case 2 /* SetHintsSigned */: return { SetHintsSigned: [ { name: "namespace", type: "address" }, { name: "list", type: "bytes32" }, { name: "keys", type: "bytes32[]" }, { name: "values", type: "bytes32[]" }, { name: "signer", type: "address" }, { name: "nonce", type: "uint256" } ] }; case 3 /* SetHintsSignedMetadata */: return { SetHintsSigned: [ { name: "namespace", type: "address" }, { name: "list", type: "bytes32" }, { name: "keys", type: "bytes32[]" }, { name: "values", type: "bytes32[]" }, { name: "metadata", type: "bytes[]" }, { name: "signer", type: "address" }, { name: "nonce", type: "uint256" } ] }; case 4 /* SetHintDelegatedSigned */: return { SetHintDelegatedSigned: [ { name: "namespace", type: "address" }, { name: "list", type: "bytes32" }, { name: "key", type: "bytes32" }, { name: "value", type: "bytes32" }, { name: "signer", type: "address" }, { name: "nonce", type: "uint256" } ] }; case 5 /* SetHintDelegatedSignedMetadata */: return { SetHintDelegatedSigned: [ { name: "namespace", type: "address" }, { name: "list", type: "bytes32" }, { name: "key", type: "bytes32" }, { name: "value", type: "bytes32" }, { name: "metadata", type: "bytes" }, { name: "signer", type: "address" }, { name: "nonce", type: "uint256" } ] }; case 6 /* SetHintsDelegatedSigned */: return { SetHintsDelegatedSigned: [ { name: "namespace", type: "address" }, { name: "list", type: "bytes32" }, { name: "keys", type: "bytes32[]" }, { name: "values", type: "bytes32[]" }, { name: "signer", type: "address" }, { name: "nonce", type: "uint256" } ] }; case 7 /* SetHintsDelegatedSignedMetadata */: return { SetHintsDelegatedSigned: [ { name: "namespace", type: "address" }, { name: "list", type: "bytes32" }, { name: "keys", type: "bytes32[]" }, { name: "values", type: "bytes32[]" }, { name: "metadata", type: "bytes[]" }, { name: "signer", type: "address" }, { name: "nonce", type: "uint256" } ] }; case 8 /* AddListDelegateSigned */: return { AddListDelegateSigned: [ { name: "namespace", type: "address" }, { name: "list", type: "bytes32" }, { name: "delegate", type: "address" }, { name: "untilTimestamp", type: "uint256" }, { name: "signer", type: "address" }, { name: "nonce", type: "uint256" } ] }; case 9 /* RemoveListDelegateSigned */: return { RemoveListDelegateSigned: [ { name: "namespace", type: "address" }, { name: "list", type: "bytes32" }, { name: "delegate", type: "address" }, { name: "signer", type: "address" }, { name: "nonce", type: "uint256" } ] }; case 10 /* SetListStatusSigned */: return { SetListStatusSigned: [ { name: "namespace", type: "address" }, { name: "list", type: "bytes32" }, { name: "revoked", type: "bool" }, { name: "signer", type: "address" }, { name: "nonce", type: "uint256" } ] }; case 11 /* SetListOwnerSigned */: return { SetListOwnerSigned: [ { name: "namespace", type: "address" }, { name: "list", type: "bytes32" }, { name: "newOwner", type: "address" }, { name: "signer", type: "address" }, { name: "nonce", type: "uint256" } ] }; case 12 /* SetMetadataSigned */: return { SetMetadataSigned: [ { name: "namespace", type: "address" }, { name: "list", type: "bytes32" }, { name: "key", type: "bytes32" }, { name: "value", type: "bytes32" }, { name: "metadata", type: "bytes" }, { name: "signer", type: "address" }, { name: "nonce", type: "uint256" } ] }; case 13 /* SetMetadataDelegatedSigned */: return { SetMetadataDelegatedSigned: [ { name: "namespace", type: "address" }, { name: "list", type: "bytes32" }, { name: "key", type: "bytes32" }, { name: "value", type: "bytes32" }, { name: "metadata", type: "bytes" }, { name: "signer", type: "address" }, { name: "nonce", type: "uint256" } ] }; default: throw new Error(`Unknown signed data type ${type}`); } } class TrustedHintControllerError extends Error { constructor(message) { super(message); this.name = this.constructor.name; Object.setPrototypeOf(this, new.target.prototype); } } class ClientNotSetError extends TrustedHintControllerError { constructor(clientType) { super(`${clientType} must be set and properly configured.`); } } class ClientMisconfiguredError extends TrustedHintControllerError { constructor(message) { super(message); } } class NotOwnerError extends TrustedHintControllerError { constructor(clientType) { super(`Provided ${clientType} must be the owner of the namespace.`); } } class NotDelegateError extends TrustedHintControllerError { constructor(clientType) { super(`Provided ${clientType} must be a delegate of the namespace.`); } } class HintSetError extends TrustedHintControllerError { constructor(message) { super(`Failed to set hint: ${message}`); } } class DelegateManagementError extends TrustedHintControllerError { constructor(action, message) { super(`Failed to ${action} list delegate: ${message}`); } } class ListStatusError extends TrustedHintControllerError { constructor(message) { super(`Failed to set list status: ${message}`); } } class ListOwnerError extends TrustedHintControllerError { constructor(message) { super(`Failed to set list owner: ${message}`); } } class MetadataOperationError extends TrustedHintControllerError { constructor(message) { super(`Failed to set metadata: ${message}`); } } class TrustedHintController { readClient; walletClient; metaTransactionWalletClient; contract; constructor(config) { let deploymentAddress; this.readClient = config.readClient; this.walletClient = config.walletClient; this.metaTransactionWalletClient = config.metaTransactionWalletClient; if (!this.readClient && !this.walletClient) { throw new ClientNotSetError("WalletClient or ReadClient"); } if (!config.registryAddress) { const deployment = getDeployment(this.readClient ?? this.walletClient, "proxy"); deploymentAddress = deployment.registry; } else { deploymentAddress = config.registryAddress; } this.contract = viem.getContract({ address: deploymentAddress, abi: trustedHintRegistry.TRUSTED_HINT_REGISTRY_ABI, client: this.readClient ?? this.walletClient }); } async getEIP712Domain() { if (!this.metaTransactionWalletClient?.chain) { throw new ClientMisconfiguredError(`WalletClient must have a chain set.`); } return { name: "TrustedHintRegistry", version: await this.contract.read.version(), chainId: this.metaTransactionWalletClient?.chain?.id, verifyingContract: this.contract.address }; } /** * Returns the hint value for the given namespace, list and key. * @param namespace The namespace of the hint. * @param list The list of the hint. * @param key The key of the hint. * @returns The transaction hash of the meta transaction. */ async getHint(namespace, list, key) { return this.contract.read.getHint([ namespace, list, key ]); } /** * Sets the hint value for the given namespace, list and key. Optionally, a metadata value can be provided. * * This is a write operation and requires a wallet client to be set. * @param namespace The namespace of the hint. * @param list The list of the hint. * @param key The key of the hint. * @param value The value of the hint. * @param [metadata] The optional metadata value of the hint. * @returns The transaction hash of the meta transaction. */ async setHint(namespace, list, key, value, metadata) { if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } try { const isOwner = await this.isListOwner(namespace, list, this.walletClient.account.address); if (!isOwner) { throw new NotOwnerError("WalletClient"); } if (metadata) { return this.contract.write.setHint([namespace, list, key, value, metadata], { chain: this.walletClient.chain, account: this.walletClient.account }); } else { return this.contract.write.setHint([namespace, list, key, value], { chain: this.walletClient.chain, account: this.walletClient.account }); } } catch (e) { throw new HintSetError(e.message); } } /** * Sets the hint value for the given namespace, list and key via a meta transaction. Optionally, a metadata value can * be provided. * * This is a write operation and requires a wallet client and a meta transaction wallet client to be set. The meta * transaction wallet client provides a signed EIP712 signature to the wallet client to carry out the transaction for * it. * @param namespace The namespace of the hint. * @param list The list of the hint. * @param key The key of the hint. * @param value The value of the hint. * @param [metadata] The optional metadata value of the hint. * @returns The transaction hash of the meta transaction. */ async setHintSigned(namespace, list, key, value, metadata) { if (!this.metaTransactionWalletClient || !this.metaTransactionWalletClient.account) { throw new ClientNotSetError("MetaTransactionWalletClient"); } if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } if (this.metaTransactionWalletClient.chain?.id != this.walletClient.chain?.id) { throw new ClientMisconfiguredError(`Provided WalletClient and MetaTransactionWalletClient must be on the same chain.`); } try { const metaSigner = this.metaTransactionWalletClient.account; const signerIsOwner = await this.isListOwner(namespace, list, metaSigner.address); if (!signerIsOwner) { throw new NotOwnerError("MetaTransactionWalletClient"); } const signerNonce = await this.contract.read.nonces([metaSigner.address]); const type = metadata ? getSignedDataType(SignedDataType.SetHintSignedMetadata) : getSignedDataType(SignedDataType.SetHintSigned); const message = metadata ? { namespace, list, key, value, metadata, signer: metaSigner.address, nonce: signerNonce } : { namespace, list, key, value, signer: metaSigner.address, nonce: signerNonce }; const domain = await this.getEIP712Domain(); const signature = await this.metaTransactionWalletClient.signTypedData({ account: metaSigner, domain, types: type, primaryType: "SetHintSigned", message }); if (metadata) { return this.contract.write.setHintSigned( [namespace, list, key, value, metadata, metaSigner.address, signature], { chain: this.walletClient.chain, account: this.walletClient.account } ); } else { return this.contract.write.setHintSigned( [namespace, list, key, value, metaSigner.address, signature], { chain: this.walletClient.chain, account: this.walletClient.account } ); } } catch (e) { throw new HintSetError(`Failed to set hint signed: ${e.message}`); } } /** * Batch sets the hint values for the given namespace, list and keys. Optionally, an array of metadata values can be * provided. * * This is a write operation and requires a wallet client. * @param namespace The namespace of the hint. * @param list The list of the hint. * @param keys The keys of the hint. * @param values The values of the hint. * @param [metadata] The optional metadata values of the hint. * @returns The transaction hash of the meta transaction. */ async setHints(namespace, list, keys, values, metadata) { if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } try { const isOwner = await this.isListOwner(namespace, list, this.walletClient.account.address); if (!isOwner) { throw new NotOwnerError("WalletClient"); } if (metadata) { return this.contract.write.setHints([namespace, list, keys, values, metadata], { chain: this.walletClient.chain, account: this.walletClient.account }); } else { return this.contract.write.setHints([namespace, list, keys, values], { chain: this.walletClient.chain, account: this.walletClient.account }); } } catch (e) { throw new HintSetError(`Failed to set hints: ${e.message}`); } } /** * Batch sets the hint values for the given namespace, list and keys via a meta transaction. Optionally, an array of * metadata values can be provided. * * This is a write operation and requires a wallet client and a meta transaction wallet client to be set. The meta * transaction wallet client provides a signed EIP712 signature to the wallet client to carry out the transaction for * it. * @param namespace The namespace of the hint. * @param list The list of the hint. * @param keys The keys of the hint. * @param values The values of the hint. * @param [metadata] The optional metadata values of the hint. * @returns The transaction hash of the meta transaction. */ async setHintsSigned(namespace, list, keys, values, metadata) { if (!this.metaTransactionWalletClient || !this.metaTransactionWalletClient.account) { throw new ClientNotSetError("MetaTransactionWalletClient"); } if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } if (this.metaTransactionWalletClient.chain?.id != this.walletClient.chain?.id) { throw new ClientMisconfiguredError(`Provided WalletClient and MetaTransactionWalletClient must be on the same chain.`); } try { const metaSigner = this.metaTransactionWalletClient.account; const signerIsOwner = await this.isListOwner(namespace, list, metaSigner.address); if (!signerIsOwner) { throw new NotOwnerError("MetaTransactionWalletClient"); } const signerNonce = await this.contract.read.nonces([metaSigner.address]); const type = metadata ? getSignedDataType(SignedDataType.SetHintsSignedMetadata) : getSignedDataType(SignedDataType.SetHintsSigned); const message = metadata ? { namespace, list, keys, values, metadata, signer: metaSigner.address, nonce: signerNonce } : { namespace, list, keys, values, signer: metaSigner.address, nonce: signerNonce }; const domain = await this.getEIP712Domain(); const signature = await this.metaTransactionWalletClient.signTypedData({ account: metaSigner, domain, types: type, primaryType: "SetHintsSigned", message }); if (metadata) { return this.contract.write.setHintsSigned( [namespace, list, keys, values, metadata, metaSigner.address, signature], { chain: this.walletClient.chain, account: this.walletClient.account } ); } else { return this.contract.write.setHintsSigned( [namespace, list, keys, values, metaSigner.address, signature], { chain: this.walletClient.chain, account: this.walletClient.account } ); } } catch (e) { throw new HintSetError(`Failed to set hints signed: ${e.message}`); } } /** * Sets the hint value for the given namespace, list and key as a delegate. Optionally, a metadata value can be * provided. * * This is a write operation and requires a wallet client to be set. The wallet client must be a delegate of the * namespace. * @param namespace The namespace of the hint. * @param list The list of the hint. * @param key The key of the hint. * @param value The value of the hint. * @param [metadata] The optional metadata value of the hint. * @returns The transaction hash of the meta transaction. */ async setHintDelegated(namespace, list, key, value, metadata) { if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } try { const isDelegate = await this.isListDelegate(namespace, list, this.walletClient.account.address); if (!isDelegate) { throw new NotDelegateError("WalletClient"); } if (metadata) { return this.contract.write.setHintDelegated([namespace, list, key, value, metadata], { chain: this.walletClient.chain, account: this.walletClient.account }); } else { return this.contract.write.setHintDelegated([namespace, list, key, value], { chain: this.walletClient.chain, account: this.walletClient.account }); } } catch (e) { throw new HintSetError(`Failed to set hint delegated: ${e.message}`); } } /** * Sets the hint value for the given namespace, list and key as a delegate via a meta transaction. Optionally, a * metadata value can be provided. * * This is a write operation and requires a wallet client and a meta transaction wallet client to be set. The meta * transaction wallet client provides a signed EIP712 signature to the wallet client to carry out the transaction for * it. * @param namespace The namespace of the hint. * @param list The list of the hint. * @param key The key of the hint. * @param value The value of the hint. * @param [metadata] The optional metadata value of the hint. * @returns The transaction hash of the meta transaction. */ async setHintDelegatedSigned(namespace, list, key, value, metadata) { if (!this.metaTransactionWalletClient || !this.metaTransactionWalletClient.account) { throw new ClientNotSetError("MetaTransactionWalletClient"); } if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } if (this.metaTransactionWalletClient.chain?.id != this.walletClient.chain?.id) { throw new ClientMisconfiguredError(`Provided WalletClient and MetaTransactionWalletClient must be on the same chain.`); } try { const metaSigner = this.metaTransactionWalletClient.account; const signerIsDelegate = await this.isListDelegate(namespace, list, metaSigner.address); if (!signerIsDelegate) { throw new NotDelegateError("MetaTransactionWalletClient"); } const signerNonce = await this.contract.read.nonces([metaSigner.address]); const type = metadata ? getSignedDataType(SignedDataType.SetHintDelegatedSignedMetadata) : getSignedDataType(SignedDataType.SetHintDelegatedSigned); const message = metadata ? { namespace, list, key, value, metadata, signer: metaSigner.address, nonce: signerNonce } : { namespace, list, key, value, signer: metaSigner.address, nonce: signerNonce }; const domain = await this.getEIP712Domain(); const signature = await this.metaTransactionWalletClient.signTypedData({ account: metaSigner, domain, types: type, primaryType: "SetHintDelegatedSigned", message }); if (metadata) { return this.contract.write.setHintDelegatedSigned( [namespace, list, key, value, metadata, metaSigner.address, signature], { chain: this.walletClient.chain, account: this.walletClient.account } ); } else { return this.contract.write.setHintDelegatedSigned( [namespace, list, key, value, metaSigner.address, signature], { chain: this.walletClient.chain, account: this.walletClient.account } ); } } catch (e) { throw new HintSetError(`Failed to set hint delegate signed: ${e.message}`); } } /** * Batch sets the hint values for the given namespace, list and keys as a delegate. Optionally, an array of metadata * values can be provided. * * This is a write operation and requires a wallet client to be set. The wallet client must be a delegate of the * namespace. * @param namespace The namespace of the hint. * @param list The list of the hint. * @param keys The keys of the hint. * @param values The values of the hint. * @param [metadata] The optional metadata values of the hint. * @returns The transaction hash of the meta transaction. */ async setHintsDelegated(namespace, list, keys, values, metadata) { if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } try { const isDelegate = await this.isListDelegate(namespace, list, this.walletClient.account.address); if (!isDelegate) { throw new NotDelegateError("WalletClient"); } if (metadata) { return this.contract.write.setHintsDelegated([namespace, list, keys, values, metadata], { chain: this.walletClient.chain, account: this.walletClient.account }); } else { return this.contract.write.setHintsDelegated([namespace, list, keys, values], { chain: this.walletClient.chain, account: this.walletClient.account }); } } catch (e) { throw new HintSetError(`Failed to set hints delegated: ${e.message}`); } } /** * Batch sets the hint values for the given namespace, list and keys as a delegate via a meta transaction. Optionally, * an array of metadata values can be provided. * * This is a write operation and requires a wallet client and a meta transaction wallet client to be set. The meta * transaction wallet client provides a signed EIP712 signature to the wallet client to carry out the transaction for * it. * @param namespace The namespace of the hint. * @param list The list of the hint. * @param keys The keys of the hint. * @param values The values of the hint. * @param [metadata] The optional metadata values of the hint. */ async setHintsDelegatedSigned(namespace, list, keys, values, metadata) { if (!this.metaTransactionWalletClient || !this.metaTransactionWalletClient.account) { throw new ClientNotSetError(`MetaTransactionWalletClient`); } if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } if (this.metaTransactionWalletClient.chain?.id != this.walletClient.chain?.id) { throw new ClientMisconfiguredError(`Provided WalletClient and MetaTransactionWalletClient must be on the same chain.`); } try { const metaSigner = this.metaTransactionWalletClient.account; const signerIsDelegate = await this.isListDelegate(namespace, list, metaSigner.address); if (!signerIsDelegate) { throw new NotDelegateError("MetaTransactionWalletClient"); } const signerNonce = await this.contract.read.nonces([metaSigner.address]); const type = metadata ? getSignedDataType(SignedDataType.SetHintsDelegatedSignedMetadata) : getSignedDataType(SignedDataType.SetHintsDelegatedSigned); const message = metadata ? { namespace, list, keys, values, metadata, signer: metaSigner.address, nonce: signerNonce } : { namespace, list, keys, values, signer: metaSigner.address, nonce: signerNonce }; const domain = await this.getEIP712Domain(); const signature = await this.metaTransactionWalletClient.signTypedData({ account: metaSigner, domain, types: type, primaryType: "SetHintsDelegatedSigned", message }); if (metadata) { return this.contract.write.setHintsDelegatedSigned( [namespace, list, keys, values, metadata, metaSigner.address, signature], { chain: this.walletClient.chain, account: this.walletClient.account } ); } else { return this.contract.write.setHintsDelegatedSigned( [namespace, list, keys, values, metaSigner.address, signature], { chain: this.walletClient.chain, account: this.walletClient.account } ); } } catch (e) { throw new HintSetError(`Failed to set hints delegate signed: ${e.message}`); } } ///////////////////////////////////////// LIST MANAGEMENT ///////////////////////////////////////// /** * Check the delegate status of an address in a list. * @param namespace The namespace of the list. * @param list The list. * @param delegate The delegate in question. * @returns A boolean indicating whether the given address is a delegate of the given list in the namespace. */ async isListDelegate(namespace, list, delegate) { return this.contract.read.identityIsDelegate([namespace, list, delegate]); } /** * Check the owner status of an address in a list. * @param namespace The namespace of the list. * @param list The list. * @param owner The owner in question. * @returns A boolean indicating whether the given address is the owner of the given list in the namespace. */ async isListOwner(namespace, list, owner) { return this.contract.read.identityIsOwner([namespace, list, owner]); } /** * Check if a list is revoked. * @param namespace The namespace of the list. * @param list The list. * @returns A boolean indicating whether the given list is revoked in the namespace. */ async isListRevoked(namespace, list) { const listLocationHash = viem.keccak256(viem.encodePacked(["address", "bytes32"], [namespace, list])); return this.contract.read.revokedLists([listLocationHash]); } /** * Add a delegate to a list. * @param namespace The namespace of the list. * @param list The list. * @param delegate The delegate to add. * @param delegateUntil The timestamp until which the delegate is valid. * @returns The transaction hash of the meta transaction. */ async addListDelegate(namespace, list, delegate, delegateUntil) { if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } try { const isOwner = await this.isListOwner(namespace, list, this.walletClient.account.address); if (!isOwner) { throw new NotOwnerError("WalletClient"); } return this.contract.write.addListDelegate([namespace, list, delegate, BigInt(delegateUntil)], { chain: this.walletClient.chain, account: this.walletClient.account }); } catch (e) { throw new DelegateManagementError("add", e.message); } } /** * Add a delegate to a list via a meta transaction. * * This is a write operation and requires a wallet client and a meta transaction wallet client to be set. The meta * transaction wallet client provides a signed EIP712 signature to the wallet client to carry out the transaction for * it. * @param namespace The namespace of the list. * @param list The list. * @param delegate The delegate to add. * @param delegateUntil The timestamp until which the delegate is valid. * @returns The transaction hash of the meta transaction. */ async addListDelegateSigned(namespace, list, delegate, delegateUntil) { if (!this.metaTransactionWalletClient || !this.metaTransactionWalletClient.account) { throw new ClientNotSetError("MetaTransactionWalletClient"); } if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } if (this.metaTransactionWalletClient.chain?.id != this.walletClient.chain?.id) { throw new ClientMisconfiguredError(`Provided WalletClient and MetaTransactionWalletClient must be on the same chain.`); } try { const metaSigner = this.metaTransactionWalletClient.account; const signerIsOwner = await this.isListOwner(namespace, list, metaSigner.address); if (!signerIsOwner) { throw new NotOwnerError("MetaTransactionWalletClient"); } const signerNonce = await this.contract.read.nonces([metaSigner.address]); const type = getSignedDataType(SignedDataType.AddListDelegateSigned); const message = { namespace, list, delegate, untilTimestamp: delegateUntil, signer: metaSigner.address, nonce: signerNonce }; const domain = await this.getEIP712Domain(); const signature = await this.metaTransactionWalletClient.signTypedData({ account: metaSigner, domain, types: type, primaryType: "AddListDelegateSigned", message }); return this.contract.write.addListDelegateSigned( [namespace, list, delegate, BigInt(delegateUntil), metaSigner.address, signature], { chain: this.walletClient.chain, account: this.walletClient.account } ); } catch (e) { throw new DelegateManagementError("add", e.message); } } /** * Remove a delegate from a list. * @param namespace The namespace of the list. * @param list The list. * @param delegate The delegate to remove. * @returns The transaction hash of the meta transaction. */ async removeListDelegate(namespace, list, delegate) { if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } try { const isOwner = await this.isListOwner(namespace, list, this.walletClient.account.address); if (!isOwner) { throw new NotOwnerError("WalletClient"); } return this.contract.write.removeListDelegate([namespace, list, delegate], { chain: this.walletClient.chain, account: this.walletClient.account }); } catch (e) { throw new DelegateManagementError("remove", e.message); } } /** * Remove a delegate from a list via a meta transaction. * * This is a write operation and requires a wallet client and a meta transaction wallet client to be set. The meta * transaction wallet client provides a signed EIP712 signature to the wallet client to carry out the transaction for * it. * @param namespace The namespace of the list. * @param list The list. * @param delegate The delegate to remove. * @returns The transaction hash of the meta transaction. */ async removeListDelegateSigned(namespace, list, delegate) { if (!this.metaTransactionWalletClient || !this.metaTransactionWalletClient.account) { throw new ClientNotSetError("MetaTransactionWalletClient"); } if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } if (this.metaTransactionWalletClient.chain?.id != this.walletClient.chain?.id) { throw new ClientMisconfiguredError(`Provided WalletClient and MetaTransactionWalletClient must be on the same chain.`); } try { const metaSigner = this.metaTransactionWalletClient.account; const signerIsOwner = await this.isListOwner(namespace, list, metaSigner.address); if (!signerIsOwner) { throw new NotOwnerError("MetaTransactionWalletClient"); } const signerNonce = await this.contract.read.nonces([metaSigner.address]); const type = getSignedDataType(SignedDataType.RemoveListDelegateSigned); const message = { namespace, list, delegate, signer: metaSigner.address, nonce: signerNonce }; const domain = await this.getEIP712Domain(); const signature = await this.metaTransactionWalletClient.signTypedData({ account: metaSigner, domain, types: type, primaryType: "RemoveListDelegateSigned", message }); return this.contract.write.removeListDelegateSigned( [namespace, list, delegate, metaSigner.address, signature], { chain: this.walletClient.chain, account: this.walletClient.account } ); } catch (e) { throw new DelegateManagementError("remove", e.message); } } /** * Set the status of a list. If revoked is true, the list is revoked. If revoked is false, the list is active. * * This is a write operation and requires a wallet client to be set. The wallet client must be the owner of the * namespace. * @param namespace The namespace of the list. * @param list The list. * @param revoked The new status of the list. * @returns The transaction hash of the meta transaction. */ async setListStatus(namespace, list, revoked) { if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } try { const isOwner = await this.isListOwner(namespace, list, this.walletClient.account.address); if (!isOwner) { throw new NotOwnerError("WalletClient"); } return this.contract.write.setListStatus([namespace, list, revoked], { chain: this.walletClient.chain, account: this.walletClient.account }); } catch (e) { throw new ListStatusError(e.message); } } /** * Set the status of a list via a meta transaction. If revoked is true, the list is revoked. If revoked is false, the * list is active. * * This is a write operation and requires a wallet client and a meta transaction wallet client to be set. The meta * transaction wallet client provides a signed EIP712 signature to the wallet client to carry out the transaction for * it. * @param namespace The namespace of the list. * @param list The list. * @param revoked The new status of the list. * @returns The transaction hash of the meta transaction. */ async setListStatusSigned(namespace, list, revoked) { if (!this.metaTransactionWalletClient || !this.metaTransactionWalletClient.account) { throw new ClientNotSetError("MetaTransactionWalletClient"); } if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } if (this.metaTransactionWalletClient.chain?.id != this.walletClient.chain?.id) { throw new ClientMisconfiguredError(`Provided WalletClient and MetaTransactionWalletClient must be on the same chain.`); } try { const metaSigner = this.metaTransactionWalletClient.account; const signerIsOwner = await this.isListOwner(namespace, list, metaSigner.address); if (!signerIsOwner) { throw new NotOwnerError("MetaTransactionWalletClient"); } const signerNonce = await this.contract.read.nonces([metaSigner.address]); const type = getSignedDataType(SignedDataType.SetListStatusSigned); const message = { namespace, list, revoked, signer: metaSigner.address, nonce: signerNonce }; const domain = await this.getEIP712Domain(); const signature = await this.metaTransactionWalletClient.signTypedData({ account: metaSigner, domain, types: type, primaryType: "SetListStatusSigned", message }); return this.contract.write.setListStatusSigned( [namespace, list, revoked, metaSigner.address, signature], { chain: this.walletClient.chain, account: this.walletClient.account } ); } catch (e) { throw new ListStatusError(e.message); } } /** * Set the owner of a list. * * This is a write operation and requires a wallet client to be set. The wallet client must be the owner of the * namespace. * @param namespace The namespace of the list. * @param list The list. * @param newOwner The new owner of the list. * @returns The transaction hash of the meta transaction. */ async setListOwner(namespace, list, newOwner) { if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } try { const isOwner = await this.isListOwner(namespace, list, this.walletClient.account.address); if (!isOwner) { throw new NotOwnerError("WalletClient"); } return this.contract.write.setListOwner([namespace, list, newOwner], { chain: this.walletClient.chain, account: this.walletClient.account }); } catch (e) { throw new ListOwnerError(e.message); } } /** * Set a new owner of a list via a meta transaction. * * This is a write operation and requires a wallet client and a meta transaction wallet client to be set. The meta * transaction wallet client provides a signed EIP712 signature to the wallet client to carry out the transaction for * it. * @param namespace The namespace of the list. * @param list The list. * @param newOwner The new owner of the list. * @returns The transaction hash of the meta transaction. */ async setListOwnerSigned(namespace, list, newOwner) { if (!this.metaTransactionWalletClient || !this.metaTransactionWalletClient.account) { throw new ClientNotSetError("MetaTransactionWalletClient"); } if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } if (this.metaTransactionWalletClient.chain?.id != this.walletClient.chain?.id) { throw new ClientMisconfiguredError(`Provided WalletClient and MetaTransactionWalletClient must be on the same chain.`); } try { const metaSigner = this.metaTransactionWalletClient.account; const signerIsOwner = await this.isListOwner(namespace, list, metaSigner.address); if (!signerIsOwner) { throw new NotOwnerError("MetaTransactionWalletClient"); } const signerNonce = await this.contract.read.nonces([metaSigner.address]); const type = getSignedDataType(SignedDataType.SetListOwnerSigned); const message = { namespace, list, newOwner, signer: metaSigner.address, nonce: signerNonce }; const domain = await this.getEIP712Domain(); const signature = await this.metaTransactionWalletClient.signTypedData({ account: metaSigner, domain, types: type, primaryType: "SetListOwnerSigned", message }); return this.contract.write.setListOwnerSigned( [namespace, list, newOwner, metaSigner.address, signature], { chain: this.walletClient.chain, account: this.walletClient.account } ); } catch (e) { throw new ListOwnerError(e.message); } } ///////////////////////////////////////// METADATA MANAGEMENT ///////////////////////////////////////// /** * Returns the metadata value for the given namespace, list, key and value combination. * @param namespace The namespace of the metadata. * @param list The list of the metadata. * @param key The key of the metadata. * @param value The value of the metadata. * @returns The raw bytes metadata value. */ async getMetadata(namespace, list, key, value) { return this.contract.read.getMetadata([ namespace, list, key, value ]); } /** * Sets the metadata value for the given namespace, list, key and value combination. * * This is a write operation and requires a wallet client to be set. The wallet client must be the owner of the * namespace. * @param namespace The namespace of the metadata. * @param list The list of the metadata. * @param key The key of the metadata. * @param value The value of the metadata. * @param metadata The metadata value. * @returns The transaction hash of the meta transaction. */ async setMetadata(namespace, list, key, value, metadata) { if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } try { const isOwner = await this.isListOwner(namespace, list, this.walletClient.account.address); if (!isOwner) { throw new NotOwnerError("WalletClient"); } return this.contract.write.setMetadata([namespace, list, key, value, metadata], { chain: this.walletClient.chain, account: this.walletClient.account }); } catch (e) { throw new MetadataOperationError(e.message); } } /** * Sets the metadata value for the given namespace, list, key and value combination via a meta transaction. * * This is a write operation and requires a wallet client and a meta transaction wallet client to be set. The meta * transaction wallet client provides a signed EIP712 signature to the wallet client to carry out the transaction for * it. * @param namespace The namespace of the metadata. * @param list The list of the metadata. * @param key The key of the metadata. * @param value The value of the metadata. * @param metadata The metadata value. * @returns The transaction hash of the meta transaction. */ async setMetadataSigned(namespace, list, key, value, metadata) { if (!this.metaTransactionWalletClient || !this.metaTransactionWalletClient.account) { throw new ClientNotSetError("MetaTransactionWalletClient"); } if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } if (this.metaTransactionWalletClient.chain?.id != this.walletClient.chain?.id) { throw new ClientMisconfiguredError(`Provided WalletClient and MetaTransactionWalletClient must be on the same chain.`); } try { const metaSigner = this.metaTransactionWalletClient.account; const signerIsOwner = await this.isListOwner(namespace, list, metaSigner.address); if (!signerIsOwner) { throw new NotOwnerError("MetaTransactionWalletClient"); } const signerNonce = await this.contract.read.nonces([metaSigner.address]); const type = getSignedDataType(SignedDataType.SetMetadataSigned); const message = { namespace, list, key, value, metadata, signer: metaSigner.address, nonce: signerNonce }; const domain = await this.getEIP712Domain(); const signature = await this.metaTransactionWalletClient.signTypedData({ account: metaSigner, domain, types: type, primaryType: "SetMetadataSigned", message }); return this.contract.write.setMetadataSigned( [namespace, list, key, value, metadata, metaSigner.address, signature], { chain: this.walletClient.chain, account: this.walletClient.account } ); } catch (e) { throw new MetadataOperationError(e.message); } } /** * Sets the metadata value for the given namespace, list, key and value combination as a delegate. * * This is a write operation and requires a wallet client to be set. The wallet client must be a delegate of the * namespace. * @param namespace The namespace of the metadata. * @param list The list of the metadata. * @param key The key of the metadata. * @param value The value of the metadata. * @param metadata The metadata value. * @returns The transaction hash of the meta transaction. */ async setMetadataDelegated(namespace, list, key, value, metadata) { if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } try { const isDelegate = await this.isListDelegate(namespace, list, this.walletClient.account.address); if (!isDelegate) { throw new NotDelegateError("WalletClient"); } return this.contract.write.setMetadataDelegated([namespace, list, key, value, metadata], { chain: this.walletClient.chain, account: this.walletClient.account }); } catch (e) { throw new MetadataOperationError(e.message); } } /** * Sets the metadata value for the given namespace, list, key and value combination as a delegate via a meta * transaction. * * This is a write operation and requires a wallet client and a meta transaction wallet client to be set. The meta * transaction wallet client provides a signed EIP712 signature to the wallet client to carry out the transaction for * it. * @param namespace The namespace of the metadata. * @param list The list of the metadata. * @param key The key of the metadata. * @param value The value of the metadata. * @param metadata The metadata value. * @returns The transaction hash of the meta transaction. */ async setMetadataDelegatedSigned(namespace, list, key, value, metadata) { if (!this.metaTransactionWalletClient || !this.metaTransactionWalletClient.account) { throw new ClientNotSetError("MetaTransactionWalletClient"); } if (!this.walletClient?.chain || !this.walletClient?.account) { throw new ClientMisconfiguredError(`WalletClient must have a chain and account set.`); } if (this.metaTransactionWalletClient.chain?.id != this.walletClient.chain?.id) { throw new ClientMisconfiguredError(`Provided WalletClient and MetaTransactionWalletClient must be on the same chain.`); } try { const metaSigner = this.metaTransactionWalletClient.account; const signerIsDelegate = await this.isListDelegate(namespace, list, metaSigner.address); if (!signerIsDelegate) { throw new NotDelegateError("MetaTransactionWalletClient"); } const signerNonce = await this.contract.read.nonces([metaSigner.address]); const type = getSignedDataType(SignedDataType.SetMetadataDelegatedSigned); const message = { namespace, list, key, value, metadata, signer: metaSigner.address, nonce: signerNonce }; const domain = await this.getEIP712Domain(); const signature = await this.metaTransactionWalletClient.signTypedData({ account: metaSigner, domain, types: type, primaryType: "SetMetadataDelegatedSigned", message }); return this.contract.write.setMetadataDelegatedSigned( [namespace, list, key, value, metadata, metaSigner.address, signature], { chain: this.walletClient.chain, account: this.walletClient.account } ); } catch (e) { throw new MetadataOperationError(e.message); } } } exports.TrustedHintController = TrustedHintController;