v3
The full v3 NFT program is shown below and fully annotated. The code is explained so that you may understand and modify this program for your own use.
Last updated
The full v3 NFT program is shown below and fully annotated. The code is explained so that you may understand and modify this program for your own use.
Last updated
// The 'leo_nft' program.
data1: u128, // Part 1 of the image data -- i.e., a way to link this nft to image or aws
data2: u128,
}
// base uri ascii bits. Include as many data pieces as necessary to encapsulate the uri. Padded with 0s at the end.
data0: u128, // Part 1 of the base uri in bits. Bits should be the representation of the hexadecimal bytes for the ASCII text of the URL
data1: u128,
data2: u128,
data3: u128
}
data: u128 // The sybmol's ascii text represented in bits, and the u128 value of the bitstring.
}
private owner: address,
private data: TokenId,
private edition: scalar, // which edition of the nft this particular one is -- will be 0 for unique NFTs
}
// a way to prove ownership of an nft privately
private owner: address,
private nft_owner: address,
private data: TokenId,
private edition: scalar, // which edition of the nft this particular one is -- will be 0 for unique NFTs
}
public total: u128,
public symbol: u128,
public base_uri: BaseURI,
) {
}
finalize initialize_collection(
public total: u128,
public symbol: u128,
public base_uri: BaseURI,
) {
// Ensure initialize cannot be called twice!
let is_initialized: u128 = settings.get_or_use(0u8, 0u128);
assert_eq(is_initialized, 0u128);
settings.set(1u8, total); // Number of total NFTs (first-editions) that can be minted
settings.set(2u8, 0u128); // Is the mint live
settings.set(3u8, symbol); // Symbol for the NFT
settings.set(4u8, base_uri.data0); // Base URI for NFT
settings.set(5u8, base_uri.data1);
settings.set(6u8, base_uri.data2);
settings.set(7u8, base_uri.data3);
settings.set(8u8, 0u128); // Block height for mint to go live (given mint is live setting)
settings.set(9u8, 0u128); // If collection is frozen
}
// Load the data into the mapping
// Enables someone to mint an NFT with provided image data
transition add_nft(public tokenId: TokenId, public edition: scalar) {
assert_eq(self.caller, aleo1gy3d0s00s2k7rmgqznnx2q8htmjm2p5rk8q40u5yklqhe44utvys0dmzdy);
let tokenEditionHash: field = BHP256::commit_to_field(tokenHash, edition);
return then finalize(tokenEditionHash);
}
finalize add_nft(public tokenEditionHash: field) {
let frozen: u128 = settings.get(9u8);
assert_eq(frozen, 0u128);
let existing_editions: u8 = nft_totals.get_or_use(tokenEditionHash, 255u8);
assert_eq(existing_editions, 255u8);
nft_totals.set(tokenEditionHash, 1u8);
// Reduce the amount of total nfts that can be minted
let remaining: u128 = settings.get(1u8);
settings.set(1u8, remaining - 1u128);
}
transition add_minter(public minter: address, public amount: u8) {
assert_eq(self.caller, aleo1gy3d0s00s2k7rmgqznnx2q8htmjm2p5rk8q40u5yklqhe44utvys0dmzdy);
return then finalize(minter, amount);
}
finalize add_minter(
public minter: address,
public amount: u8
)
{
let frozen: u128 = settings.get(9u8);
assert_eq(frozen, 0u128);
whitelist.set(minter, amount);
}
transition set_mint_status(public status: u128) {
assert_eq(self.caller, aleo1gy3d0s00s2k7rmgqznnx2q8htmjm2p5rk8q40u5yklqhe44utvys0dmzdy);
return then finalize(status);
}
finalize set_mint_status(public status: u128) {
let frozen: u128 = settings.get(9u8);
assert_eq(frozen, 0u128);
settings.set(2u8, status);
}
transition set_mint_block(public mint_block: u128) {
assert_eq(self.caller, aleo1gy3d0s00s2k7rmgqznnx2q8htmjm2p5rk8q40u5yklqhe44utvys0dmzdy);
return then finalize(mint_block);
}
finalize set_mint_block(public mint_block: u128) {
let frozen: u128 = settings.get(9u8);
assert_eq(frozen, 0u128);
settings.set(8u8, mint_block);
}
transition update_symbol(public symbol: u128) {
assert_eq(self.caller, aleo1gy3d0s00s2k7rmgqznnx2q8htmjm2p5rk8q40u5yklqhe44utvys0dmzdy);
return then finalize(symbol);
}
finalize update_symbol(public symbol: u128) {
let frozen: u128 = settings.get(9u8);
assert_eq(frozen, 0u128);
settings.set(3u8, symbol);
}
transition update_base_uri(public base_uri: BaseURI) {
assert_eq(self.caller, aleo1gy3d0s00s2k7rmgqznnx2q8htmjm2p5rk8q40u5yklqhe44utvys0dmzdy);
return then finalize(base_uri);
}
finalize update_base_uri(public base_uri: BaseURI) {
let frozen: u128 = settings.get(9u8);
assert_eq(frozen, 0u128);
settings.set(4u8, base_uri.data0); // Base URI for NFT
settings.set(5u8, base_uri.data1);
settings.set(6u8, base_uri.data2);
settings.set(7u8, base_uri.data3);
}
transition freeze() {
assert_eq(self.caller, aleo1gy3d0s00s2k7rmgqznnx2q8htmjm2p5rk8q40u5yklqhe44utvys0dmzdy);
return then finalize();
}
finalize freeze() {
let frozen: u128 = settings.get(9u8);
assert_eq(frozen, 0u128);
settings.set(9u8, 1u128);
}
let tokenHash: field = BHP256::hash_to_field(tokenId);
let tokenEditionHash: field = BHP256::commit_to_field(tokenHash, edition);
return NFT {
owner: self.caller,
data: tokenId,
edition
} then finalize(self.caller, tokenEditionHash);
}
finalize mint(public owner: address, public tokenEditionHash: field) {
// Ensure mint is live
let is_live: u128 = settings.get(2u8);
assert_eq(is_live, 1u128);
// Ensure owner can mint and decrease remaining mints (overflow protection)
let remaining: u8 = whitelist.get(owner);
whitelist.set(owner, remaining - 1u8);
// Ensure more editions can be made and decrease remaining editions (overflow protection)
let amount: u8 = nft_totals.get(tokenEditionHash);
nft_totals.set(tokenEditionHash, amount - 1u8);
}
transition transfer_private(
nft: NFT,
private receiver: address
) -> NFT
{
return NFT {
owner: receiver,
data: nft.data,
edition: nft.edition
};
}
transition transfer_public(
private receiver: address,
private data: TokenId,
private edition: scalar
)
{
let tokenHash: field = BHP256::hash_to_field(data);
let tokenEditionHash: field = BHP256::commit_to_field(tokenHash, edition);
let caller: address = self.caller;
return then finalize(receiver, tokenEditionHash, caller);
}
finalize transfer_public(
public receiver: address,
public tokenEditionHash: field,
public caller: address
)
{
assert_eq(caller, nft_owners.get(tokenEditionHash));
nft_owners.set(tokenEditionHash, receiver);
}
transition convert_private_to_public(
nft: NFT
)
{
let tokenHash: field = BHP256::hash_to_field(nft.data);
let tokenEditionHash: field = BHP256::commit_to_field(tokenHash, nft.edition);
return then finalize(nft.owner, tokenEditionHash);
}
finalize convert_private_to_public(
public owner: address,
public tokenEditionHash: field
)
{
nft_owners.set(tokenEditionHash, owner);
}
transition convert_public_to_private(
private owner: address,
private data: TokenId,
private edition: scalar
) -> NFT
{
assert_eq(owner, self.caller);
let tokenHash: field = BHP256::hash_to_field(data);
let tokenEditionHash: field = BHP256::commit_to_field(tokenHash, edition);
return NFT {
owner,
data,
edition
} then finalize(owner, tokenEditionHash);
}
finalize convert_public_to_private(
public owner: address,
public tokenEditionHash: field
)
{
assert_eq(owner, nft_owners.get(tokenEditionHash));
// mapping::remove is not implemented yet, so instead we set the owner to be a dummy address that cannot publicly transfer or convert to private
nft_owners.set(tokenEditionHash, aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc);
}
return (
NFT {
owner: nft.owner,
data: nft.data,
edition: nft.edition
},
NFT_ownership {
owner: prove_to,
nft_owner: nft.owner,
data: nft.data,
edition: nft.edition
}
);
}
}