Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | 27x 27x 27x 27x 27x 27x 431x 431x 431x 431x 431x 431x 27x 61x 61x 61x 61x 61x 61x 61x 61x 61x 61x 61x 61x 61x 61x 61x 27x 54x 54x 54x 54x 54x 54x 54x 54x 54x 54x 54x 54x 54x 54x 54x 54x 27x 49x 49x 49x 49x 49x 49x 49x 49x | export { MinaNFTContract }; import { Field, state, State, method, SmartContract, UInt64, Signature, PublicKey, Poseidon, Bool, } from "o1js"; import { Update, Metadata, Storage } from "./metadata"; import { MinaNFTMetadataUpdateProof } from "./update"; import { EscrowTransfer, EscrowApproval } from "./escrow"; import { EscrowTransferProof } from "./transfer"; /** * MinaNFTContract is a smart contract that implements the Mina NFT standard. * @property name The name of the NFT. * @property metadata The metadata of the NFT. * @property storage The storage of the NFT - IPFS (i:...) or Arweave (a:...) hash string * @property owner The owner of the NFT - Poseidon hash of owner's public key * @property escrow The escrow of the NFT - Poseidon hash of three escrow's public keys * @property version The version of the NFT, increases by one with the changing of the metadata or the owner */ class MinaNFTContract extends SmartContract { @state(Field) name = State<Field>(); @state(Metadata) metadata = State<Metadata>(); @state(Storage) storage = State<Storage>(); @state(Field) owner = State<Field>(); @state(Field) escrow = State<Field>(); @state(UInt64) version = State<UInt64>(); /** * Update metadata of the NFT * @param update {@link Update} - data for the update * @param signature signature of the owner * @param owner owner's public key * @param proof {@link MinaNFTMetadataUpdateProof} - proof of the update of the metadata to be correctly inserted into the Merkle Map */ @method async update( update: Update, signature: Signature, owner: PublicKey, proof: MinaNFTMetadataUpdateProof ) { // Check that the metadata is correct const metadata = this.metadata.getAndRequireEquals(); Metadata.assertEquals(metadata, update.oldRoot); Metadata.assertEquals(metadata, proof.publicInput.oldRoot); Metadata.assertEquals(proof.publicInput.newRoot, update.newRoot); // Check that the proof verifies proof.verify(); signature.verify(owner, Update.toFields(update)).assertEquals(Bool(true)); //signature.verify(owner, [Field(30)]).assertEquals(Bool(true)); update.owner.assertEquals(Poseidon.hash(owner.toFields())); this.owner .getAndRequireEquals() .assertEquals(update.owner, "Owner mismatch"); this.name.getAndRequireEquals().assertEquals(update.name, "Name mismatch"); const version = this.version.getAndRequireEquals(); const newVersion: UInt64 = version.add(UInt64.from(1)); newVersion.assertEquals(update.version); this.metadata.set(update.newRoot); this.version.set(update.version); this.storage.set(update.storage); } /** * Transfer the NFT to new owner * @param data {@link EscrowTransfer} - data for the transfer * @param signature1 signature of the first escrow * @param signature2 signature of the second escrow * @param signature3 signature of the third escrow * @param escrow1 public key of the first escrow * @param escrow2 public key of the second escrow * @param escrow3 public key of the third escrow */ @method async escrowTransfer( data: EscrowTransfer, signature1: Signature, signature2: Signature, signature3: Signature, escrow1: PublicKey, escrow2: PublicKey, escrow3: PublicKey ) { this.owner .getAndRequireEquals() .assertEquals(data.oldOwner, "Owner mismatch"); const escrow = this.escrow.getAndRequireEquals(); escrow.assertNotEquals(Field(0), "Escrow is not set"); escrow.assertEquals(data.escrow); this.name.getAndRequireEquals().assertEquals(data.name, "Name mismatch"); const version = this.version.getAndRequireEquals(); const newVersion: UInt64 = version.add(UInt64.from(1)); newVersion.assertEquals(data.version); const dataFields = EscrowTransfer.toFields(data); signature1.verify(escrow1, dataFields).assertEquals(true); signature2.verify(escrow2, dataFields).assertEquals(true); signature3.verify(escrow3, dataFields).assertEquals(true); data.escrow.assertEquals( Poseidon.hash([ Poseidon.hash(escrow1.toFields()), Poseidon.hash(escrow2.toFields()), Poseidon.hash(escrow3.toFields()), ]) ); this.owner.set(data.newOwner); this.version.set(newVersion); this.escrow.set(Field(0)); } /** * Approve setting of the new escrow * @param proof {@link EscrowTransferProof} - escrow proof */ @method async approveEscrow(proof: EscrowTransferProof) { proof.verify(); this.owner .getAndRequireEquals() .assertEquals(proof.publicInput.owner, "Owner mismatch"); this.name .getAndRequireEquals() .assertEquals(proof.publicInput.approval.name, "Name mismatch"); const version = this.version.getAndRequireEquals(); const newVersion: UInt64 = version.add(UInt64.from(1)); newVersion.assertEquals(proof.publicInput.approval.version); this.version.set(proof.publicInput.approval.version); this.escrow.set(proof.publicInput.approval.escrow); } } |