From 700ca27a217cf3d39458f9b24eb26af66d2ebcd9 Mon Sep 17 00:00:00 2001 From: Andrew Chung Date: Wed, 16 Apr 2025 13:37:37 +0900 Subject: [PATCH 1/6] Updated access controler abi --- .../abi/jsons/AccessController.json | 1021 ++++++++++------- 1 file changed, 622 insertions(+), 399 deletions(-) diff --git a/src/story_protocol_python_sdk/abi/jsons/AccessController.json b/src/story_protocol_python_sdk/abi/jsons/AccessController.json index 5c181d9..72ebaac 100644 --- a/src/story_protocol_python_sdk/abi/jsons/AccessController.json +++ b/src/story_protocol_python_sdk/abi/jsons/AccessController.json @@ -1,645 +1,868 @@ [ { - "type": "constructor", "inputs": [ { + "internalType": "address", "name": "ipAccountRegistry", - "type": "address", - "internalType": "address" + "type": "address" }, { + "internalType": "address", "name": "moduleRegistry", - "type": "address", - "internalType": "address" + "type": "address" } ], - "stateMutability": "nonpayable" + "stateMutability": "nonpayable", + "type": "constructor" }, { - "type": "function", - "name": "IP_ASSET_REGISTRY", - "inputs": [], - "outputs": [ + "inputs": [ { - "name": "", - "type": "address", - "internalType": "contract IIPAssetRegistry" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "MODULE_REGISTRY", - "inputs": [], - "outputs": [ + "internalType": "address", + "name": "signer", + "type": "address" + }, { - "name": "", - "type": "address", - "internalType": "contract IModuleRegistry" + "internalType": "address", + "name": "to", + "type": "address" } ], - "stateMutability": "view" + "name": "AccessController__BothCallerAndRecipientAreNotRegisteredModule", + "type": "error" }, { - "type": "function", - "name": "UPGRADE_INTERFACE_VERSION", "inputs": [], - "outputs": [ - { - "name": "", - "type": "string", - "internalType": "string" - } - ], - "stateMutability": "view" + "name": "AccessController__CallerIsNotIPAccountOrOwner", + "type": "error" }, { - "type": "function", - "name": "__ProtocolPausable_init", "inputs": [ { - "name": "accessManager", - "type": "address", - "internalType": "address" + "internalType": "address", + "name": "ipAccount", + "type": "address" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "AccessController__IPAccountIsNotValid", + "type": "error" }, { - "type": "function", - "name": "authority", "inputs": [], - "outputs": [ + "name": "AccessController__IPAccountIsZeroAddress", + "type": "error" + }, + { + "inputs": [ { - "name": "", - "type": "address", - "internalType": "address" + "internalType": "address", + "name": "ipAccount", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" } ], - "stateMutability": "view" + "name": "AccessController__OwnerIsIPAccount", + "type": "error" }, { - "type": "function", - "name": "checkPermission", "inputs": [ { + "internalType": "address", "name": "ipAccount", - "type": "address", - "internalType": "address" + "type": "address" }, { + "internalType": "address", "name": "signer", - "type": "address", - "internalType": "address" + "type": "address" }, { + "internalType": "address", "name": "to", - "type": "address", - "internalType": "address" + "type": "address" }, { + "internalType": "bytes4", "name": "func", - "type": "bytes4", - "internalType": "bytes4" + "type": "bytes4" } ], - "outputs": [], - "stateMutability": "view" + "name": "AccessController__PermissionDenied", + "type": "error" + }, + { + "inputs": [], + "name": "AccessController__PermissionIsNotValid", + "type": "error" + }, + { + "inputs": [], + "name": "AccessController__SignerIsZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "AccessController__ToAndFuncAreZeroAddressShouldCallSetAllPermissions", + "type": "error" + }, + { + "inputs": [], + "name": "AccessController__ZeroAccessManager", + "type": "error" + }, + { + "inputs": [], + "name": "AccessController__ZeroIPAccountRegistry", + "type": "error" + }, + { + "inputs": [], + "name": "AccessController__ZeroModuleRegistry", + "type": "error" }, { - "type": "function", - "name": "getPermission", "inputs": [ { - "name": "ipAccount", - "type": "address", - "internalType": "address" - }, - { - "name": "signer", - "type": "address", - "internalType": "address" - }, + "internalType": "address", + "name": "authority", + "type": "address" + } + ], + "name": "AccessManagedInvalidAuthority", + "type": "error" + }, + { + "inputs": [ { - "name": "to", - "type": "address", - "internalType": "address" + "internalType": "address", + "name": "caller", + "type": "address" }, { - "name": "func", - "type": "bytes4", - "internalType": "bytes4" + "internalType": "uint32", + "name": "delay", + "type": "uint32" } ], - "outputs": [ + "name": "AccessManagedRequiredDelay", + "type": "error" + }, + { + "inputs": [ { - "name": "", - "type": "uint8", - "internalType": "uint8" + "internalType": "address", + "name": "caller", + "type": "address" } ], - "stateMutability": "view" + "name": "AccessManagedUnauthorized", + "type": "error" }, { - "type": "function", - "name": "initialize", "inputs": [ { - "name": "accessManager", - "type": "address", - "internalType": "address" + "internalType": "address", + "name": "target", + "type": "address" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "AddressEmptyCode", + "type": "error" }, { - "type": "function", - "name": "isConsumingScheduledOp", - "inputs": [], - "outputs": [ + "inputs": [ { - "name": "", - "type": "bytes4", - "internalType": "bytes4" + "internalType": "address", + "name": "implementation", + "type": "address" } ], - "stateMutability": "view" + "name": "ERC1967InvalidImplementation", + "type": "error" }, { - "type": "function", - "name": "pause", "inputs": [], - "outputs": [], - "stateMutability": "nonpayable" + "name": "ERC1967NonPayable", + "type": "error" }, { - "type": "function", - "name": "paused", "inputs": [], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" + "name": "EnforcedPause", + "type": "error" }, { - "type": "function", - "name": "proxiableUUID", "inputs": [], - "outputs": [ + "name": "ExpectedPause", + "type": "error" + }, + { + "inputs": [], + "name": "FailedCall", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" + }, + { + "inputs": [], + "name": "UUPSUnauthorizedCallContext", + "type": "error" + }, + { + "inputs": [ { - "name": "", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "bytes32", + "name": "slot", + "type": "bytes32" } ], - "stateMutability": "view" + "name": "UUPSUnsupportedProxiableUUID", + "type": "error" }, { - "type": "function", - "name": "setAllPermissions", + "anonymous": false, "inputs": [ { - "name": "ipAccount", - "type": "address", - "internalType": "address" - }, - { - "name": "signer", - "type": "address", - "internalType": "address" - }, - { - "name": "permission", - "type": "uint8", - "internalType": "uint8" + "indexed": false, + "internalType": "address", + "name": "authority", + "type": "address" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "AuthorityUpdated", + "type": "event" }, { - "type": "function", - "name": "setAuthority", + "anonymous": false, "inputs": [ { - "name": "newAuthority", - "type": "address", - "internalType": "address" + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "Initialized", + "type": "event" }, { - "type": "function", - "name": "setTransientBatchPermissions", + "anonymous": false, "inputs": [ { - "name": "permissions", - "type": "tuple[]", - "internalType": "struct AccessPermission.Permission[]", - "components": [ - { - "name": "ipAccount", - "type": "address", - "internalType": "address" - }, - { - "name": "signer", - "type": "address", - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "func", - "type": "bytes4", - "internalType": "bytes4" - }, - { - "name": "permission", - "type": "uint8", - "internalType": "uint8" - } - ] + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" } ], - "outputs": [], - "stateMutability": "nonpayable" + "name": "Paused", + "type": "event" }, { - "type": "function", - "name": "setTransientPermission", + "anonymous": false, "inputs": [ { + "indexed": false, + "internalType": "address", + "name": "ipAccountOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", "name": "ipAccount", - "type": "address", - "internalType": "address" + "type": "address" }, { + "indexed": true, + "internalType": "address", "name": "signer", - "type": "address", - "internalType": "address" + "type": "address" }, { + "indexed": true, + "internalType": "address", "name": "to", - "type": "address", - "internalType": "address" + "type": "address" }, { + "indexed": false, + "internalType": "bytes4", "name": "func", - "type": "bytes4", - "internalType": "bytes4" + "type": "bytes4" }, { + "indexed": false, + "internalType": "uint8", "name": "permission", - "type": "uint8", - "internalType": "uint8" + "type": "uint8" } ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "unpause", - "inputs": [], - "outputs": [], - "stateMutability": "nonpayable" + "name": "PermissionSet", + "type": "event" }, { - "type": "function", - "name": "upgradeToAndCall", + "anonymous": false, "inputs": [ { - "name": "newImplementation", - "type": "address", - "internalType": "address" + "indexed": false, + "internalType": "address", + "name": "ipAccountOwner", + "type": "address" }, { - "name": "data", - "type": "bytes", - "internalType": "bytes" + "indexed": true, + "internalType": "address", + "name": "ipAccount", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes4", + "name": "func", + "type": "bytes4" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "permission", + "type": "uint8" } ], - "outputs": [], - "stateMutability": "payable" + "name": "TransientPermissionSet", + "type": "event" }, { - "type": "event", - "name": "AuthorityUpdated", + "anonymous": false, "inputs": [ { - "name": "authority", - "type": "address", "indexed": false, - "internalType": "address" + "internalType": "address", + "name": "account", + "type": "address" } ], - "anonymous": false + "name": "Unpaused", + "type": "event" }, { - "type": "event", - "name": "Initialized", + "anonymous": false, "inputs": [ { - "name": "version", - "type": "uint64", - "indexed": false, - "internalType": "uint64" + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" } ], - "anonymous": false + "name": "Upgraded", + "type": "event" }, { - "type": "event", - "name": "Paused", - "inputs": [ + "inputs": [], + "name": "IP_ASSET_REGISTRY", + "outputs": [ { - "name": "account", - "type": "address", - "indexed": false, - "internalType": "address" + "internalType": "contract IIPAssetRegistry", + "name": "", + "type": "address" } ], - "anonymous": false + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MODULE_REGISTRY", + "outputs": [ + { + "internalType": "contract IModuleRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UPGRADE_INTERFACE_VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" }, { - "type": "event", - "name": "PermissionSet", "inputs": [ { - "name": "ipAccountOwner", - "type": "address", - "indexed": false, - "internalType": "address" - }, + "internalType": "address", + "name": "accessManager", + "type": "address" + } + ], + "name": "__ProtocolPausable_init", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "authority", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ { + "internalType": "address", "name": "ipAccount", - "type": "address", - "indexed": true, - "internalType": "address" + "type": "address" }, { + "internalType": "address", "name": "signer", - "type": "address", - "indexed": true, - "internalType": "address" + "type": "address" }, { + "internalType": "address", "name": "to", - "type": "address", - "indexed": true, - "internalType": "address" + "type": "address" }, { + "internalType": "bytes4", "name": "func", - "type": "bytes4", - "indexed": false, - "internalType": "bytes4" - }, - { - "name": "permission", - "type": "uint8", - "indexed": false, - "internalType": "uint8" + "type": "bytes4" } ], - "anonymous": false + "name": "checkPermission", + "outputs": [], + "stateMutability": "view", + "type": "function" }, { - "type": "event", - "name": "Unpaused", "inputs": [ { - "name": "account", - "type": "address", - "indexed": false, - "internalType": "address" + "internalType": "address", + "name": "ipAccount", + "type": "address" + }, + { + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "func", + "type": "bytes4" } ], - "anonymous": false - }, - { - "type": "event", - "name": "Upgraded", - "inputs": [ + "name": "getPermanentPermission", + "outputs": [ { - "name": "implementation", - "type": "address", - "indexed": true, - "internalType": "address" + "internalType": "uint8", + "name": "", + "type": "uint8" } ], - "anonymous": false + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "AccessController__BothCallerAndRecipientAreNotRegisteredModule", "inputs": [ { + "internalType": "address", + "name": "ipAccount", + "type": "address" + }, + { + "internalType": "address", "name": "signer", - "type": "address", - "internalType": "address" + "type": "address" }, { + "internalType": "address", "name": "to", - "type": "address", - "internalType": "address" + "type": "address" + }, + { + "internalType": "bytes4", + "name": "func", + "type": "bytes4" } - ] - }, - { - "type": "error", - "name": "AccessController__CallerIsNotIPAccountOrOwner", - "inputs": [] - }, - { - "type": "error", - "name": "AccessController__IPAccountIsNotValid", - "inputs": [ + ], + "name": "getPermission", + "outputs": [ { - "name": "ipAccount", - "type": "address", - "internalType": "address" + "internalType": "uint8", + "name": "", + "type": "uint8" } - ] - }, - { - "type": "error", - "name": "AccessController__IPAccountIsZeroAddress", - "inputs": [] + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "AccessController__PermissionDenied", "inputs": [ { + "internalType": "address", "name": "ipAccount", - "type": "address", - "internalType": "address" + "type": "address" }, { + "internalType": "address", "name": "signer", - "type": "address", - "internalType": "address" + "type": "address" }, { + "internalType": "address", "name": "to", - "type": "address", - "internalType": "address" + "type": "address" }, { + "internalType": "bytes4", "name": "func", - "type": "bytes4", - "internalType": "bytes4" + "type": "bytes4" } - ] - }, - { - "type": "error", - "name": "AccessController__PermissionIsNotValid", - "inputs": [] + ], + "name": "getTransientPermission", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "AccessController__SignerIsZeroAddress", - "inputs": [] + "inputs": [ + { + "internalType": "address", + "name": "accessManager", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "AccessController__ToAndFuncAreZeroAddressShouldCallSetAllPermissions", - "inputs": [] + "inputs": [], + "name": "isConsumingScheduledOp", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "AccessController__ZeroAccessManager", - "inputs": [] + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "AccessController__ZeroIPAccountRegistry", - "inputs": [] + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "AccessController__ZeroModuleRegistry", - "inputs": [] + "inputs": [], + "name": "proxiableUUID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" }, { - "type": "error", - "name": "AccessManagedInvalidAuthority", "inputs": [ { - "name": "authority", - "type": "address", - "internalType": "address" + "internalType": "address", + "name": "ipAccount", + "type": "address" + }, + { + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "internalType": "uint8", + "name": "permission", + "type": "uint8" } - ] + ], + "name": "setAllPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "AccessManagedRequiredDelay", "inputs": [ { - "name": "caller", - "type": "address", - "internalType": "address" + "internalType": "address", + "name": "ipAccount", + "type": "address" }, { - "name": "delay", - "type": "uint32", - "internalType": "uint32" + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "internalType": "uint8", + "name": "permission", + "type": "uint8" } - ] + ], + "name": "setAllTransientPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "AccessManagedUnauthorized", "inputs": [ { - "name": "caller", - "type": "address", - "internalType": "address" + "internalType": "address", + "name": "newAuthority", + "type": "address" } - ] + ], + "name": "setAuthority", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "AddressEmptyCode", "inputs": [ { - "name": "target", - "type": "address", - "internalType": "address" + "components": [ + { + "internalType": "address", + "name": "ipAccount", + "type": "address" + }, + { + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "func", + "type": "bytes4" + }, + { + "internalType": "uint8", + "name": "permission", + "type": "uint8" + } + ], + "internalType": "struct AccessPermission.Permission[]", + "name": "permissions", + "type": "tuple[]" } - ] + ], + "name": "setBatchPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "ERC1967InvalidImplementation", "inputs": [ { - "name": "implementation", - "type": "address", - "internalType": "address" + "components": [ + { + "internalType": "address", + "name": "ipAccount", + "type": "address" + }, + { + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "func", + "type": "bytes4" + }, + { + "internalType": "uint8", + "name": "permission", + "type": "uint8" + } + ], + "internalType": "struct AccessPermission.Permission[]", + "name": "permissions", + "type": "tuple[]" } - ] - }, - { - "type": "error", - "name": "ERC1967NonPayable", - "inputs": [] - }, - { - "type": "error", - "name": "EnforcedPause", - "inputs": [] - }, - { - "type": "error", - "name": "ExpectedPause", - "inputs": [] - }, - { - "type": "error", - "name": "FailedInnerCall", - "inputs": [] + ], + "name": "setBatchTransientPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "InvalidInitialization", - "inputs": [] + "inputs": [ + { + "internalType": "address", + "name": "ipAccount", + "type": "address" + }, + { + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "func", + "type": "bytes4" + }, + { + "internalType": "uint8", + "name": "permission", + "type": "uint8" + } + ], + "name": "setPermission", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "NotInitializing", - "inputs": [] + "inputs": [ + { + "internalType": "address", + "name": "ipAccount", + "type": "address" + }, + { + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "func", + "type": "bytes4" + }, + { + "internalType": "uint8", + "name": "permission", + "type": "uint8" + } + ], + "name": "setTransientPermission", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "UUPSUnauthorizedCallContext", - "inputs": [] + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "type": "error", - "name": "UUPSUnsupportedProxiableUUID", "inputs": [ { - "name": "slot", - "type": "bytes32", - "internalType": "bytes32" + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" } - ] + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" } -] +] \ No newline at end of file From 59cf3f27c5473e0ef4146d8496e780750dd83ed4 Mon Sep 17 00:00:00 2001 From: Andrew Chung Date: Wed, 16 Apr 2025 13:38:05 +0900 Subject: [PATCH 2/6] Added set_permission() and set_all_permissions() and respective integration tests --- .../resources/Permission.py | 262 +++++++++++++----- .../test_integration_permission.py | 244 +++++++--------- 2 files changed, 287 insertions(+), 219 deletions(-) diff --git a/src/story_protocol_python_sdk/resources/Permission.py b/src/story_protocol_python_sdk/resources/Permission.py index 55bde2e..417aae1 100644 --- a/src/story_protocol_python_sdk/resources/Permission.py +++ b/src/story_protocol_python_sdk/resources/Permission.py @@ -5,9 +5,12 @@ from story_protocol_python_sdk.abi.IPAccountImpl.IPAccountImpl_client import IPAccountImplClient from story_protocol_python_sdk.abi.IPAssetRegistry.IPAssetRegistry_client import IPAssetRegistryClient +from story_protocol_python_sdk.abi.AccessController.AccessController_client import AccessControllerClient from story_protocol_python_sdk.resources.IPAccount import IPAccount - from story_protocol_python_sdk.utils.transaction_utils import build_and_send_transaction +from story_protocol_python_sdk.utils.validation import validate_address +from story_protocol_python_sdk.utils.constants import DEFAULT_FUNCTION_SELECTOR +from story_protocol_python_sdk.utils.sign import Sign class Permission: """ @@ -24,75 +27,190 @@ def __init__(self, web3: Web3, account, chain_id: int): self.ip_asset_registry_client = IPAssetRegistryClient(web3) self.ip_account = IPAccount(web3, account, chain_id) - - # def setPermission(self, ip_asset: str, signer: str, to: str, permission: int, func: str = "0x00000000", tx_options: dict = None) -> dict: - # """ - # Sets the permission for a specific function call. - - # :param ip_asset str: The address of the IP account that grants the permission for `signer`. - # :param signer str: The address that can call `to` on behalf of the `ip_asset`. - # :param to str: The address that can be called by the `signer`. - # :param permission int: The new permission level. - # :param func str: [Optional] The function selector string of `to` that can be called by the `signer` on behalf of the `ipAccount`. - # :param tx_options dict: [Optional] The transaction options. - # :return dict: A dictionary with the transaction hash. - # """ - # try: - # if not self.web3.is_address(signer): - # raise ValueError(f"The address {signer} that can call 'to' on behalf of the 'ip_asset' is not a valid address.") - - # if not self.web3.is_address(to): - # raise ValueError(f"The recipient of the transaction {to} is not a valid address.") + self.access_controller_client = AccessControllerClient(web3) + self.sign_util = Sign(web3, self.chain_id, self.account) + + def set_permission(self, ip_id: str, signer: str, to: str, permission: int, func: str = DEFAULT_FUNCTION_SELECTOR, tx_options: dict = None) -> dict: + """ + Sets the permission for a specific function call. + Each policy is represented as a mapping from an IP account address to a signer address to a recipient + address to a function selector to a permission level. The permission level is an enum of `AccessPermission`. + By default, all policies are set to ABSTAIN, which means that the permission is not set. + The owner of ipAccount by default has all permission. + + :param ip_id str: The IP ID of the IP account that grants the permission for `signer`. + :param signer str: The address that can call `to` on behalf of the `ip_id`. + :param to str: The address that can be called by the `signer`. + :param permission int: The new permission level. + :param func str: [Optional] The function selector string of `to` that can be called by the `signer` on behalf of the `ipAccount`. + :param tx_options dict: [Optional] The transaction options. + :return dict: A dictionary with the transaction hash and success status if waiting for transaction. + """ + try: + validate_address(signer) + validate_address(to) - # if not self._is_registered(ip_asset): - # raise ValueError(f"The IP account with id {ip_asset} is not registered.") - - # config_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'scripts', 'config.json')) - # with open(config_path, 'r') as config_file: - # config = json.load(config_file) - # contract_address = None - # for contract in config['contracts']: - # if contract['contract_name'] == 'AccessController': - # contract_address = contract['contract_address'] - # break - # if not contract_address: - # raise ValueError(f"Contract address for AccessController not found in config.json") - # abi_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'abi', 'AccessController', 'AccessController.json')) - # with open(abi_path, 'r') as abi_file: - # abi = json.load(abi_file) - - # contract = self.web3.eth.contract(address=contract_address, abi=abi) - - # data = contract.encode_abi( - # fn_name="setPermission", - # args=[ - # ip_asset, - # signer, - # to, - # func, - # permission - # ] - # ) - - # response = self.ip_account.execute( - # to=contract_address, - # value=0, - # account_address=ip_asset, - # data=data - # ) - - # return { - # 'txHash': response['txHash'] - # } - - # except Exception as e: - # raise e - - # def _is_registered(self, ip_id: str) -> bool: - # """ - # Check if an IP is registered. - - # :param ip_id str: The IP ID to check. - # :return bool: True if registered, False otherwise. - # """ - # return self.ip_asset_registry_client.isRegistered(ip_id) \ No newline at end of file + self._check_is_registered(ip_id) + + data = self.access_controller_client.contract.encode_abi( + abi_element_identifier="setPermission", + args=[ + self.web3.to_checksum_address(ip_id), + self.web3.to_checksum_address(signer), + self.web3.to_checksum_address(to), + Web3.keccak(text=func)[:4] if func else b'\x00\x00\x00\x00', + permission + ] + ) + + response = self.ip_account.execute( + to=self.access_controller_client.contract.address, + value=0, + ip_id=ip_id, + data=data, + tx_options=tx_options + ) + + return { + 'tx_hash': response['tx_hash'] + } + + except Exception as e: + raise e + + def set_all_permissions(self, ip_id: str, signer: str, permission: int, tx_options: dict = None) -> dict: + """ + Sets permission to a signer for all functions across all modules. + + :param ip_id str: The IP ID of the IP account that grants the permission. + :param signer str: The address that will receive the permissions. + :param permission int: The new permission level. + :param tx_options dict: [Optional] The transaction options. + :return dict: A dictionary with the transaction hash and success status if waiting for transaction. + """ + try: + validate_address(signer) + + self._check_is_registered(ip_id) + + data = self.access_controller_client.contract.encode_abi( + abi_element_identifier="setAllPermissions", + args=[ + self.web3.to_checksum_address(ip_id), + self.web3.to_checksum_address(signer), + permission + ] + ) + + if tx_options and tx_options.get('encoded_tx_data_only'): + return {'encoded_tx_data': data} + + response = self.ip_account.execute( + to=self.access_controller_client.contract.address, + value=0, + ip_id=ip_id, + data=data, + tx_options=tx_options + ) + + return { + 'tx_hash': response['tx_hash'] + } + + except Exception as e: + raise e + + def create_set_permission_signature(self, ip_id: str, signer: str, to: str, permission: int, + func: str = DEFAULT_FUNCTION_SELECTOR, deadline: int = None, + tx_options: dict = None) -> dict: + """ + Specific permission overrides wildcard permission with signature. + + :param ip_id str: The IP ID of the IP account that grants the permission. + :param signer str: The address that can call `to` on behalf of the `ip_id`. + :param to str: The address that can be called by the `signer`. + :param permission int: The new permission level. + :param func str: [Optional] The function selector string. + :param deadline int: [Optional] The deadline for the signature validity. + :param tx_options dict: [Optional] The transaction options. + :return dict: A dictionary with the transaction hash and success status if waiting for transaction. + """ + try: + validate_address(signer) + validate_address(to) + + self._check_is_registered(ip_id) + + ip_account_client = IPAccountImplClient(self.web3, address=ip_id) + + data = self.access_controller_client.encode_set_transient_permission( + ip_account=ip_id, + signer=signer, + to=to, + func=func, + permission=permission + ) + + # Get state and calculate deadline + state = ip_account_client.state() + block_timestamp = self.web3.eth.get_block('latest').timestamp + calculated_deadline = self.sign_util.get_deadline(block_timestamp, deadline) + + # Get permission signature + signature = self.sign_util.get_permission_signature( + ip_id=ip_id, + deadline=calculated_deadline, + state=state, + permissions=[{ + 'ip_id': ip_id, + 'signer': signer, + 'to': to, + 'permission': permission, + 'func': func + }] + ) + + execute_with_sig_data = ip_account_client.encode_execute_with_sig( + to=self.access_controller_client.address, + value=0, + data=data, + signer=signer, + deadline=calculated_deadline, + signature=signature + ) + + if tx_options and tx_options.get('encoded_tx_data_only'): + return {'encoded_tx_data': execute_with_sig_data} + + tx_hash = ip_account_client.execute_with_sig( + to=self.access_controller_client.address, + value=0, + data=data, + signer=signer, + deadline=calculated_deadline, + signature=signature + ) + + if tx_options and tx_options.get('wait_for_transaction'): + # Wait for transaction receipt logic would go here + return { + 'txHash': tx_hash, + 'success': True + } + + return { + 'txHash': tx_hash + } + + except Exception as e: + raise e + + def _check_is_registered(self, ip_id: str) -> None: + """ + Check if an IP is registered. + + :param ip_id str: The IP ID to check. + :raises ValueError: If the IP is not registered. + """ + if not self.ip_asset_registry_client.isRegistered(ip_id): + raise ValueError(f"IP id with {ip_id} is not registered.") diff --git a/tests/integration/test_integration_permission.py b/tests/integration/test_integration_permission.py index a2713e4..3df771c 100644 --- a/tests/integration/test_integration_permission.py +++ b/tests/integration/test_integration_permission.py @@ -1,174 +1,124 @@ # tests/integration/test_integration_permission.py -import os, json, sys import pytest -from dotenv import load_dotenv from web3 import Web3 -# Ensure the src directory is in the Python path -current_dir = os.path.dirname(__file__) -src_path = os.path.abspath(os.path.join(current_dir, '..', '..')) -if src_path not in sys.path: - sys.path.append(src_path) +from setup_for_integration import ( + web3, + account, + story_client, + get_token_id, + MockERC721, + MockERC20, + ZERO_ADDRESS, + ROYALTY_POLICY, + PIL_LICENSE_TEMPLATE, + CORE_METADATA_MODULE +) -from utils import get_token_id, get_story_client_in_devnet, MockERC721, check_event_in_tx - -load_dotenv() -private_key = os.getenv('WALLET_PRIVATE_KEY') -rpc_url = os.getenv('RPC_PROVIDER_URL') - -# Initialize Web3 -web3 = Web3(Web3.HTTPProvider(rpc_url)) -if not web3.is_connected(): - raise Exception("Failed to connect to Web3 provider") - -# Set up the account with the private key -account = web3.eth.account.from_key(private_key) - -@pytest.fixture -def story_client(): - return get_story_client_in_devnet(web3, account) - -@pytest.mark.skip(reason="Permission Tests not implemented yet") class TestPermissions: - - def test_setPermission(story_client): - token_id = get_token_id(MockERC721, story_client.web3, story_client.account) - - response = story_client.IPAsset.register( - token_contract=MockERC721, - token_id=token_id - ) - - response = story_client.Permission.setPermission( - ip_asset=response['ipId'], - signer=account.address, - to="0x2ac240293f12032E103458451dE8A8096c5A72E8", - permission=1, - func="0x00000000" - ) - - assert response is not None, "Response is None, indicating the contract interaction failed." - assert 'txHash' in response, "Response does not contain 'txHash'." - assert response['txHash'] is not None, "'txHash' is None." - assert isinstance(response['txHash'], str), "'txHash' is not a string." - assert len(response['txHash']) > 0, "'txHash' is empty." - - assert check_event_in_tx(web3, response['txHash'], "PermissionSet(address,address,address,address,bytes4,uint8)") is True - - @pytest.fixture - def registered_ip(story_client): + @pytest.fixture(scope="class") + def ip_id(self, story_client): """Fixture to create an IP for testing permissions.""" token_id = get_token_id(MockERC721, story_client.web3, story_client.account) response = story_client.IPAsset.register( nft_contract=MockERC721, - token_id=token_id + token_id=token_id, + tx_options={"wait_for_transaction": True} ) - return response['ipId'] + assert 'ip_id' in response, "Failed to register IP" + return response['ip_id'] - def test_set_permission_with_specific_function(story_client, registered_ip): - """Test setting permission for a specific function.""" - module_address = "0x2ac240293f12032E103458451dE8A8096c5A72E8" - function_selector = Web3.keccak(text="transfer(address,uint256)")[:4].hex() - - response = story_client.Permission.setPermission( - ip_asset=registered_ip, + def test_set_permission(self, story_client, ip_id): + """Test setting permission successfully.""" + response = story_client.Permission.set_permission( + ip_id=ip_id, signer=account.address, - to=module_address, + to=CORE_METADATA_MODULE, permission=1, # ALLOW - func=function_selector + func="function setAll(address,string,bytes32,bytes32)", + tx_options={"wait_for_transaction": True} ) assert response is not None - assert 'txHash' in response - assert isinstance(response['txHash'], str) - assert len(response['txHash']) > 0 - assert check_event_in_tx(web3, response['txHash'], "PermissionSet(address,address,address,address,bytes4,uint8)") - - def test_set_all_permissions(story_client, registered_ip): - """Test setting all permissions for a signer.""" - response = story_client.Permission.setAllPermissions( - ip_asset=registered_ip, + assert 'tx_hash' in response + assert isinstance(response['tx_hash'], str) + assert len(response['tx_hash']) > 0 + + def test_set_all_permissions(self, story_client, ip_id): + """Test setting all permissions successfully.""" + response = story_client.Permission.set_all_permissions( + ip_id=ip_id, signer=account.address, - permission=1 # ALLOW + permission=1, # ALLOW ) assert response is not None - assert 'txHash' in response - assert isinstance(response['txHash'], str) - assert len(response['txHash']) > 0 - assert check_event_in_tx(web3, response['txHash'], "PermissionSet(address,address,address,address,bytes4,uint8)") - - def test_set_batch_permissions(story_client, registered_ip): - """Test setting multiple permissions in a single transaction.""" - module_address = "0x2ac240293f12032E103458451dE8A8096c5A72E8" - permissions = [ - { - 'ip_asset': registered_ip, - 'signer': account.address, - 'to': module_address, - 'permission': 1, - 'func': "0x00000000" - }, - { - 'ip_asset': registered_ip, - 'signer': account.address, - 'to': module_address, - 'permission': 2, # DENY - 'func': Web3.keccak(text="transfer(address,uint256)")[:4].hex() - } - ] - - response = story_client.Permission.setBatchPermissions(permissions) - - assert response is not None - assert 'txHash' in response - assert isinstance(response['txHash'], str) - assert len(response['txHash']) > 0 - assert check_event_in_tx(web3, response['txHash'], "PermissionSet(address,address,address,address,bytes4,uint8)") + assert 'tx_hash' in response + assert isinstance(response['tx_hash'], str) + assert len(response['tx_hash']) > 0 - def test_set_permission_invalid_ip(story_client): - """Test setting permission for an unregistered IP.""" - unregistered_ip = "0x1234567890123456789012345678901234567890" + # def test_create_set_permission_signature(self, story_client, ip_id): + # """Test creating set permission signature.""" + # deadline = web3.eth.get_block('latest')['timestamp'] + 60000 - with pytest.raises(ValueError) as exc_info: - story_client.Permission.setPermission( - ip_asset=unregistered_ip, - signer=account.address, - to="0x2ac240293f12032E103458451dE8A8096c5A72E8", - permission=1 - ) + # response = story_client.Permission.create_set_permission_signature( + # ip_id=ip_id, + # signer=account.address, + # to=CORE_METADATA_MODULE, + # func="function setAll(address,string,bytes32,bytes32)", + # permission=1, # ALLOW + # deadline=deadline, + # tx_options={"wait_for_transaction": True} + # ) + + # assert response is not None + # assert 'txHash' in response + # assert isinstance(response['txHash'], str) + # assert len(response['txHash']) > 0 + # assert response['success'] is True + + # def test_get_encoded_data_for_create_set_permission_signature(self, story_client, ip_id): + # """Test getting encoded data for createSetPermissionSignature.""" + # deadline = web3.eth.get_block('latest')['timestamp'] + 60000 - assert "is not registered" in str(exc_info.value) - - def test_set_permission_invalid_signer(story_client, registered_ip): - """Test setting permission with invalid signer address.""" - with pytest.raises(ValueError) as exc_info: - story_client.Permission.setPermission( - ip_asset=registered_ip, - signer="0xinvalid", - to="0x2ac240293f12032E103458451dE8A8096c5A72E8", - permission=1 - ) + # response = story_client.Permission.create_set_permission_signature( + # ip_id=ip_id, + # signer=account.address, + # to=CORE_METADATA_MODULE, + # func="function setAll(address,string,bytes32,bytes32)", + # permission=1, # ALLOW + # deadline=deadline, + # tx_options={"encoded_tx_data_only": True} + # ) + + # assert 'encoded_tx_data' in response + # assert isinstance(response['encoded_tx_data']['data'], str) + # assert len(response['encoded_tx_data']['data']) > 0 + + # def test_set_permission_invalid_ip(self, story_client): + # """Test setting permission for an unregistered IP.""" + # unregistered_ip = "0x1234567890123456789012345678901234567890" - assert "is not a valid address" in str(exc_info.value) - - def test_create_permission_signature(story_client, registered_ip): - """Test creating and executing a permission signature.""" - module_address = "0x2ac240293f12032E103458451dE8A8096c5A72E8" - deadline = web3.eth.get_block('latest')['timestamp'] + 1000 + # with pytest.raises(ValueError) as exc_info: + # story_client.Permission.set_permission( + # ip_id=unregistered_ip, + # signer=account.address, + # to="CORE_METADATA_MODULE", + # permission=1, + # tx_options={"wait_for_transaction": True} + # ) - response = story_client.Permission.createSetPermissionSignature( - ip_asset=registered_ip, - signer=account.address, - to=module_address, - permission=1, - func="0x00000000", - deadline=deadline - ) - - assert response is not None - assert 'txHash' in response - assert isinstance(response['txHash'], str) - assert len(response['txHash']) > 0 - assert check_event_in_tx(web3, response['txHash'], "PermissionSet(address,address,address,address,bytes4,uint8)") \ No newline at end of file + # assert f"IP id with {unregistered_ip} is not registered" in str(exc_info.value) + + # def test_set_permission_invalid_function_signature(self, story_client, ip_id): + # """Test setting permission with invalid function signature.""" + # with pytest.raises(Exception): + # story_client.Permission.set_permission( + # ip_id=ip_id, + # signer=account.address, + # to=CORE_METADATA_MODULE, + # permission=1, + # func="invalid_function_signature", + # tx_options={"wait_for_transaction": True} + # ) \ No newline at end of file From faf3242399cd7a649282a22718108a418fce695b Mon Sep 17 00:00:00 2001 From: Andrew Chung Date: Wed, 16 Apr 2025 13:38:34 +0900 Subject: [PATCH 3/6] Added default_func_selector to constants and validate_address() helper fn --- src/story_protocol_python_sdk/utils/constants.py | 1 + src/story_protocol_python_sdk/utils/validation.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 src/story_protocol_python_sdk/utils/validation.py diff --git a/src/story_protocol_python_sdk/utils/constants.py b/src/story_protocol_python_sdk/utils/constants.py index df83925..8d17752 100644 --- a/src/story_protocol_python_sdk/utils/constants.py +++ b/src/story_protocol_python_sdk/utils/constants.py @@ -2,3 +2,4 @@ ZERO_HASH = "0x0000000000000000000000000000000000000000000000000000000000000000" ROYALTY_POLICY = "0xBe54FB168b3c982b7AaE60dB6CF75Bd8447b390E" ZERO_FUNC = "0x00000000" +DEFAULT_FUNCTION_SELECTOR = "0x00000000" diff --git a/src/story_protocol_python_sdk/utils/validation.py b/src/story_protocol_python_sdk/utils/validation.py new file mode 100644 index 0000000..e1ea155 --- /dev/null +++ b/src/story_protocol_python_sdk/utils/validation.py @@ -0,0 +1,15 @@ +from web3 import Web3 + +def validate_address(address: str) -> str: + """ + Validates if the provided string is a valid Ethereum address. + + :param address str: The address to validate. + :return str: The validated address. + :raises ValueError: If the address is not valid. + """ + if not Web3.is_address(address): + raise ValueError(f"Invalid address: {address}.") + return address + + From e817aaff9b40a6422be8178d69b9a52948b950e6 Mon Sep 17 00:00:00 2001 From: Andrew Chung Date: Wed, 16 Apr 2025 13:39:29 +0900 Subject: [PATCH 4/6] Added CORE_METADATA_MODULE constant for integration tests --- tests/integration/setup_for_integration.py | 6 ++++-- tests/integration/utils.py | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/integration/setup_for_integration.py b/tests/integration/setup_for_integration.py index cc075c3..9f7ab98 100644 --- a/tests/integration/setup_for_integration.py +++ b/tests/integration/setup_for_integration.py @@ -27,7 +27,8 @@ ARBITRATION_POLICY_UMA, generate_cid, WIP_TOKEN_ADDRESS, - setup_royalty_vault + setup_royalty_vault, + CORE_METADATA_MODULE ) # Load environment variables @@ -86,5 +87,6 @@ def story_client_2(): 'wallet_address', 'wallet_address_2', 'private_key', - 'private_key_2' + 'private_key_2', + 'CORE_METADATA_MODULE' ] \ No newline at end of file diff --git a/tests/integration/utils.py b/tests/integration/utils.py index ea205a1..dbc879b 100644 --- a/tests/integration/utils.py +++ b/tests/integration/utils.py @@ -19,6 +19,7 @@ ROYALTY_MODULE="0xD2f60c40fEbccf6311f8B47c4f2Ec6b040400086" PIL_LICENSE_TEMPLATE="0x2E896b0b2Fdb7457499B56AAaA4AE55BCB4Cd316" ARBITRATION_POLICY_UMA="0xfFD98c3877B8789124f02C7E8239A4b0Ef11E936" +CORE_METADATA_MODULE="0x6E81a25C99C6e8430aeC7353325EB138aFE5DC16" def get_story_client_in_sepolia(web3: Web3, account) -> StoryClient: chain_id = 11155111 # Sepolia chain ID From 8b4639ca51cd2ee7dad4a0a18d3e999096b19222 Mon Sep 17 00:00:00 2001 From: Andrew Chung Date: Wed, 16 Apr 2025 14:45:37 +0900 Subject: [PATCH 5/6] Updated create_set_permission_signature() and respective integration tests --- .../resources/Permission.py | 62 ++++++-------- .../test_integration_permission.py | 85 ++++++------------- 2 files changed, 53 insertions(+), 94 deletions(-) diff --git a/src/story_protocol_python_sdk/resources/Permission.py b/src/story_protocol_python_sdk/resources/Permission.py index 417aae1..2a24106 100644 --- a/src/story_protocol_python_sdk/resources/Permission.py +++ b/src/story_protocol_python_sdk/resources/Permission.py @@ -102,9 +102,6 @@ def set_all_permissions(self, ip_id: str, signer: str, permission: int, tx_optio ] ) - if tx_options and tx_options.get('encoded_tx_data_only'): - return {'encoded_tx_data': data} - response = self.ip_account.execute( to=self.access_controller_client.contract.address, value=0, @@ -141,28 +138,36 @@ def create_set_permission_signature(self, ip_id: str, signer: str, to: str, perm self._check_is_registered(ip_id) - ip_account_client = IPAccountImplClient(self.web3, address=ip_id) + ip_account_client = IPAccountImplClient(self.web3, contract_address=ip_id) - data = self.access_controller_client.encode_set_transient_permission( - ip_account=ip_id, - signer=signer, - to=to, - func=func, - permission=permission + # Convert addresses to checksum format + ip_id = self.web3.to_checksum_address(ip_id) + signer = self.web3.to_checksum_address(signer) + to = self.web3.to_checksum_address(to) + + data = self.access_controller_client.contract.encode_abi( + abi_element_identifier="setTransientPermission", + args=[ + ip_id, + signer, + to, + Web3.keccak(text=func)[:4] if func else b'\x00\x00\x00\x00', + permission + ] ) # Get state and calculate deadline state = ip_account_client.state() block_timestamp = self.web3.eth.get_block('latest').timestamp - calculated_deadline = self.sign_util.get_deadline(block_timestamp, deadline) + calculated_deadline = self.sign_util.get_deadline(deadline) # Get permission signature - signature = self.sign_util.get_permission_signature( + signature_response = self.sign_util.get_permission_signature( ip_id=ip_id, deadline=calculated_deadline, state=state, permissions=[{ - 'ip_id': ip_id, + 'ipId': ip_id, 'signer': signer, 'to': to, 'permission': permission, @@ -170,36 +175,23 @@ def create_set_permission_signature(self, ip_id: str, signer: str, to: str, perm }] ) - execute_with_sig_data = ip_account_client.encode_execute_with_sig( - to=self.access_controller_client.address, - value=0, - data=data, - signer=signer, - deadline=calculated_deadline, - signature=signature - ) + # Extract the signature string from the response + signature_hex = signature_response["signature"] - if tx_options and tx_options.get('encoded_tx_data_only'): - return {'encoded_tx_data': execute_with_sig_data} - - tx_hash = ip_account_client.execute_with_sig( - to=self.access_controller_client.address, + # Create and sign the transaction + response = self.ip_account.execute_with_sig( + to=self.access_controller_client.contract.address, value=0, + ip_id=ip_id, data=data, signer=signer, deadline=calculated_deadline, - signature=signature + signature=self.web3.to_bytes(hexstr=signature_hex), + tx_options=tx_options ) - if tx_options and tx_options.get('wait_for_transaction'): - # Wait for transaction receipt logic would go here - return { - 'txHash': tx_hash, - 'success': True - } - return { - 'txHash': tx_hash + 'tx_hash': response['tx_hash'] } except Exception as e: diff --git a/tests/integration/test_integration_permission.py b/tests/integration/test_integration_permission.py index 3df771c..085a228 100644 --- a/tests/integration/test_integration_permission.py +++ b/tests/integration/test_integration_permission.py @@ -58,67 +58,34 @@ def test_set_all_permissions(self, story_client, ip_id): assert isinstance(response['tx_hash'], str) assert len(response['tx_hash']) > 0 - # def test_create_set_permission_signature(self, story_client, ip_id): - # """Test creating set permission signature.""" - # deadline = web3.eth.get_block('latest')['timestamp'] + 60000 + def test_create_set_permission_signature(self, story_client, ip_id): + """Test creating set permission signature.""" + deadline = web3.eth.get_block('latest')['timestamp'] + 60000 - # response = story_client.Permission.create_set_permission_signature( - # ip_id=ip_id, - # signer=account.address, - # to=CORE_METADATA_MODULE, - # func="function setAll(address,string,bytes32,bytes32)", - # permission=1, # ALLOW - # deadline=deadline, - # tx_options={"wait_for_transaction": True} - # ) - - # assert response is not None - # assert 'txHash' in response - # assert isinstance(response['txHash'], str) - # assert len(response['txHash']) > 0 - # assert response['success'] is True - - # def test_get_encoded_data_for_create_set_permission_signature(self, story_client, ip_id): - # """Test getting encoded data for createSetPermissionSignature.""" - # deadline = web3.eth.get_block('latest')['timestamp'] + 60000 - - # response = story_client.Permission.create_set_permission_signature( - # ip_id=ip_id, - # signer=account.address, - # to=CORE_METADATA_MODULE, - # func="function setAll(address,string,bytes32,bytes32)", - # permission=1, # ALLOW - # deadline=deadline, - # tx_options={"encoded_tx_data_only": True} - # ) + response = story_client.Permission.create_set_permission_signature( + ip_id=ip_id, + signer=account.address, + to=CORE_METADATA_MODULE, + func="setAll(address,string,bytes32,bytes32)", + permission=1, # ALLOW + deadline=deadline, + ) - # assert 'encoded_tx_data' in response - # assert isinstance(response['encoded_tx_data']['data'], str) - # assert len(response['encoded_tx_data']['data']) > 0 + assert response is not None + assert 'tx_hash' in response + assert isinstance(response['tx_hash'], str) + assert len(response['tx_hash']) > 0 - # def test_set_permission_invalid_ip(self, story_client): - # """Test setting permission for an unregistered IP.""" - # unregistered_ip = "0x1234567890123456789012345678901234567890" + def test_set_permission_invalid_ip(self, story_client): + """Test setting permission for an unregistered IP.""" + unregistered_ip = "0x1234567890123456789012345678901234567890" - # with pytest.raises(ValueError) as exc_info: - # story_client.Permission.set_permission( - # ip_id=unregistered_ip, - # signer=account.address, - # to="CORE_METADATA_MODULE", - # permission=1, - # tx_options={"wait_for_transaction": True} - # ) + with pytest.raises(ValueError) as exc_info: + story_client.Permission.set_permission( + ip_id=unregistered_ip, + signer=account.address, + to=CORE_METADATA_MODULE, + permission=1, + ) - # assert f"IP id with {unregistered_ip} is not registered" in str(exc_info.value) - - # def test_set_permission_invalid_function_signature(self, story_client, ip_id): - # """Test setting permission with invalid function signature.""" - # with pytest.raises(Exception): - # story_client.Permission.set_permission( - # ip_id=ip_id, - # signer=account.address, - # to=CORE_METADATA_MODULE, - # permission=1, - # func="invalid_function_signature", - # tx_options={"wait_for_transaction": True} - # ) \ No newline at end of file + assert f"IP id with {unregistered_ip} is not registered" in str(exc_info.value) From 5f5bc9e08c4955d08b7da73eeda6e1f18e53a2de Mon Sep 17 00:00:00 2001 From: Andrew Chung Date: Thu, 17 Apr 2025 14:15:22 +0900 Subject: [PATCH 6/6] Updated error msgs --- src/story_protocol_python_sdk/resources/Permission.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/story_protocol_python_sdk/resources/Permission.py b/src/story_protocol_python_sdk/resources/Permission.py index 2a24106..125be36 100644 --- a/src/story_protocol_python_sdk/resources/Permission.py +++ b/src/story_protocol_python_sdk/resources/Permission.py @@ -76,7 +76,7 @@ def set_permission(self, ip_id: str, signer: str, to: str, permission: int, func } except Exception as e: - raise e + raise Exception(f"Failed to set permission for IP {ip_id}: {str(e)}") def set_all_permissions(self, ip_id: str, signer: str, permission: int, tx_options: dict = None) -> dict: """ @@ -115,7 +115,7 @@ def set_all_permissions(self, ip_id: str, signer: str, permission: int, tx_optio } except Exception as e: - raise e + raise Exception(f"Failed to set all permissions for IP {ip_id} and signer {signer}: {str(e)}") def create_set_permission_signature(self, ip_id: str, signer: str, to: str, permission: int, func: str = DEFAULT_FUNCTION_SELECTOR, deadline: int = None, @@ -195,7 +195,7 @@ def create_set_permission_signature(self, ip_id: str, signer: str, to: str, perm } except Exception as e: - raise e + raise Exception(f"Failed to create permission signature for IP {ip_id}, signer {signer}, to {to}: {str(e)}") def _check_is_registered(self, ip_id: str) -> None: """