Skip to content

Commit bfbdc6b

Browse files
authored
[UPDATE] Register() Bug Fix + Mainnet Support (#40)
* [UPDATE] New Release & Register() Metadata Bug Fix (#38) * Updated demo to aeneid * Fixed metadata camelcase bug * Updated readme to aeneid * manual upload of new ver to pypi * [UPDATE] Added mainnet support (#39)
1 parent 2b191cc commit bfbdc6b

7 files changed

Lines changed: 73 additions & 71 deletions

File tree

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# Story Protocol SDK
1+
# Story SDK
22

3-
Welcome to the documents for Story Protocol Python SDK. The Python SDK provides the APIs for developers to build applications with Story Protocol. By using the SDK, developers can create the resources like IP assets and perform actions to interact with the resource.
3+
Welcome to the documents for Story Python SDK. The Python SDK provides the APIs for developers to build applications with Story. By using the SDK, developers can create the resources like IP assets and perform actions to interact with the resource.
44

55
## How to use Story Protocol SDK in Your Project
66

@@ -48,14 +48,14 @@ The preceding code created the `account` object for creating the SDK client.
4848

4949
To set up the SDK client, import `StoryClient` from `story_protocol_python_sdk`. Write the following code, utilizing the `account` we created previously.
5050

51-
> :information-source: Make sure to have RPC_PROVIDER_URL for your desired chain set up in your .env file. We recommend using the Sepolia network with `RPC_PROVIDER_URL=https://rpc.ankr.com/eth_sepolia`.
51+
> :information-source: Make sure to have RPC_PROVIDER_URL for your desired chain set up in your .env file. We recommend using the public default one with `RPC_PROVIDER_URL=https://aeneid.storyrpc.io`.
5252
5353
```Python main.py
5454
from story_protocol_python_sdk import StoryClient
5555

5656
# Create StoryClient instance
57-
odyssey_chain_id = 1516
58-
story_client = StoryClient(web3, account, odyssey_chain_id)
57+
aeneid_chain_id = 1315
58+
story_client = StoryClient(web3, account, aeneid_chain_id)
5959
```
6060

6161
## Running test cases

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setup(
77
name='story_protocol_python_sdk',
8-
version='0.3.5',
8+
version='0.3.7',
99
packages=find_packages(where='src', exclude=["tests"]),
1010
package_dir={'': 'src'},
1111
install_requires=[
@@ -18,7 +18,7 @@
1818
license='MIT',
1919
author='Andrew Chung',
2020
author_email='andrew@storyprotocol.xyz',
21-
description='A Python SDK for interacting with the Story Protocol.',
21+
description='A Python SDK for interacting with Story.',
2222
long_description=open('README.md').read(),
2323
long_description_content_type='text/markdown',
2424
classifiers=[

src/story_protocol_python_sdk/resources/IPAsset.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ def register(
6262
:param nft_contract str: The address of the NFT.
6363
:param token_id int: The token identifier of the NFT.
6464
:param ip_metadata dict: [Optional] Metadata for the IP.
65-
:param ip_metadata_URI str: [Optional] Metadata URI for the IP.
65+
:param ip_metadata_uri str: [Optional] Metadata URI for the IP.
6666
:param ip_metadata_hash str: [Optional] Metadata hash for the IP.
67-
:param nft_metadata_URI str: [Optional] Metadata URI for the NFT.
67+
:param nft_metadata_uri str: [Optional] Metadata URI for the NFT.
6868
:param nft_metadata_hash str: [Optional] Metadata hash for the NFT.
6969
:param deadline int: [Optional] Signature deadline in milliseconds.
7070
:param tx_options dict: [Optional] Transaction options.
@@ -96,10 +96,10 @@ def register(
9696

9797
if ip_metadata:
9898
req_object['ipMetadata'].update({
99-
'ipMetadataURI': ip_metadata.get('ipMetadataURI', ""),
100-
'ipMetadataHash': ip_metadata.get('ipMetadataHash', ZERO_HASH),
101-
'nftMetadataURI': ip_metadata.get('nftMetadataURI', ""),
102-
'nftMetadataHash': ip_metadata.get('nftMetadataHash', ZERO_HASH),
99+
'ipMetadataURI': ip_metadata.get('ip_metadata_uri', ""),
100+
'ipMetadataHash': ip_metadata.get('ip_metadata_hash', ZERO_HASH),
101+
'nftMetadataURI': ip_metadata.get('nft_metadata_uri', ""),
102+
'nftMetadataHash': ip_metadata.get('nft_metadata_hash', ZERO_HASH),
103103
})
104104

105105
calculated_deadline = self.sign_util.get_deadline(deadline=deadline)

src/story_protocol_python_sdk/story_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def __init__(self, web3, account, chain_id: int):
3636
if not web3 or not account:
3737
raise ValueError("web3 and account must be provided")
3838

39-
if chain_id != 1315:
39+
if chain_id not in [1315, 1514]:
4040
raise ValueError("only support story devnet")
4141

4242
self.web3 = web3

tests/demo/demo.py

Lines changed: 21 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,19 @@
33
from web3 import Web3
44

55
from story_protocol_python_sdk import StoryClient
6-
from demo_utils import get_token_id, MockERC721, MockERC20, mint_tokens
6+
from demo_utils import get_token_id, MockERC721, MockERC20, mint_tokens, ROYALTY_POLICY, ROYALTY_MODULE, PIL_LICENSE_TEMPLATE
77

88
def main():
99
# 1. Set up your Story Config
1010
load_dotenv()
1111
private_key = os.getenv('WALLET_PRIVATE_KEY')
1212
rpc_url = os.getenv('RPC_PROVIDER_URL')
1313

14+
if not private_key:
15+
raise ValueError("WALLET_PRIVATE_KEY environment variable is not set")
16+
if not rpc_url:
17+
raise ValueError("RPC_PROVIDER_URL environment variable is not set")
18+
1419
# Initialize Web3
1520
web3 = Web3(Web3.HTTPProvider(rpc_url))
1621
if not web3.is_connected():
@@ -20,26 +25,22 @@ def main():
2025
account = web3.eth.account.from_key(private_key)
2126

2227
# Create StoryClient instance
23-
story_client = StoryClient(web3, account, 11155111)
28+
story_client = StoryClient(web3, account, 1315)
2429

2530
# 2. Register an IP Asset
2631
token_id = get_token_id(MockERC721, story_client.web3, story_client.account)
32+
2733
registered_ip_asset_response = story_client.IPAsset.register(
28-
token_contract=MockERC721,
34+
nft_contract=MockERC721,
2935
token_id=token_id
3036
)
3137
print(f"Root IPA created at transaction hash {registered_ip_asset_response['txHash']}, IPA ID: {registered_ip_asset_response['ipId']}")
3238

3339
# 3. Register PIL Terms
34-
commercial_use_params = {
35-
'currency': MockERC20,
36-
'minting_fee': 2,
37-
'royalty_policy': "0xAAbaf349C7a2A84564F9CC4Ac130B3f19A718E86"
38-
}
3940
register_pil_terms_response = story_client.License.registerCommercialUsePIL(
40-
minting_fee=commercial_use_params['minting_fee'],
41-
currency=commercial_use_params['currency'],
42-
royalty_policy=commercial_use_params['royalty_policy']
41+
default_minting_fee=1,
42+
currency=MockERC20,
43+
royalty_policy=ROYALTY_POLICY
4344
)
4445
if 'txHash' in register_pil_terms_response:
4546
print(f"PIL Terms registered at transaction hash {register_pil_terms_response['txHash']}, License Terms ID: {register_pil_terms_response['licenseTermsId']}")
@@ -50,59 +51,42 @@ def main():
5051
try:
5152
attach_license_terms_response = story_client.License.attachLicenseTerms(
5253
ip_id=registered_ip_asset_response['ipId'],
53-
license_template="0x260B6CB6284c89dbE660c0004233f7bB99B5edE7",
54+
license_template=PIL_LICENSE_TEMPLATE,
5455
license_terms_id=register_pil_terms_response['licenseTermsId']
5556
)
5657
print(f"Attached License Terms to IP at transaction hash {attach_license_terms_response['txHash']}")
5758
except Exception as e:
5859
print(f"License Terms ID {register_pil_terms_response['licenseTermsId']} already attached to this IPA.")
5960

6061
#Before you mint make sure you have enough ERC20 tokens according to the minting fee above
61-
token_ids = mint_tokens(MockERC20, web3, account, account.address, 2)
62+
token_ids = mint_tokens(MockERC20, web3, account, account.address, 10000)
6263

6364
# 5. Mint License
6465
mint_license_response = story_client.License.mintLicenseTokens(
6566
licensor_ip_id=registered_ip_asset_response['ipId'],
66-
license_template="0x260B6CB6284c89dbE660c0004233f7bB99B5edE7",
67+
license_template=PIL_LICENSE_TEMPLATE,
6768
license_terms_id=register_pil_terms_response['licenseTermsId'],
6869
amount=1,
69-
receiver=account.address
70+
receiver=account.address,
71+
max_minting_fee=1,
72+
max_revenue_share=0
7073
)
7174
print(f"License Token minted at transaction hash {mint_license_response['txHash']}, License Token IDs: {mint_license_response['licenseTokenIds']}")
7275

7376
# 6. Mint derivative IP Asset using your license
7477
derivative_token_id = get_token_id(MockERC721, story_client.web3, story_client.account)
7578
registered_ip_asset_derivative_response = story_client.IPAsset.register(
76-
token_contract=MockERC721,
79+
nft_contract=MockERC721,
7780
token_id=derivative_token_id
7881
)
7982
print(f"Derivative IPA created at transaction hash {registered_ip_asset_derivative_response['txHash']}, IPA ID: {registered_ip_asset_derivative_response['ipId']}")
8083

8184
link_derivative_response = story_client.IPAsset.registerDerivativeWithLicenseTokens(
8285
child_ip_id=registered_ip_asset_derivative_response['ipId'],
83-
license_token_ids=mint_license_response['licenseTokenIds']
86+
license_token_ids=mint_license_response['licenseTokenIds'],
87+
max_rts=5 * 10 ** 6
8488
)
8589
print(f"Derivative IPA linked to parent at transaction hash {link_derivative_response['txHash']}")
8690

87-
# 7. Collect Royalty Tokens
88-
collect_royalty_tokens_response = story_client.Royalty.collectRoyaltyTokens(
89-
parent_ip_id=registered_ip_asset_response['ipId'],
90-
child_ip_id=registered_ip_asset_derivative_response['ipId']
91-
)
92-
print(f"Collected royalty token {collect_royalty_tokens_response['royaltyTokensCollected']} at transaction hash {collect_royalty_tokens_response['txHash']}")
93-
94-
# 8. Claim Revenue
95-
snapshot_response = story_client.Royalty.snapshot(
96-
child_ip_id=registered_ip_asset_derivative_response['ipId']
97-
)
98-
print(f"Took a snapshot with ID {snapshot_response['snapshotId']} at transaction hash {snapshot_response['txHash']}")
99-
100-
claim_revenue_response = story_client.Royalty.claimRevenue(
101-
snapshot_ids=[snapshot_response['snapshotId']],
102-
child_ip_id=registered_ip_asset_derivative_response['ipId'],
103-
token=MockERC20
104-
)
105-
print(f"Claimed revenue token {claim_revenue_response['claimableToken']} at transaction hash {claim_revenue_response['txHash']}")
106-
10791
if __name__ == "__main__":
10892
main()

tests/demo/demo_utils.py

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
# Mock ERC721 contract address
2-
MockERC721 = "0x7ee32b8B515dEE0Ba2F25f612A04a731eEc24F49"
2+
MockERC721 = "0xa1119092ea911202E0a65B743a13AE28C5CF2f21"
33

44
# Mock ERC20 contract address (same as used in TypeScript tests)
5-
MockERC20 = "0xB132A6B7AE652c974EE1557A3521D53d18F6739f"
5+
MockERC20 = "0xF2104833d386a2734a4eB3B8ad6FC6812F29E38E"
6+
7+
ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"
8+
ROYALTY_POLICY="0xBe54FB168b3c982b7AaE60dB6CF75Bd8447b390E" #Royalty Policy LAP
9+
ROYALTY_MODULE="0xD2f60c40fEbccf6311f8B47c4f2Ec6b040400086"
10+
PIL_LICENSE_TEMPLATE="0x2E896b0b2Fdb7457499B56AAaA4AE55BCB4Cd316"
611

712
def get_token_id(nft_contract, web3, account):
813
contract_abi = [
@@ -15,23 +20,26 @@ def get_token_id(nft_contract, web3, account):
1520
}
1621
]
1722

18-
# Fetch the current average gas price from the node plus 10%
19-
current_gas_price = int(web3.eth.gas_price * 1.1)
20-
2123
contract = web3.eth.contract(address=nft_contract, abi=contract_abi)
22-
transaction = contract.functions.mint(account.address).build_transaction({
23-
'from': account.address,
24-
'nonce': web3.eth.get_transaction_count(account.address),
25-
'gas': 2000000,
26-
'gasPrice': current_gas_price
27-
})
28-
signed_txn = account.sign_transaction(transaction)
29-
tx_hash = web3.eth.send_raw_transaction(signed_txn.raw_transaction)
30-
tx_receipt = web3.eth.wait_for_transaction_receipt(tx_hash)
24+
25+
try:
26+
transaction = contract.functions.mint(account.address).build_transaction({
27+
'from': account.address,
28+
'nonce': web3.eth.get_transaction_count(account.address),
29+
'gas': 2000000
30+
})
31+
32+
signed_txn = account.sign_transaction(transaction)
33+
tx_hash = web3.eth.send_raw_transaction(signed_txn.raw_transaction)
34+
tx_receipt = web3.eth.wait_for_transaction_receipt(tx_hash)
3135

32-
logs = tx_receipt['logs']
33-
if logs[0]['topics'][3]:
34-
return int(logs[0]['topics'][3].hex(), 16)
36+
logs = tx_receipt['logs']
37+
if len(logs) > 0 and len(logs[0]['topics']) > 3:
38+
return int(logs[0]['topics'][3].hex(), 16)
39+
raise ValueError(f"No token ID in logs: {tx_receipt}")
40+
41+
except Exception as e:
42+
raise e
3543

3644
def mint_tokens(erc20_contract_address, web3, account, to_address, amount):
3745
contract_abi = [

tests/integration/test_integration_ip_asset.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@ def test_register_ip_asset(story_client, child_ip_id):
4444
def test_register_ip_asset_with_metadata(story_client):
4545
token_id = get_token_id(MockERC721, story_client.web3, story_client.account)
4646
metadata = {
47-
'metadataURI': "test-uri",
48-
'metadataHash': web3.to_hex(web3.keccak(text="test-metadata-hash")),
49-
'nftMetadataHash': web3.to_hex(web3.keccak(text="test-nft-metadata-hash"))
47+
'ip_metadata_uri': "test-uri",
48+
'ip_metadata_hash': web3.to_hex(web3.keccak(text="test-metadata-hash")),
49+
'nft_metadata_uri': "test-nft-uri",
50+
'nft_metadata_hash': web3.to_hex(web3.keccak(text="test-nft-metadata-hash"))
5051
}
5152

5253
response = story_client.IPAsset.register(
@@ -143,6 +144,14 @@ def nft_collection(story_client):
143144
return txData['nftContract']
144145

145146
def test_mint_register_attach_terms(story_client, nft_collection):
147+
148+
metadata = {
149+
'ip_metadata_uri': "test-uri",
150+
'ip_metadata_hash': web3.to_hex(web3.keccak(text="test-metadata-hash")),
151+
'nft_metadata_uri': "test-nft-uri",
152+
'nft_metadata_hash': web3.to_hex(web3.keccak(text="test-nft-metadata-hash"))
153+
}
154+
146155
response = story_client.IPAsset.mintAndRegisterIpAssetWithPilTerms(
147156
spg_nft_contract=nft_collection,
148157
terms=[{
@@ -176,6 +185,7 @@ def test_mint_register_attach_terms(story_client, nft_collection):
176185
'expect_group_reward_pool': ZERO_ADDRESS
177186
}
178187
}],
188+
ip_metadata=metadata
179189
)
180190

181191
assert 'txHash' in response

0 commit comments

Comments
 (0)