@@ -505,7 +505,7 @@ NFT_TYPES_SOURCE = """resource NFT has store, create, consume, replace, burn, re
505505 royalty_bps: u16
506506}
507507
508- resource Collection has store, replace {
508+ resource Collection has store, create, replace {
509509 creator: Address
510510 total_supply: u64
511511 max_supply: u64
@@ -533,6 +533,18 @@ receipt RoyaltyPayment has create {
533533"""
534534
535535NFT_ACTION_SOURCES = {
536+ "create_collection": """
537+ action create_collection(creator: Address, max_supply: u64) -> collection: Collection
538+ where
539+ assert_invariant(max_supply > 0, "max supply must be positive")
540+ assert_invariant(max_supply <= 10000, "max supply too high")
541+
542+ create collection = Collection {
543+ creator: creator,
544+ total_supply: 0,
545+ max_supply: max_supply
546+ } with_lock(creator)
547+ """,
536548 "mint": """
537549action mint(collection_before: Collection, to: Address, metadata_hash: Hash) -> (collection_after: Collection, nft: NFT)
538550where
@@ -1460,6 +1472,7 @@ for action, source in LAUNCH_ACTION_SOURCES.items():
14601472
14611473ORIGINAL_SCOPED_ACTIONS = {
14621474 "nft.cell": [
1475+ "create_collection",
14631476 "mint",
14641477 "transfer",
14651478 "create_listing",
@@ -1512,6 +1525,7 @@ ORIGINAL_SCOPED_LOCK_FAIL_CLOSED = {}
15121525EXPECTED_SOURCE_ACTIONS = {
15131526 "token.cell": ["mint_with_authority", "transfer_token", "burn", "merge"],
15141527 "nft.cell": [
1528+ "create_collection",
15151529 "mint",
15161530 "transfer",
15171531 "create_listing",
@@ -2538,6 +2552,9 @@ def molecule_u32(value):
25382552def molecule_bytes(data):
25392553 return molecule_u32(len(data)) + data
25402554
2555+ def molecule_string_witness(data):
2556+ return molecule_bytes(molecule_bytes(data))
2557+
25412558def molecule_fixvec(items):
25422559 out = bytearray(molecule_u32(len(items)))
25432560 for item in items:
@@ -3920,7 +3937,36 @@ def build_nft_action_case(action_record, cellscript_lock, cellscript_type, desti
39203937 original_scoped = action_record.get("kind") == "original-scoped-action-strict"
39213938 flow_state = 0 if original_scoped else None
39223939
3923- if action == "mint":
3940+ if action == "create_collection":
3941+ name = b"Acceptance Collection"
3942+ symbol = b"ACPT"
3943+ base_uri = b"ckb://cellscript/nft/"
3944+ max_supply = 200
3945+ valid_collection_payload = (
3946+ collection_molecule_data(current_owner, 0, max_supply, name, symbol, base_uri)
3947+ if original_scoped
3948+ else collection_data(current_owner, 0, max_supply)
3949+ )
3950+ malformed_collection_payload = (
3951+ collection_molecule_data(current_owner, 1, max_supply, name, symbol, base_uri)
3952+ if original_scoped
3953+ else collection_data(current_owner, 1, max_supply)
3954+ )
3955+ witness = (
3956+ entry_witness(current_owner, max_supply, molecule_string_witness(name), molecule_string_witness(symbol), molecule_string_witness(base_uri))
3957+ if original_scoped
3958+ else entry_witness(current_owner, max_supply)
3959+ )
3960+ initial = create_script_locked_cells(
3961+ "nft.create_collection",
3962+ [{"capacity": 1000 * 100_000_000, "lock": cellscript_lock, "type": None, "data": b""}],
3963+ cell_deps,
3964+ )
3965+ input_cell = initial["cells"][0]
3966+ outputs = [{"capacity": hex_u64(1000 * 100_000_000), "lock": cellscript_lock, "type": cellscript_type}]
3967+ valid_tx = transaction(input_cell, outputs, ["0x" + valid_collection_payload.hex()], cell_deps, [witness])
3968+ malformed_tx = transaction(input_cell, outputs, ["0x" + malformed_collection_payload.hex()], cell_deps, [witness])
3969+ elif action == "mint":
39243970 input_collection_payload = (
39253971 collection_molecule_data(current_owner, 10, 1000)
39263972 if original_scoped
@@ -5855,7 +5901,7 @@ def run_stateful_nft_listing_sale(always_success_dep):
58555901 scenario = "nft.mint-list-transfer-by-listing"
58565902 actions = {
58575903 name: deploy_stateful_action(action_record_by(nft_action_artifacts, name), always_success_dep)
5858- for name in ("mint", "create_listing", "buy_from_listing")
5904+ for name in ("create_collection", " mint", "create_listing", "buy_from_listing")
58595905 }
58605906 collection_type = always_success_lock("0xc1")
58615907 nft_type = always_success_lock("0xc2")
@@ -5864,7 +5910,12 @@ def run_stateful_nft_listing_sale(always_success_dep):
58645910 seller = bytes([0x11]) * 32
58655911 buyer_lock = always_success_lock("0xc5")
58665912 buyer = decode_hex(script_hash(buyer_lock), 32)
5867- royalty_recipient = seller
5913+ collection_creator = actions["mint"]["lock_hash"]
5914+ royalty_recipient = collection_creator
5915+ collection_name = b"Stateful Collection"
5916+ collection_symbol = b"SNFT"
5917+ collection_base_uri = b"ckb://cellscript/stateful-nft/"
5918+ max_supply = 200
58685919 metadata_hash = bytes([0x33]) * 32
58695920 token_id = 1
58705921 price = 10_000
@@ -5874,32 +5925,51 @@ def run_stateful_nft_listing_sale(always_success_dep):
58745925 steps = []
58755926
58765927 initial = create_script_locked_cells(
5877- "stateful.nft.collection ",
5928+ "stateful.nft.collection_seed ",
58785929 [{
58795930 "capacity": 900 * 100_000_000,
5880- "lock": actions["mint "]["lock"],
5881- "type": collection_type ,
5882- "data": collection_molecule_data(seller, 0, 1000) ,
5931+ "lock": actions["create_collection "]["lock"],
5932+ "type": None ,
5933+ "data": b"" ,
58835934 }],
5884- actions["mint "]["cell_deps"],
5935+ actions["create_collection "]["cell_deps"],
58855936 )
5886- collection0 = initial["cells"][0]
5937+ collection_seed = initial["cells"][0]
58875938 tx1 = transaction(
5939+ collection_seed,
5940+ [{"capacity": hex_u64(800 * 100_000_000), "lock": actions["mint"]["lock"], "type": collection_type}],
5941+ ["0x" + collection_molecule_data(collection_creator, 0, max_supply, collection_name, collection_symbol, collection_base_uri).hex()],
5942+ actions["create_collection"]["cell_deps"],
5943+ [
5944+ entry_witness(
5945+ collection_creator,
5946+ max_supply,
5947+ molecule_string_witness(collection_name),
5948+ molecule_string_witness(collection_symbol),
5949+ molecule_string_witness(collection_base_uri),
5950+ )
5951+ ],
5952+ )
5953+ step = run_stateful_step(scenario, "create_collection_for_live_mint", tx1, [collection_seed])
5954+ steps.append(step)
5955+ collection0 = output_cell_from_tx(step["commit"], tx1, 0)
5956+
5957+ tx2 = transaction(
58885958 collection0,
58895959 [
58905960 {"capacity": hex_u64(500 * 100_000_000), "lock": actions["mint"]["lock"], "type": collection_type},
58915961 {"capacity": hex_u64(300 * 100_000_000), "lock": actions["buy_from_listing"]["lock"], "type": nft_type},
58925962 ],
58935963 [
5894- "0x" + collection_molecule_data(seller , token_id, 1000 ).hex(),
5964+ "0x" + collection_molecule_data(collection_creator , token_id, max_supply, collection_name, collection_symbol, collection_base_uri ).hex(),
58955965 "0x" + nft_data(token_id, seller, metadata_hash, royalty_recipient, 250).hex(),
58965966 ],
58975967 actions["mint"]["cell_deps"],
58985968 [entry_witness(seller, metadata_hash)],
58995969 )
5900- step = run_stateful_step(scenario, "mint_nft_for_listing_sale", tx1 , [collection0])
5970+ step = run_stateful_step(scenario, "mint_nft_for_listing_sale", tx2 , [collection0])
59015971 steps.append(step)
5902- nft_for_sale = output_cell_from_tx(step["commit"], tx1 , 1)
5972+ nft_for_sale = output_cell_from_tx(step["commit"], tx2 , 1)
59035973 nft_dep = cell_dep_for(nft_for_sale)
59045974
59055975 listing_initial = create_script_locked_cells(
@@ -5908,7 +5978,7 @@ def run_stateful_nft_listing_sale(always_success_dep):
59085978 actions["create_listing"]["cell_deps"],
59095979 )
59105980 listing_input = listing_initial["cells"][0]
5911- tx2 = transaction(
5981+ tx3 = transaction(
59125982 listing_input,
59135983 [
59145984 {"capacity": hex_u64(300 * 100_000_000), "lock": actions["buy_from_listing"]["lock"], "type": listing_type},
@@ -5921,11 +5991,11 @@ def run_stateful_nft_listing_sale(always_success_dep):
59215991 [nft_dep] + actions["create_listing"]["cell_deps"],
59225992 [entry_witness(price, created_at)],
59235993 )
5924- step = run_stateful_step(scenario, "create_listing_from_live_nft_dep", tx2 , [listing_input])
5994+ step = run_stateful_step(scenario, "create_listing_from_live_nft_dep", tx3 , [listing_input])
59255995 steps.append(step)
5926- listing = output_cell_from_tx(step["commit"], tx2 , 0)
5996+ listing = output_cell_from_tx(step["commit"], tx3 , 0)
59275997
5928- tx3 = transaction(
5998+ tx4 = transaction(
59295999 [nft_for_sale, listing],
59306000 [
59316001 {"capacity": hex_u64(300 * 100_000_000), "lock": buyer_lock, "type": nft_type},
@@ -5940,7 +6010,7 @@ def run_stateful_nft_listing_sale(always_success_dep):
59406010 actions["buy_from_listing"]["cell_deps"],
59416011 [entry_witness(buyer, seller, price), "0x"],
59426012 )
5943- step = run_stateful_step(scenario, "buy_listing_from_live_nft_and_listing", tx3 , [nft_for_sale, listing])
6013+ step = run_stateful_step(scenario, "buy_listing_from_live_nft_and_listing", tx4 , [nft_for_sale, listing])
59446014 steps.append(step)
59456015
59466016 return {
@@ -6561,6 +6631,7 @@ try:
65616631 "burn",
65626632 "buy_from_listing",
65636633 "cancel_listing",
6634+ "create_collection",
65646635 "create_listing",
65656636 "create_offer",
65666637 "mint",
0 commit comments