Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions src/story_protocol_python_sdk/resources/IPAsset.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
from story_protocol_python_sdk.utils.sign import Sign
from story_protocol_python_sdk.utils.constants import ZERO_ADDRESS, ZERO_HASH

from story_protocol_python_sdk.abi.SPGNFTImpl.SPGNFTImpl_client import SPGNFTImplClient

class IPAsset:
"""
IPAssetClient allows you to create, get, and list IP Assets with Story
Expand Down Expand Up @@ -46,6 +48,43 @@ def __init__(self, web3: Web3, account, chain_id: int):
self.license_terms_util = LicenseTerms(web3)
self.sign_util = Sign(web3, self.chain_id, self.account)

def mint(
self,
nft_contract: str,
to_address: str,
metadata_uri: str,
metadata_hash: bytes,
allow_duplicates: bool = False,
tx_options: dict = None
):
spg_nft_client = SPGNFTImplClient(self.web3, contract_address=nft_contract)

def build_mint_transaction(to, metadata_uri, metadata_hash, allow_duplicates, transaction_options):
return spg_nft_client.contract.functions.mint(
to,
metadata_uri,
metadata_hash,
allow_duplicates
).build_transaction(transaction_options)

response = build_and_send_transaction(
self.web3,
self.account,
build_mint_transaction,
to_address,
metadata_uri,
metadata_hash,
allow_duplicates,
tx_options=tx_options
)

tx_hash = response['tx_hash']
# Ensure the transaction hash starts with "0x"
if isinstance(tx_hash, str) and not tx_hash.startswith('0x'):
tx_hash = '0x' + tx_hash

return tx_hash

def register(
self,
nft_contract: str,
Expand Down
210 changes: 210 additions & 0 deletions tests/integration/test_integration_ip_asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,3 +400,213 @@ def test_register_ip_and_attach_pil_terms(self, story_client, nft_collection, pa
assert isinstance(result['tx_hash'], str) and result['tx_hash']
assert isinstance(result['ip_id'], str) and result['ip_id']
assert isinstance(result['license_terms_ids'], list) and result['license_terms_ids']

# Add this test class to your existing test_integration_ip_asset.py file

class TestIPAssetMint:
@pytest.fixture(scope="module")
def nft_collection(self, story_client):
tx_data = story_client.NFTClient.create_nft_collection(
name="test-mint-collection",
symbol="MINT",
max_supply=100,
is_public_minting=True,
mint_open=True,
contract_uri="test-mint-uri",
mint_fee_recipient=account.address,
)
return tx_data['nft_contract']

def test_mint_basic(self, story_client, nft_collection):
"""Test basic minting functionality"""
metadata_uri = "https://example.com/metadata/1.json"
metadata_hash = web3.keccak(text="test-metadata-content")

response = story_client.IPAsset.mint(
nft_contract=nft_collection,
to_address=account.address,
metadata_uri=metadata_uri,
metadata_hash=metadata_hash,
allow_duplicates=False
)

assert response is not None
assert isinstance(response, str)
assert len(response) > 0
assert response.startswith("0x")

# Wait for transaction confirmation to verify it was successful
receipt = story_client.web3.eth.wait_for_transaction_receipt(response)
assert receipt.status == 1

def test_mint_with_duplicates_allowed(self, story_client, nft_collection):
"""Test minting with duplicate metadata allowed"""
metadata_uri = "https://example.com/metadata/duplicate.json"
metadata_hash = web3.keccak(text="duplicate-metadata-content")

# First mint
response1 = story_client.IPAsset.mint(
nft_contract=nft_collection,
to_address=account.address,
metadata_uri=metadata_uri,
metadata_hash=metadata_hash,
allow_duplicates=True
)

assert response1 is not None
receipt1 = story_client.web3.eth.wait_for_transaction_receipt(response1)
assert receipt1.status == 1

# Second mint with same metadata (should succeed with allow_duplicates=True)
response2 = story_client.IPAsset.mint(
nft_contract=nft_collection,
to_address=account.address,
metadata_uri=metadata_uri,
metadata_hash=metadata_hash,
allow_duplicates=True
)

assert response2 is not None
receipt2 = story_client.web3.eth.wait_for_transaction_receipt(response2)
assert receipt2.status == 1

# Verify different transaction hashes
assert response1 != response2

def test_mint_to_different_address(self, story_client, nft_collection):
"""Test minting to a different recipient address"""
# Create a different recipient address for testing
different_account = story_client.web3.eth.account.create()
recipient_address = different_account.address

metadata_uri = "https://example.com/metadata/different-recipient.json"
metadata_hash = web3.keccak(text="different-recipient-metadata")

response = story_client.IPAsset.mint(
nft_contract=nft_collection,
to_address=recipient_address,
metadata_uri=metadata_uri,
metadata_hash=metadata_hash,
allow_duplicates=False
)

assert response is not None
receipt = story_client.web3.eth.wait_for_transaction_receipt(response)
assert receipt.status == 1

def test_mint_with_various_metadata_formats(self, story_client, nft_collection):
"""Test minting with different metadata URI formats"""
test_cases = [
{
"uri": "ipfs://QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG",
"content": "ipfs-metadata"
},
{
"uri": "https://gateway.pinata.cloud/ipfs/QmTest123",
"content": "pinata-gateway-metadata"
},
{
"uri": "ar://abc123def456",
"content": "arweave-metadata"
},
{
"uri": "", # Empty URI
"content": "empty-uri-metadata"
}
]

for i, test_case in enumerate(test_cases):
metadata_hash = web3.keccak(text=f"{test_case['content']}-{i}")

response = story_client.IPAsset.mint(
nft_contract=nft_collection,
to_address=account.address,
metadata_uri=test_case["uri"],
metadata_hash=metadata_hash,
allow_duplicates=False
)

assert response is not None
receipt = story_client.web3.eth.wait_for_transaction_receipt(response)
assert receipt.status == 1

def test_mint_with_zero_hash(self, story_client, nft_collection):
"""Test minting with zero hash"""
metadata_uri = "https://example.com/metadata/zero-hash.json"
zero_hash = b'\x00' * 32 # 32 bytes of zeros

response = story_client.IPAsset.mint(
nft_contract=nft_collection,
to_address=account.address,
metadata_uri=metadata_uri,
metadata_hash=zero_hash,
allow_duplicates=False
)

assert response is not None
receipt = story_client.web3.eth.wait_for_transaction_receipt(response)
assert receipt.status == 1


def test_mint_error_cases(self, story_client, nft_collection):
"""Test various error cases for minting"""
metadata_uri = "https://example.com/metadata/error-test.json"
metadata_hash = web3.keccak(text="error-test-metadata")

# Test with invalid address format (not a valid hex address)
with pytest.raises(Exception):
story_client.IPAsset.mint(
nft_contract=nft_collection,
to_address="invalid-address-format",
metadata_uri=metadata_uri,
metadata_hash=metadata_hash,
allow_duplicates=False
)

# Test with invalid metadata hash format (wrong length - too short)
with pytest.raises(Exception):
story_client.IPAsset.mint(
nft_contract=nft_collection,
to_address=account.address,
metadata_uri=metadata_uri,
metadata_hash=b"too_short", # bytes32 should be 32 bytes
allow_duplicates=False
)

# Test with invalid metadata hash format (wrong length - too long)
with pytest.raises(Exception):
story_client.IPAsset.mint(
nft_contract=nft_collection,
to_address=account.address,
metadata_uri=metadata_uri,
metadata_hash=b"this_is_way_too_long_for_bytes32_format_and_should_fail",
allow_duplicates=False
)

def test_mint_with_existing_metadata_hash_no_duplicates(self, story_client, nft_collection):
"""Test that minting with existing metadata hash fails when duplicates not allowed"""
metadata_uri = "https://example.com/metadata/no-duplicates.json"
metadata_hash = web3.keccak(text="no-duplicates-metadata")

# First mint should succeed
response1 = story_client.IPAsset.mint(
nft_contract=nft_collection,
to_address=account.address,
metadata_uri=metadata_uri,
metadata_hash=metadata_hash,
allow_duplicates=False
)

assert response1 is not None
receipt1 = story_client.web3.eth.wait_for_transaction_receipt(response1)
assert receipt1.status == 1

# Second mint with same metadata hash should fail when allow_duplicates=False
with pytest.raises(Exception):
story_client.IPAsset.mint(
nft_contract=nft_collection,
to_address=account.address,
metadata_uri=metadata_uri,
metadata_hash=metadata_hash,
allow_duplicates=False
)