Ανατομία των έξυπνων συμβολαίων
Τελευταία επεξεργασία: @wackerow(opens in a new tab), 14 Ιουνίου 2024
Ένα έξυπνο συμβόλαιο είναι ένα πρόγραμμα που τρέχει σε μια διεύθυνση στο Ethereum. Αποτελούνται από δεδομένα και λειτουργίες που μπορούν να εκτελεστούν κατά τη λήψη μιας συναλλαγής. Εδώ είναι μια επισκόπηση του τι αποτελεί ένα έξυπνο συμβόλαιο.
Προαπαιτούμενα
Βεβαιωθείτε ότι έχετε διαβάσει πρώτα για τα έξυπνα συμβόλαια. Για την ανάγνωση αυτού του εγγράφου θεωρείται ότι είστε ήδη εξοικειωμένοι με γλώσσες προγραμματισμού, όπως η JavaScript ή η Python.
Δεδομένα
Τυχόν δεδομένα του συμβολαίου πρέπει να ανατεθούν σε μια τοποθεσία: είτε σε storage
ή memory
. Απαιτεί αρκετό κόστος η τροποποίηση του αποθηκευτικού χώρου σε ένα έξυπνο συμβόλαιο, για αυτόν τον λόγο θα πρέπει να εξετάσετε προσεκτικά πού αποθηκεύονται τα δεδομένα σας.
Αποθηκευτικός χώρος
Τα μόνιμα δεδομένα αναφέρονται ως αποθηκευτικά δεδομένα και αντιπροσωπεύονται από μεταβλητές της κατάστασης. Αυτές οι τιμές αποθηκεύονται μόνιμα στην κρυπτοαλυσίδα. Πρέπει να δηλώσετε τον τύπο, έτσι ώστε το συμβόλαιο να μπορεί να παρακολουθεί πόσο αποθηκευτικό χώρο χρειάζεται στο blockchain για τη μεταγλώττιση.
1// Solidity example2contract SimpleStorage {3 uint storedData; // State variable4 // ...5}Αντιγραφή
1# Vyper example2storedData: int128Αντιγραφή
Εάν έχετε ήδη προγραμματίσει αντικειμενοστρεφείς γλώσσες, πιθανότατα θα είστε εξοικειωμένοι με τους περισσότερους τύπους. Ωστόσο, η διεύθυνση
θα πρέπει να είναι νέα για εσάς, εάν είστε νέοι στην ανάπτυξη του Ethereum.
Ένας τύπος address
μπορεί να περιέχει μια διεύθυνση Ethereum που ισοδυναμεί με 20 bytes ή 160 bits. Επιστρέφει σε δεκαεξαδικό συμβολισμό με αρχικό 0x.
Άλλοι τύποι περιλαμβάνουν:
- boolean
- integer
- αριθμοί σταθερών σημείων
- πίνακες byte σταθερού μεγέθους
- πίνακες byte δυναμικού μεγέθους
- Ορθολογικά και ακέραια κυριολεκτήματα
- Κυριολεκτήματα συμβολοσειράς
- Δεκαεξαδικά γράμματα
- Αριθμοί
Για περισσότερες επεξηγήσεις, ρίξτε μια ματιά στα έγγραφα:
Μνήμη
Οι αξίες που αποθηκεύονται μόνο για τη διάρκεια της εκτέλεσης μιας συνάρτησης συμβολαίου ονομάζονται μεταβλητές μνήμης. Δεδομένου ότι αυτές δεν αποθηκεύονται μόνιμα στο blockchain, η χρήση τους είναι πολύ φθηνότερη.
Μάθετε περισσότερα σχετικά με τον τρόπο με τον οποίο το EVM αποθηκεύει δεδομένα (Αποθήκευση, Μνήμη και Στοίβα) στα Έγγραφα Solidity(opens in a new tab).
Μεταβλητές περιβάλλοντος
Εκτός από τις μεταβλητές που ορίζετε στο συμβόλαιό σας, υπάρχουν ορισμένες ειδικές καθολικές μεταβλητές. Χρησιμοποιούνται κυρίως για την παροχή πληροφοριών σχετικά με το blockchain ή την τρέχουσα συναλλαγή.
Παραδείγματα:
Ρύθμιση | Μεταβλητή κατάστασης | Περιγραφή |
---|---|---|
block.timestamp | uint256 | Χρονική σήμανση τρέχουσας εποχής μπλοκ |
msg.sender | διεύθυνση | Αποστολέας του μηνύματος (τρέχουσα κλήση) |
Συναρτήσεις
Με τους πιο απλοϊκούς όρους, οι συναρτήσεις μπορούν να λάβουν πληροφορίες ή να ορίσουν πληροφορίες ως απάντηση στις εισερχόμενες συναλλαγές.
Υπάρχουν δύο τύποι κλήσεων συναρτήσεων:
internal
– αυτές δε δημιουργούν κλήση EVM- Οι εσωτερικές συναρτήσεις και οι μεταβλητές κατάστασης μπορούν να προσπελαστούν μόνο εσωτερικά (δηλαδή μέσα από το τρέχον συμβόλαιο ή συμβόλαια που προκύπτουν από αυτό)
external
– αυτές δημιουργούν κλήση EVM- Οι εξωτερικές συναρτήσεις αποτελούν μέρος της διεπαφής συμβολαίου, πράγμα που σημαίνει ότι μπορούν να κληθούν από άλλα συμβόλαια και μέσω συναλλαγών. Μια εξωτερική συνάρτηση
f
δεν μπορεί να κληθεί εσωτερικά (δηλαδή ηf()
δεν λειτουργεί, αλλά ηthis.f()
λειτουργεί).
- Οι εξωτερικές συναρτήσεις αποτελούν μέρος της διεπαφής συμβολαίου, πράγμα που σημαίνει ότι μπορούν να κληθούν από άλλα συμβόλαια και μέσω συναλλαγών. Μια εξωτερική συνάρτηση
Μπορούν επίσης να είναι public
ή private
- Οι συναρτήσεις
public
μπορούν να κληθούν εσωτερικά μέσα από το συμβόλαιο ή εξωτερικά μέσω μηνυμάτων - Οι συναρτήσεις
private
είναι ορατές μόνο για το συμβόλαιο στο οποίο ορίζονται και όχι σε παράγωγα συμβόλαια
Τόσο οι συναρτήσεις όσο και οι μεταβλητές κατάστασης μπορούν να γίνουν δημόσιες ή ιδιωτικές
Ακολουθεί μια συνάρτηση για την ενημέρωση μεταβλητής κατάστασης σε ένα συμβόλαιο:
1// Solidity example2function update_name(string value) public {3 dapp_name = value;4}Αντιγραφή
- Η παράμετρος
value
του τύπουstring
μεταβιβάζεται στη συνάρτηση:update_name
- Έχει δηλωθεί
public
, που σημαίνει ότι μπορεί ο οποιοσδήποτε να έχει πρόσβαση σε αυτή - Δεν έχει δηλωθεί
view
, επομένως μπορεί να τροποποιήσει την κατάσταση του συμβολαίου
Προβολή συναρτήσεων
Αυτές οι συναρτήσεις υπόσχονται να μην τροποποιήσουν την κατάσταση των δεδομένων του συμβολαίου. Συνηθισμένα παραδείγματα είναι οι συναρτήσεις «getter» — μπορείτε να το χρησιμοποιήσετε για να λάβετε το υπόλοιπο ενός χρήστη, για παράδειγμα.
1// Solidity example2function balanceOf(address _owner) public view returns (uint256 _balance) {3 return ownerPizzaCount[_owner];4}Αντιγραφή
1dappName: public(string)23@view4@public5def readName() -> string:6 return dappNameΑντιγραφή
Τι θεωρείται τροποποίηση κατάστασης:
- Εγγραφή σε μεταβλητές κατάστασης.
- Εκπομπή συμβάντων(opens in a new tab).
- Δημιουργία άλλων συμβολαίων(opens in a new tab).
- Χρήση
selfdestruct
. - Αποστολή ether μέσω κλήσεων.
- Κλήση οποιασδήποτε συνάρτησης που δεν έχει επισημανθεί
view
ήpure
. - Χρήση κλήσεων χαμηλού επιπέδου.
- Χρήση ενσωματωμένης διάταξης που περιέχει συγκεκριμένους Opcodes.
Συναρτήσεις κατασκευαστή
Οι συναρτήσεις constructor
εκτελούνται μόνο μία φορά κατά την αρχική ανάπτυξη του συμβολαίου. Όπως το constructor
σε πολλές γλώσσες προγραμματισμού που βασίζονται σε κλάσεις, αυτές οι συναρτήσεις συχνά αρχικοποιούν τις μεταβλητές κατάστασης στις καθορισμένες τιμές τους.
1// Solidity example2// Initializes the contract's data, setting the `owner`3// to the address of the contract creator.4constructor() public {5 // All smart contracts rely on external transactions to trigger its functions.6 // `msg` is a global variable that includes relevant data on the given transaction,7 // such as the address of the sender and the ETH value included in the transaction.8 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties9 owner = msg.sender;10}Εμφάνιση όλωνΑντιγραφή
1# Vyper example23@external4def __init__(_beneficiary: address, _bidding_time: uint256):5 self.beneficiary = _beneficiary6 self.auctionStart = block.timestamp7 self.auctionEnd = self.auctionStart + _bidding_timeΑντιγραφή
Ενσωματωμένες μεταβλητές
Εκτός από τις μεταβλητές και τις συναρτήσεις που ορίζετε στο συμβόλαιό σας, υπάρχουν ορισμένες ειδικές ενσωματωμένες συναρτήσεις. Το πιο προφανές παράδειγμα είναι:
address.send()
– Soliditysend(address)
– Vyper
Αυτά επιτρέπουν στα συμβόλαια να στέλνουν ETH σε άλλους λογαριασμούς.
Σύνταξη μεταβλητών
Η μεταβλητή σας χρειάζεται:
- Παραμέτρους και τύπο μεταβλητής (εάν δέχεται παραμέτρους).
- Διασάφηση εσωτερική ή εξωτερική.
- δήλωση καθαρού/προβολή/πληρωτέο
- Τύπος απόδοσης (αν επιστρέφει μια τιμή).
1pragma solidity >=0.4.0 <=0.6.0;23contract ExampleDapp {4 string dapp_name; // state variable56 // Called when the contract is deployed and initializes the value7 constructor() public {8 dapp_name = "My Example dapp";9 }1011 // Get Function12 function read_name() public view returns(string) {13 return dapp_name;14 }1516 // Set Function17 function update_name(string value) public {18 dapp_name = value;19 }20}Εμφάνιση όλωνΑντιγραφή
Ένα πλήρες συμβόλαιο μπορεί να μοιάζει κάπως έτσι. Η συνάρτηση constructor
παρέχει μια αρχική τιμή για τη μεταβλητή dapp_name
.
Γεγονότα και αρχεία καταγραφής
Τα συμβάντα επιτρέπουν στο έξυπνο συμβόλαιό σας να επικοινωνεί με το περιβάλλον frontend σας ή άλλες συνδρομητικές εφαρμογές. Μόλις μια συναλλαγή επικυρωθεί και προστεθεί σε ένα μπλοκ, τα έξυπνα συμβόλαια μπορούν να εκπέμπουν συμβάντα και πληροφορίες καταγραφής, τα οποία στη συνέχεια το frontend μπορεί να επεξεργαστεί και να χρησιμοποιήσει.
Παραδείγματα με σχολιασμό
Αυτά είναι μερικά παραδείγματα γραμμένα σε Solidity. Εάν θέλετε να παίξετε με τον κώδικα, μπορείτε να αλληλεπιδράσετε μαζί του στο Remix(opens in a new tab).
Hello world
1// Specifies the version of Solidity, using semantic versioning.2// Learn more: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma3pragma solidity ^0.5.10;45// Defines a contract named `HelloWorld`.6// A contract is a collection of functions and data (its state).7// Once deployed, a contract resides at a specific address on the Ethereum blockchain.8// Learn more: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html9contract HelloWorld {1011 // Declares a state variable `message` of type `string`.12 // State variables are variables whose values are permanently stored in contract storage.13 // The keyword `public` makes variables accessible from outside a contract14 // and creates a function that other contracts or clients can call to access the value.15 string public message;1617 // Similar to many class-based object-oriented languages, a constructor is18 // a special function that is only executed upon contract creation.19 // Constructors are used to initialize the contract's data.20 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors21 constructor(string memory initMessage) public {22 // Accepts a string argument `initMessage` and sets the value23 // into the contract's `message` storage variable).24 message = initMessage;25 }2627 // A public function that accepts a string argument28 // and updates the `message` storage variable.29 function update(string memory newMessage) public {30 message = newMessage;31 }32}Εμφάνιση όλωνΑντιγραφή
Κρυπτονόμισμα
1pragma solidity ^0.5.10;23contract Token {4 // An `address` is comparable to an email address - it's used to identify an account on Ethereum.5 // Addresses can represent a smart contract or an external (user) accounts.6 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/types.html#address7 address public owner;89 // A `mapping` is essentially a hash table data structure.10 // This `mapping` assigns an unsigned integer (the token balance) to an address (the token holder).11 // Μάθετε περισσότερα: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types12 mapping (address => uint) public balances;1314 // Τα γεγονότα επιτρέπουν την καταγραφή ενεργειών στην αλυσίδα μπλοκ.15 // Ethereum clients can listen for events in order to react to contract state changes.16 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events17 event Transfer(address from, address to, uint amount);1819 // Initializes the contract's data, setting the `owner`20 // to the address of the contract creator.21 constructor() public {22 // All smart contracts rely on external transactions to trigger its functions.23 // `msg` is a global variable that includes relevant data on the given transaction,24 // such as the address of the sender and the ETH value included in the transaction.25 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties26 owner = msg.sender;27 }2829 // Creates an amount of new tokens and sends them to an address.30 function mint(address receiver, uint amount) public {31 // `require` is a control structure used to enforce certain conditions.32 // If a `require` statement evaluates to `false`, an exception is triggered,33 // which reverts all changes made to the state during the current call.34 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions3536 // Only the contract owner can call this function37 require(msg.sender == owner, "You are not the owner.");3839 // Enforces a maximum amount of tokens40 require(amount < 1e60, "Maximum issuance exceeded");4142 // Increases the balance of `receiver` by `amount`43 balances[receiver] += amount;44 }4546 // Sends an amount of existing tokens from any caller to an address.47 function transfer(address receiver, uint amount) public {48 // The sender must have enough tokens to send49 require(amount <= balances[msg.sender], "Insufficient balance.");5051 // Adjusts token balances of the two addresses52 balances[msg.sender] -= amount;53 balances[receiver] += amount;5455 // Emits the event defined earlier56 emit Transfer(msg.sender, receiver, amount);57 }58}Εμφάνιση όλωνΑντιγραφή
Μοναδικό ψηφιακό στοιχείο
1pragma solidity ^0.5.10;23// Imports symbols from other files into the current contract.4// In this case, a series of helper contracts from OpenZeppelin.5// Learn more: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#importing-other-source-files67import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol";8import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";9import "../node_modules/@openzeppelin/contracts/introspection/ERC165.sol";10import "../node_modules/@openzeppelin/contracts/math/SafeMath.sol";1112// The `is` keyword is used to inherit functions and keywords from external contracts.13// In this case, `CryptoPizza` inherits from the `IERC721` and `ERC165` contracts.14// Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#inheritance15contract CryptoPizza is IERC721, ERC165 {16 // Uses OpenZeppelin's SafeMath library to perform arithmetic operations safely.17 // Learn more: https://docs.openzeppelin.com/contracts/2.x/api/math#SafeMath18 using SafeMath for uint256;1920 // Constant state variables in Solidity are similar to other languages21 // but you must assign from an expression which is constant at compile time.22 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constant-state-variables23 uint256 constant dnaDigits = 10;24 uint256 constant dnaModulus = 10 ** dnaDigits;25 bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;2627 // Struct types let you define your own type28 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/types.html#structs29 struct Pizza {30 string name;31 uint256 dna;32 }3334 // Creates an empty array of Pizza structs35 Pizza[] public pizzas;3637 // Mapping from pizza ID to its owner's address38 mapping(uint256 => address) public pizzaToOwner;3940 // Mapping from owner's address to number of owned token41 mapping(address => uint256) public ownerPizzaCount;4243 // Mapping from token ID to approved address44 mapping(uint256 => address) pizzaApprovals;4546 // You can nest mappings, this example maps owner to operator approvals47 mapping(address => mapping(address => bool)) private operatorApprovals;4849 // Internal function to create a random Pizza from string (name) and DNA50 function _createPizza(string memory _name, uint256 _dna)51 // The `internal` keyword means this function is only visible52 // within this contract and contracts that derive this contract53 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#visibility-and-getters54 internal55 // `isUnique` is a function modifier that checks if the pizza already exists56 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers57 isUnique(_name, _dna)58 {59 // Adds Pizza to array of Pizzas and get id60 uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1);6162 // Checks that Pizza owner is the same as current user63 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions6465 // note that address(0) is the zero address,66 // indicating that pizza[id] is not yet allocated to a particular user.6768 assert(pizzaToOwner[id] == address(0));6970 // Maps the Pizza to the owner71 pizzaToOwner[id] = msg.sender;72 ownerPizzaCount[msg.sender] = SafeMath.add(73 ownerPizzaCount[msg.sender],74 175 );76 }7778 // Creates a random Pizza from string (name)79 function createRandomPizza(string memory _name) public {80 uint256 randDna = generateRandomDna(_name, msg.sender);81 _createPizza(_name, randDna);82 }8384 // Generates random DNA from string (name) and address of the owner (creator)85 function generateRandomDna(string memory _str, address _owner)86 public87 // Functions marked as `pure` promise not to read from or modify the state88 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions89 pure90 returns (uint256)91 {92 // Generates random uint from string (name) + address (owner)93 uint256 rand = uint256(keccak256(abi.encodePacked(_str))) +94 uint256(_owner);95 rand = rand % dnaModulus;96 return rand;97 }9899 // Returns array of Pizzas found by owner100 function getPizzasByOwner(address _owner)101 public102 // Functions marked as `view` promise not to modify state103 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions104 view105 returns (uint256[] memory)106 {107 // Uses the `memory` storage location to store values only for the108 // lifecycle of this function call.109 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/introduction-to-smart-contracts.html#storage-memory-and-the-stack110 uint256[] memory result = new uint256[](ownerPizzaCount[_owner]);111 uint256 counter = 0;112 for (uint256 i = 0; i < pizzas.length; i++) {113 if (pizzaToOwner[i] == _owner) {114 result[counter] = i;115 counter++;116 }117 }118 return result;119 }120121 // Transfers Pizza and ownership to other address122 function transferFrom(address _from, address _to, uint256 _pizzaId) public {123 require(_from != address(0) && _to != address(0), "Invalid address.");124 require(_exists(_pizzaId), "Pizza does not exist.");125 require(_from != _to, "Cannot transfer to the same address.");126 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");127128 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);129 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);130 pizzaToOwner[_pizzaId] = _to;131132 // Emits event defined in the imported IERC721 contract133 emit Transfer(_from, _to, _pizzaId);134 _clearApproval(_to, _pizzaId);135 }136137 /**138 * Safely transfers the ownership of a given token ID to another address139 * If the target address is a contract, it must implement `onERC721Received`,140 * which is called upon a safe transfer, and return the magic value141 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;142 * otherwise, the transfer is reverted.143 */144 function safeTransferFrom(address from, address to, uint256 pizzaId)145 public146 {147 // solium-disable-next-line arg-overflow148 this.safeTransferFrom(from, to, pizzaId, "");149 }150151 /**152 * Safely transfers the ownership of a given token ID to another address153 * If the target address is a contract, it must implement `onERC721Received`,154 * which is called upon a safe transfer, and return the magic value155 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;156 * otherwise, the transfer is reverted.157 */158 function safeTransferFrom(159 address from,160 address to,161 uint256 pizzaId,162 bytes memory _data163 ) public {164 this.transferFrom(from, to, pizzaId);165 require(_checkOnERC721Received(from, to, pizzaId, _data), "Must implement onERC721Received.");166 }167168 /**169 * Internal function to invoke `onERC721Received` on a target address170 * The call is not executed if the target address is not a contract171 */172 function _checkOnERC721Received(173 address from,174 address to,175 uint256 pizzaId,176 bytes memory _data177 ) internal returns (bool) {178 if (!isContract(to)) {179 return true;180 }181182 bytes4 retval = IERC721Receiver(to).onERC721Received(183 msg.sender,184 from,185 pizzaId,186 _data187 );188 return (retval == _ERC721_RECEIVED);189 }190191 // Burns a Pizza - destroys Token completely192 // The `external` function modifier means this function is193 // part of the contract interface and other contracts can call it194 function burn(uint256 _pizzaId) external {195 require(msg.sender != address(0), "Invalid address.");196 require(_exists(_pizzaId), "Pizza does not exist.");197 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");198199 ownerPizzaCount[msg.sender] = SafeMath.sub(200 ownerPizzaCount[msg.sender],201 1202 );203 pizzaToOwner[_pizzaId] = address(0);204 }205206 // Returns count of Pizzas by address207 function balanceOf(address _owner) public view returns (uint256 _balance) {208 return ownerPizzaCount[_owner];209 }210211 // Returns owner of the Pizza found by id212 function ownerOf(uint256 _pizzaId) public view returns (address _owner) {213 address owner = pizzaToOwner[_pizzaId];214 require(owner != address(0), "Invalid Pizza ID.");215 return owner;216 }217218 // Approves other address to transfer ownership of Pizza219 function approve(address _to, uint256 _pizzaId) public {220 require(msg.sender == pizzaToOwner[_pizzaId], "Must be the Pizza owner.");221 pizzaApprovals[_pizzaId] = _to;222 emit Approval(msg.sender, _to, _pizzaId);223 }224225 // Returns approved address for specific Pizza226 function getApproved(uint256 _pizzaId)227 public228 view229 returns (address operator)230 {231 require(_exists(_pizzaId), "Pizza does not exist.");232 return pizzaApprovals[_pizzaId];233 }234235 /**236 * Private function to clear current approval of a given token ID237 * Reverts if the given address is not indeed the owner of the token238 */239 function _clearApproval(address owner, uint256 _pizzaId) private {240 require(pizzaToOwner[_pizzaId] == owner, "Must be pizza owner.");241 require(_exists(_pizzaId), "Pizza does not exist.");242 if (pizzaApprovals[_pizzaId] != address(0)) {243 pizzaApprovals[_pizzaId] = address(0);244 }245 }246247 /*248 * Sets or unsets the approval of a given operator249 * An operator is allowed to transfer all tokens of the sender on their behalf250 */251 function setApprovalForAll(address to, bool approved) public {252 require(to != msg.sender, "Cannot approve own address");253 operatorApprovals[msg.sender][to] = approved;254 emit ApprovalForAll(msg.sender, to, approved);255 }256257 // Tells whether an operator is approved by a given owner258 function isApprovedForAll(address owner, address operator)259 public260 view261 returns (bool)262 {263 return operatorApprovals[owner][operator];264 }265266 // Takes ownership of Pizza - only for approved users267 function takeOwnership(uint256 _pizzaId) public {268 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");269 address owner = this.ownerOf(_pizzaId);270 this.transferFrom(owner, msg.sender, _pizzaId);271 }272273 // Checks if Pizza exists274 function _exists(uint256 pizzaId) internal view returns (bool) {275 address owner = pizzaToOwner[pizzaId];276 return owner != address(0);277 }278279 // Checks if address is owner or is approved to transfer Pizza280 function _isApprovedOrOwner(address spender, uint256 pizzaId)281 internal282 view283 returns (bool)284 {285 address owner = pizzaToOwner[pizzaId];286 // Disable solium check because of287 // https://github.com/duaraghav8/Solium/issues/175288 // solium-disable-next-line operator-whitespace289 return (spender == owner ||290 this.getApproved(pizzaId) == spender ||291 this.isApprovedForAll(owner, spender));292 }293294 // Check if Pizza is unique and doesn't exist yet295 modifier isUnique(string memory _name, uint256 _dna) {296 bool result = true;297 for (uint256 i = 0; i < pizzas.length; i++) {298 if (299 keccak256(abi.encodePacked(pizzas[i].name)) ==300 keccak256(abi.encodePacked(_name)) &&301 pizzas[i].dna == _dna302 ) {303 result = false;304 }305 }306 require(result, "Pizza with such name already exists.");307 _;308 }309310 // Returns whether the target address is a contract311 function isContract(address account) internal view returns (bool) {312 uint256 size;313 // Currently there is no better way to check if there is a contract in an address314 // than to check the size of the code at that address.315 // Δείτε το https://ethereum.stackexchange.com/a/14016/36603316 // για περισσότερες πληροφορίες σχετικά με τον τρόπο λειτουργίας.317 // TODO Check this again before the Serenity release, because all addresses will be318 // contracts then.319 // solium-disable-next-line security/no-inline-assembly320 assembly {321 size := extcodesize(account)322 }323 return size > 0;324 }325}Εμφάνιση όλωνΑντιγραφή
Περισσότερες πληροφορίες
Ελέγξτε την τεκμηρίωση του Solidity και του Vyper για μια πιο ολοκληρωμένη επισκόπηση των έξυπνων συμβολαίων:
Σχετικά θέματα
Σχετικοί οδηγοί
- Μείωση του μεγέθους των συμβολαίων για την καταπολέμηση του ορίου μεγέθους των συμβολαίων – Πρακτικές συμβουλές για τη μείωση του μεγέθους των έξυπνων συμβολαίων σας.
- Καταχώριση δεδομένων από έξυπνα συμβόλαια με συμβάντα – Εισαγωγή στα συμβάντα έξυπνων συμβολαίων και πώς να τα χρησιμοποιείτε για να καταχωρίζετε δεδομένα.
- Αλληλεπίδραση με άλλα συμβόλαια από το Solidity – Πώς να αναπτύξετε ένα έξυπνο συμβόλαιο από ένα υπάρχον συμβόλαιο και να αλληλεπιδράσετε με αυτό.