Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- scilla_version 0
- (***************************************************)
- (* Associated library *)
- (***************************************************)
- import BoolUtils
- library NonfungibleToken
- (***************************************************)
- (* Product library *)
- (***************************************************)
- type Product =
- | Product of Uint256 Uint128 Uint128 Uint128 Uint128 Uint128 Bool
- (* uint256 id;*)
- (* uint256 price;*)
- (* uint256 available;*)
- (* uint256 supply;*)
- (* uint256 sold;*)
- (* uint256 interval;*)
- (* bool renewable;*)
- let unlimited_supply = Uint128 0
- let create_product =
- fun (_productId: Uint256) =>
- fun (_initialPrice: Uint128) =>
- fun (_initialInventoryQuantity: Uint128) =>
- fun (_supply: Uint128) =>
- fun (_interval: Uint128) =>
- let s = Uint128 0 in
- let r = False in
- Product _productId _initialPrice _initialInventoryQuantity _supply s _interval r
- type ChangeInventoryResult =
- | ChangeInventoryFailed
- | ChangeInventorySuccess of Product
- let increment_inventory =
- fun (p: Product) =>
- fun (_inventoryAdjustment: Uint128) =>
- match p with
- | Product id price available supply sold interval renewable =>
- let newInventoryLevel = builtin add available _inventoryAdjustment in
- let unlimited = builtin eq supply unlimited_supply in
- match unlimited with
- | True =>
- let np = Product id price newInventoryLevel supply sold interval renewable in
- ChangeInventorySuccess np
- | False =>
- let ns = builtin add sold newInventoryLevel in
- let uvs = builtin lt supply ns in
- match uvs with
- | True => ChangeInventoryFailed
- | False =>
- let np = Product id price newInventoryLevel supply sold interval renewable in
- ChangeInventorySuccess np
- end
- end
- end
- let decrement_inventory =
- fun (p: Product) =>
- fun (_inventoryAdjustment: Uint128) =>
- match p with
- | Product id price available supply sold interval renewable =>
- let newInventoryLevel = builtin sub available _inventoryAdjustment in
- let overflow = builtin lt available newInventoryLevel in
- match overflow with
- | True => ChangeInventoryFailed
- | False =>
- let np = Product id price newInventoryLevel supply sold interval renewable in
- ChangeInventorySuccess np
- end
- end
- type PurchaseInventoryResult =
- | PurchaseInventoryFailed
- | PurchaseInventorySuccess of Product
- let purchase_one_unit_in_stock =
- fun (p: Product) =>
- match p with
- | Product id price available supply sold interval renewable =>
- let os = builtin eq available unlimited_supply in
- match os with
- | True => PurchaseInventoryFailed
- | False =>
- let one = Uint128 1 in
- let ns = builtin add sold one in
- let na = builtin sub available one in
- let np = Product id price na supply ns interval renewable in
- PurchaseInventorySuccess np
- end
- end
- (***************************************************)
- (* DinoSeed library *)
- (***************************************************)
- type DinoSeed =
- | DinoSeed of Uint256 BNum
- (* uint256 genes;*)
- (* BNum bornBlock;*)
- (***************************************************)
- (* NonfungibleToken *)
- (***************************************************)
- let one_msg =
- fun (msg : Message) =>
- let nil_msg = Nil {Message} in
- Cons {Message} msg nil_msg
- (* Checks and see if an address is a contract owner *)
- let checkContractOwner =
- fun (msgSender: ByStr20) =>
- fun (owner: ByStr20) =>
- builtin eq msgSender owner
- (* Checks and see if an address is a token owner *)
- let isTokenOwner =
- fun (msgSender: ByStr20) =>
- fun (tokenOwner : Option ByStr20) =>
- match tokenOwner with
- | None => False
- | Some val =>
- builtin eq val msgSender
- end
- (* Checks if a given address is approved to make txn the given tokenID *)
- (* Not to be confused with isApprovedForAll *)
- let isApproved =
- fun (msgSender: ByStr20) =>
- fun (val: Option ByStr20) =>
- match val with
- | None => False
- | Some val =>
- builtin eq val msgSender
- end
- (* Checks if an message sender is approved by a given owner. (i.e. operator) *)
- let isApprovedForAll =
- fun (msgSender: ByStr20) =>
- fun (m: Option (Map (ByStr20) (Bool))) =>
- match m with
- | None => False
- (* owner did not assign anyone to the approval mapping *)
- | Some val =>
- (* val is of type Map (ByStr20) (Bool) *)
- let check_list = builtin get val msgSender in
- match check_list with
- | None => False
- | Some is_sender_approved =>
- (* check if sender has access rights *)
- match is_sender_approved with
- | True => True
- | False => False
- end
- end
- end
- (* Check if a sender is an operator of the owner, approved for the given ID *)
- (* or is the owner of the token *)
- let isApprovedOrOwner =
- fun (isOwner: Bool) =>
- fun (isApproved: Bool) =>
- fun (isApprovedForAll: Bool) =>
- let isOwnerOrApproved = orb isOwner isApproved in
- orb isOwnerOrApproved isApprovedForAll
- let isAuthorizedOrNotToContractHolder =
- fun (isAuthorized: Bool) =>
- fun (isToContracHoler: Option Bool) =>
- match isToContracHoler with
- | Some p =>
- match p with
- | True => isAuthorized
- | False => False
- end
- | None => isAuthorized
- end
- (* Error events *)
- let makeErrorEvent =
- fun (location: String) =>
- fun (errorCode: Uint32) =>
- {_eventname: "Error"; raisedAt: location; code: errorCode }
- (* Error codes *)
- let code_success = Uint32 0
- let code_failure = Uint32 1
- let code_not_authorized = Uint32 2
- let code_not_found = Uint32 4
- let code_bad_request = Uint32 5
- let code_token_exists = Uint32 6
- let code_product_exists = Uint32 7
- let code_invalid_quantity = Uint32 8
- let code_unexpected_error = Uint32 9
- let code_product_not_exists = Uint32 10
- let code_purchase_error = Uint32 20
- let code_not_implement_error = Uint32 255
- (***************************************************)
- (* The contract definition *)
- (***************************************************)
- contract NonfungibleToken
- (owner : ByStr20,
- name : String,
- symbol: String
- )
- (* mutable fields *)
- (* Mapping between tokenId to token owner *)
- field tokenOwnerMap: Map Uint256 ByStr20 = Emp Uint256 ByStr20
- (* Mapping from owner to number of owned tokens *)
- field ownedTokenCount: Map ByStr20 Uint256 = Emp ByStr20 Uint256
- (* Mapping between tokenId to approved address *)
- (* @dev: There can only be one approved address per token at a given time. *)
- field tokenApprovals: Map Uint256 ByStr20 = Emp Uint256 ByStr20
- (* Mapping from owner to operator approvals *)
- field operatorApprovals: Map ByStr20 (Map ByStr20 Bool)
- = Emp ByStr20 (Map ByStr20 Bool)
- field dinoSeedMap: Map Uint256 DinoSeed = Emp Uint256 DinoSeed
- field nonceSeed: Uint256 = Uint256 0
- field productsMap: Map Uint256 Product = Emp Uint256 Product
- field contractHolderMap: Map ByStr20 Bool = Emp ByStr20 Bool
- (* immutable field *)
- (* @notice Count all NFTs assigned to an owner *)
- transition balanceOf(address: ByStr20)
- optionBal <- ownedTokenCount[address];
- balance = match optionBal with
- | Some bal => bal
- | None => Uint256 0
- end;
- e = {_eventname: "balanceOf"; bal: balance};
- event e
- end
- (* Get the owner of a particular tokenId *)
- transition ownerOf(tokenId: Uint256)
- someVal <- tokenOwnerMap[tokenId];
- match someVal with
- | Some val =>
- e = {_eventname: "ownerOf"; id: tokenId; owner: val};
- event e
- | None =>
- e = let raisedAt = "ownerOf" in makeErrorEvent raisedAt code_not_found;
- event e
- end
- end
- (* @dev: TODO whitelist contract address can mint the token*)
- (* @dev: Mint new tokens. Only `contractOwner`, '_this_address' can mint the token*)
- (* @param: to - address of the token recipient *)
- (* @param: tokenId - token id of the new token *)
- (* Returns error message code_token_exist if token exists *)
- transition mint(to: ByStr20, tokenId: Uint256)
- (* Sender must be the contract owner *)
- isOwner = checkContractOwner owner _sender;
- isThisContract = checkContractOwner _this_address _sender;
- isAuthorized = orb isOwner isThisContract;
- match isAuthorized with
- | True =>
- (* Check if token exists *)
- tokenExist <- exists tokenOwnerMap[tokenId];
- match tokenExist with
- | True =>
- (* Token exists, return error code *)
- e = let raisedAt = "mint" in makeErrorEvent raisedAt code_token_exists;
- event e
- | False =>
- (* Mint token *)
- tokenOwnerMap[tokenId] := to;
- (* add to owner count *)
- userCnt <- ownedTokenCount[to];
- match userCnt with
- | Some val =>
- (* Append to existing results *)
- newVal= let one = Uint256 1 in builtin add val one;
- ownedTokenCount[to] := newVal
- | None =>
- (* User does not have existing tokens *)
- newVal = Uint256 1;
- ownedTokenCount[to] := newVal
- end;
- (* Emit success event *)
- e = {_eventname: "Mint successful"; by: _sender; recipient: to; token: tokenId};
- event e
- end
- | False =>
- (* Unauthorized transaction - sender is not the contract owner*)
- e = let raisedAt = "mint" in makeErrorEvent raisedAt code_not_authorized;
- event e
- end
- end
- (* @dev Transfer the ownership of a given token ID to another address *)
- (* @param from: Current owner of the token *)
- (* @param to: Recipient address of the token *)
- (* @param tokenId uint256 id of the token to be transferred *)
- transition transferFrom(from: ByStr20, to: ByStr20, tokenId: Uint256)
- copy_tokenOwner <- tokenOwnerMap[tokenId];
- copy_tokenApprovals <- tokenApprovals[tokenId];
- (* Get tokenOwner ByStr20 *)
- getTokenOwner <- tokenOwnerMap[tokenId];
- match getTokenOwner with
- | None =>
- (* Token not found *)
- e = let raisedAt = "transferFrom" in makeErrorEvent raisedAt code_not_found;
- event e
- | Some tokenOwner =>
- copy_operatorApproval <- operatorApprovals[tokenOwner];
- (* Libary functions to check for conditions *)
- checkOwner = isTokenOwner _sender copy_tokenOwner;
- checkApproved = isApproved _sender copy_tokenApprovals;
- checkApprovedForAll = isApprovedForAll _sender copy_operatorApproval;
- (* Checks if the `from` is indeed the owner of the token *)
- isFromTokenOwner = builtin eq tokenOwner from;
- match isFromTokenOwner with
- | False =>
- (* From address is not the same as the tokenOwner *)
- e = let raisedAt = "transferFrom" in makeErrorEvent raisedAt code_bad_request;
- event e
- | True =>
- (* isApprovedOrOwner checks if any of the three conditions are met *)
- isAuthorized = isApprovedOrOwner checkOwner checkApproved checkApprovedForAll;
- isToContracHoler <- contractHolderMap[to];
- isAuthorized2 = isAuthorizedOrNotToContractHolder isAuthorized isToContracHoler;
- match isAuthorized2 with
- | True =>
- (* Remove from Approval *)
- match checkApproved with
- | True =>
- (* Remove entry from approvals at the token level *)
- delete tokenApprovals[tokenId]
- | False =>
- end;
- (* Change tokenOwnerMap *)
- tokenOwnerMap[tokenId] := to;
- (* Change Count *)
- (*subtract one from previous token owner *)
- somePrevBal <- ownedTokenCount[from];
- match somePrevBal with
- | Some prevBal =>
- newBal = let one = Uint256 1 in builtin sub prevBal one;
- ownedTokenCount[from] := newBal
- | None =>
- e = let raisedAt = "transferFrom" in makeErrorEvent raisedAt code_unexpected_error;
- event e
- end;
- (* add one to the new token owner *)
- userCnt <- ownedTokenCount[to];
- (* Calculate the new token count value for recipient *)
- newVal = let one = Uint256 1 in match userCnt with
- | Some val =>
- (* Add to existing value *)
- builtin add val one
- | None => one
- end;
- ownedTokenCount[to] := newVal;
- (* check and notify to contract Holder *)
- e = {_eventname: "transferFrom successful"; from: _sender; recipient: to; token: tokenId};
- event e
- | False =>
- (* Unauthorized transaction *)
- e = let raisedAt = "transferFrom" in makeErrorEvent raisedAt code_not_authorized;
- event e
- end
- end
- end
- end
- (* @dev: Approves another address to transfer the given token ID *)
- (* - There can only be one approved address per token at a given time *)
- (* - Absence of entry in tokenApproval indicates there is no approved address *)
- (* param: to ByStr20 to be approved for the given token id *)
- (* param: tokenId uint256 id of the token to be apporved *)
- transition approve(to: ByStr20, tokenId: Uint256)
- copy_tokenOwner <- tokenOwnerMap[tokenId];
- (* Get tokenOwner ByStr20 *)
- getTokenOwner <- tokenOwnerMap[tokenId];
- match getTokenOwner with
- | None =>
- (* Token not found *)
- e = let raisedAt = "approve" in makeErrorEvent raisedAt code_not_found;
- event e
- | Some tokenOwner =>
- copy_operatorApproval <- operatorApprovals[tokenOwner];
- checkApprovedForAll = isApprovedForAll _sender copy_operatorApproval;
- checkOwner = isTokenOwner _sender copy_tokenOwner;
- isAuthorized = orb checkApprovedForAll checkOwner;
- match isAuthorized with
- | True =>
- (* add to token approval mapping *)
- tokenApprovals[tokenId] := to;
- (* Emit event *)
- e = {_eventname: "Approve successful"; from: _sender; approvedTo: to; token: tokenId};
- event e
- | False =>
- (* Unauthorized transaction *)
- e = let raisedAt = "approve" in makeErrorEvent raisedAt code_not_authorized;
- event e
- end
- end
- end
- (* @dev: sets or unsets the approval of a given operator *)
- (* @param: address to be set or unset as operator *)
- (* @param: approved - status of the approval to be set *)
- transition setApprovalForAll(to: ByStr20, approved: Bool)
- (* Checks if the _sender is approving himself *)
- isValidOperation = let check = builtin eq _sender to in negb check;
- (* require _sender is not approving himself *)
- match isValidOperation with
- | True =>
- (* Check if sender has an existing record on the operatorApproval *)
- operatorApprovals[_sender][to] := approved;
- (* Stringify boolean value to be emitted in the event *)
- approvedStr = bool_to_string approved;
- e = {_eventname: "setApprovalForAll successful"; from: _sender; recipient: to; status: approvedStr};
- event e
- | False =>
- e = let raisedAt = "setApprovalForAll" in makeErrorEvent raisedAt code_not_authorized;
- event e
- end
- end
- (* uint256 id;*)
- (* uint256 price;*)
- (* uint256 available;*)
- (* uint256 supply;*)
- (* uint256 sold;*)
- (* uint256 interval;*)
- (* bool renewable;*)
- transition createProduct(productId: Uint256, initialPrice: Uint128, initialInventoryQuantity: Uint128, supply: Uint128, interval: Uint128)
- isAuthorized = checkContractOwner owner _sender;
- match isAuthorized with
- | True =>
- copy_product <- productsMap[productId];
- match copy_product with
- | Some _ =>
- e = let raisedAt = "createProduct" in makeErrorEvent raisedAt code_product_exists;
- event e
- | None =>
- ivq = builtin lt supply initialInventoryQuantity;
- match ivq with
- | True =>
- e = let raisedAt = "createProduct" in makeErrorEvent raisedAt code_invalid_quantity;
- event e
- | False =>
- p = create_product productId initialPrice initialInventoryQuantity supply interval;
- productsMap[productId] := p;
- e = {_eventname: "createProduct successful"; id: productId};
- event e
- end
- end
- | False =>
- (* Unauthorized transaction - sender is not the contract owner*)
- e = let raisedAt = "createProduct" in makeErrorEvent raisedAt code_not_authorized;
- event e
- end
- end
- transition purchaseProduct(productId: Uint256)
- copy_product <- productsMap[productId];
- match copy_product with
- | Some p =>
- match p with
- | Product id price available supply sold interval renewable =>
- vp = builtin eq _amount price;
- match vp with
- | False =>
- e = let raisedAt = "purchaseProduct" in makeErrorEvent raisedAt code_purchase_error;
- event e
- | True =>
- po = purchase_one_unit_in_stock p;
- match po with
- | PurchaseInventoryFailed =>
- e = let raisedAt = "purchaseProduct" in makeErrorEvent raisedAt code_purchase_error;
- event e
- | PurchaseInventorySuccess np =>
- productsMap[productId] := np;
- x <- & BLOCKNUMBER;
- (*TODO this must is genes*)
- attributes = productId;
- dn = DinoSeed attributes x;
- n <- nonceSeed;
- one256 = Uint256 1;
- nid = builtin add n one256;
- nonceSeed := nid;
- dinoSeedMap[nid] := dn;
- accept;
- msg = {_tag : "mint"; _recipient : _this_address; _amount : Uint128 0;
- to : _sender; tokenId : nid};
- msgs = one_msg msg;
- send msgs;
- e = {_eventname: "purchaseProduct successful"; id: nid};
- event e
- end
- end
- end
- | None =>
- e = let raisedAt = "purchaseProduct" in makeErrorEvent raisedAt code_product_not_exists;
- event e
- end
- end
- transition setHolderStatus(holder: ByStr20, b: Bool)
- isAuthorized = checkContractOwner owner _sender;
- match isAuthorized with
- | True =>
- contractHolderMap[holder] := b;
- (* Emit success event *)
- e = {_eventname: "setHolderStatus successful"; by: _this_address; recipient: _sender; approved: b};
- event e
- | False =>
- (* Unauthorized transaction - sender is not the contract owner*)
- e = let raisedAt = "setHolderStatus" in makeErrorEvent raisedAt code_not_authorized;
- event e
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement