Anatomia inteligentnych kontraktów
Strona ostatnio zaktualizowana: 14 lutego 2026
Inteligentny kontrakt to program, który działa pod adresem Ethereum. Składają się z danych i funkcji, które można wykonać po otrzymaniu transakcji. Oto przegląd tego, co stanowi inteligentny kontrakt.
Wymagania wstępne
Upewnij się, że najpierw przeczytałeś/aś o inteligentnych kontraktach. Ten dokument zakłada, że znasz już języki programowania, takie jak JavaScript lub Python.
Dane
Wszelkie dane kontraktu muszą być przypisane do lokalizacji: do storage lub memory. Modyfikacja pamięci masowej w inteligentnym kontrakcie jest kosztowna, więc musisz zastanowić się, gdzie powinny znajdować się Twoje dane.
Przechowywanie
Trwałe dane są nazywane pamięcią masową i są reprezentowane przez zmienne stanu. Te wartości są przechowywane na stałe w blockchain. Musisz zadeklarować typ, aby kontrakt mógł śledzić, ile pamięci w blockchainie potrzebuje podczas kompilacji.
1// Przykład w Solidity2contract SimpleStorage {3 uint storedData; // Zmienna stanu4 // ...5}1# Przykład Vyper2storedData: int128Jeśli programowałeś już w językach obiektowych, prawdopodobnie znasz większość typów. Jednak typ address powinien być dla Ciebie nowością, jeśli dopiero zaczynasz programować w Ethereum.
Typ address może zawierać adres Ethereum, który odpowiada 20 bajtom lub 160 bitom. Jest zwracany w zapisach szesnastkowych z wiodącym 0x.
Inne typy:
- boolean
- liczba całkowita
- fixed point numbers
- fixed-size byte arrays
- dynamicznie wymiarowane tablice bajtów
- literały wymierne i całkowite
- literały ciągów znaków
- literały szesnastkowe
- enumy
Aby uzyskać więcej wyjaśnień, zapoznaj się z dokumentami:
Pamięć
Wartości przechowywane tylko przez cały okres wykonywania funkcji kontraktowej nazywane są zmiennymi pamięci. Ponieważ nie są one przechowywane na stałe w blockchain, są znacznie tańsze w użyciu.
Dowiedz się więcej o tym, jak EVM przechowuje dane (Storage, Memory i Stack) w dokumentacji Solidityopens in a new tab.
Zmienne środowiskowe
Oprócz zmiennych, które definiujesz w kontrakcie, istnieją pewne specjalne zmienne globalne. Są one wykorzystywane głównie do dostarczania informacji na temat łańcucha bloków lub bieżącej transakcji.
Przykłady:
| Prop | Zmienna stanu | Opis |
|---|---|---|
block.timestamp | uint256 | Aktualny blok — znacznik czasu epoki |
msg.sender | address | Nadawca wiadomości (bieżące wywołanie) |
Funkcje
W najbardziej uproszczonym ujęciu, funkcje mogą pobierać informacje lub ustawiać informacje w odpowiedzi na przychodzące transakcje.
Istnieją dwa rodzaje wywołań funkcji:
internal– nie tworzą wywołania EVM- Wewnętrzne funkcje i zmienne stanu są dostępne tylko wewnętrznie (tj. z poziomu bieżącego kontraktu lub kontraktów z niego dziedziczących)
external– tworzą wywołanie EVM- Funkcje zewnętrzne są częścią interfejsu kontraktu, co oznacza, że mogą być wywoływane z innych kontraktów oraz poprzez transakcje. Zewnętrzna funkcja
fnie może być wywoływana wewnętrznie (tj.f()nie działa, alethis.f()działa).
- Funkcje zewnętrzne są częścią interfejsu kontraktu, co oznacza, że mogą być wywoływane z innych kontraktów oraz poprzez transakcje. Zewnętrzna funkcja
Mogą być również public lub private
- Funkcje
publicmogą być wywoływane wewnętrznie z poziomu kontraktu lub zewnętrznie za pomocą wiadomości - Funkcje
privatesą widoczne tylko dla kontraktu, w którym są zdefiniowane, a nie w kontraktach pochodnych
Zarówno funkcje, jak i zmienne stanu mogą być publiczne lub prywatne
Oto funkcja aktualizacji zmiennej stanu w kontrakcie:
1// Przykład Solidity2function update_name(string value) public {3 dapp_name = value;4}- Parametr
valuetypustringjest przekazywany do funkcji:update_name - Jest zadeklarowana jako
public, co oznacza, że każdy może uzyskać do niej dostęp - Nie jest zadeklarowana jako
view, więc może modyfikować stan kontraktu
Funkcje view
Funkcje te obiecują nie zmieniać stanu danych kontraktu. Typowe przykłady to funkcje „getter”, które można wykorzystać na przykład do uzyskania salda użytkownika.
1// Przykład Solidity2function balanceOf(address _owner) public view returns (uint256 _balance) {3 return ownerPizzaCount[_owner];4}1dappName: public(string)23@view4@public5def readName() -> string:6 return dappNameCo jest uważane za modyfikację stanu:
- Zapis do zmiennych stanu.
- Emitowanie zdarzeńopens in a new tab.
- Tworzenie innych kontraktówopens in a new tab.
- Używanie
selfdestruct. - Wysyłanie etheru za pomocą wywołań.
- Wywoływanie dowolnej funkcji nieoznaczonej jako
viewlubpure. - Używanie wywołań niskiego poziomu.
- Korzystanie z asemblera wbudowanego, który zawiera określone kody operacji.
Funkcje konstruktora
Funkcje constructor są wykonywane tylko raz podczas pierwszego wdrożenia kontraktu. Podobnie jak constructor w wielu językach programowania opartych na klasach, funkcje te często inicjalizują zmienne stanu do ich określonych wartości.
1// Przykład w Solidity2// Inicjalizuje dane kontraktu, ustawiając `owner`3// na adres twórcy kontraktu.4constructor() public {5 // Wszystkie inteligentne kontrakty opierają się na zewnętrznych transakcjach, aby uruchomić swoje funkcje.6 // `msg` to globalna zmienna, która zawiera istotne dane dotyczące danej transakcji,7 // takie jak adres nadawcy i wartość ETH zawarta w transakcji.8 // Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties9 owner = msg.sender;10}Pokaż wszystko1# Przykład Vyper23@external4def __init__(_beneficiary: address, _bidding_time: uint256):5 self.beneficiary = _beneficiary6 self.auctionStart = block.timestamp7 self.auctionEnd = self.auctionStart + _bidding_timeFunkcje wbudowane
Oprócz zmiennych i funkcji, które definiujesz w kontrakcie, istnieje kilka specjalnych wbudowanych funkcji. Najbardziej oczywistym przykładem jest:
address.send()– Soliditysend(address)– Vyper
Pozwalają one na wysyłanie ETH do innych kont.
Pisanie funkcji
Twoja funkcja wymaga:
- zmiennej i typu parametru (jeżeli akceptuje parametry)
- deklaracji wewnętrznej/zewnętrznej
- deklaracji pure/view/payable
- typu zwrotów (jeśli zwraca wartość)
1pragma solidity >=0.4.0 <=0.6.0;23contract ExampleDapp {4 string dapp_name; // zmienna stanu56 // Wywoływane podczas wdrażania kontraktu, inicjalizuje wartość7 constructor() public {8 dapp_name = "Moja przykładowa dapka";9 }1011 // Funkcja pobierająca12 function read_name() public view returns(string) {13 return dapp_name;14 }1516 // Funkcja ustawiająca17 function update_name(string value) public {18 dapp_name = value;19 }20}Pokaż wszystkoPełny kontrakt może wyglądać w ten sposób. Tutaj funkcja constructor zapewnia wartość początkową dla zmiennej dapp_name.
Zdarzenia i logi
Wydarzenia umożliwiają inteligentnemu kontraktowi komunikację z frontendem oraz innymi subskrybującymi aplikacjami. Kiedy transakcja zostanie potwierdzona i dodana do bloku, inteligentne kontrakty mogą nadawać wydarzenia i rejestrować informacje, które frontend może przetwarzać i wykorzystywać.
Przykłady z adnotacjami
Są to niektóre przykłady napisane w Solidity. Jeśli chcesz pobawić się kodem, możesz wejść z nimi w interakcję w Remixopens in a new tab.
Witaj, świecie
1// Określa wersję Solidity, używając wersjonowania semantycznego.2// Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma3pragma solidity ^0.5.10;45// Definiuje kontrakt o nazwie `HelloWorld`.6// Kontrakt to zbiór funkcji i danych (jego stanu).7// Po wdrożeniu kontrakt znajduje się pod określonym adresem na blockchainie Ethereum.8// Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html9contract HelloWorld {1011 // Deklaruje zmienną stanu `message` typu `string`.12 // Zmienne stanu to zmienne, których wartości są trwale przechowywane w pamięci kontraktu (storage).13 // Słowo kluczowe `public` udostępnia zmienne na zewnątrz kontraktu14 // i tworzy funkcję, którą inne kontrakty lub klienci mogą wywołać, aby uzyskać dostęp do wartości.15 string public message;1617 // Podobnie jak w wielu obiektowych językach programowania opartych na klasach, konstruktor jest18 // specjalną funkcją, która jest wykonywana tylko podczas tworzenia kontraktu.19 // Konstruktory służą do inicjalizacji danych kontraktu.20 // Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors21 constructor(string memory initMessage) public {22 // Akceptuje argument typu string `initMessage` i ustawia wartość23 // w zmiennej `message` w pamięci kontraktu (storage).24 message = initMessage;25 }2627 // Funkcja publiczna, która akceptuje argument typu string28 // i aktualizuje zmienną `message` w pamięci kontraktu (storage).29 function update(string memory newMessage) public {30 message = newMessage;31 }32}Pokaż wszystkoToken
1pragma solidity ^0.5.10;23contract Token {4 // `address` jest porównywalny z adresem e-mail – służy do identyfikacji konta na Ethereum.5 // Adresy mogą reprezentować inteligentny kontrakt lub konta zewnętrzne (użytkowników).6 // Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/types.html#address7 address public owner;89 // `mapping` to w zasadzie struktura danych typu tablica haszująca.10 // Ten `mapping` przypisuje nieujemną liczbę całkowitą (saldo tokenu) do adresu (posiadacza tokenu).11 // Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types12 mapping (address => uint) public balances;1314 // Zdarzenia umożliwiają rejestrowanie aktywności na blockchainie.15 // Klienci Ethereum mogą nasłuchiwać zdarzeń, aby reagować na zmiany stanu kontraktu.16 // Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events17 event Transfer(address from, address to, uint amount);1819 // Inicjalizuje dane kontraktu, ustawiając `owner`20 // na adres twórcy kontraktu.21 constructor() public {22 // Wszystkie inteligentne kontrakty opierają się na zewnętrznych transakcjach, aby uruchomić swoje funkcje.23 // `msg` to globalna zmienna, która zawiera istotne dane dotyczące danej transakcji,24 // takie jak adres nadawcy i wartość ETH zawarta w transakcji.25 // Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties26 owner = msg.sender;27 }2829 // Tworzy określoną liczbę nowych tokenów i wysyła je na dany adres.30 function mint(address receiver, uint amount) public {31 // `require` to struktura kontrolna używana do wymuszania określonych warunków.32 // Jeśli wyrażenie `require` zwróci wartość `false`, wyzwalany jest wyjątek,33 // który cofa wszystkie zmiany stanu dokonane podczas bieżącego wywołania.34 // Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions3536 // Tylko właściciel kontraktu może wywołać tę funkcję37 require(msg.sender == owner, "Nie jesteś właścicielem.");3839 // Wymusza maksymalną liczbę tokenów40 require(amount < 1e60, "Przekroczono maksymalną emisję");4142 // Zwiększa saldo `receiver` o `amount`43 balances[receiver] += amount;44 }4546 // Wysyła określoną liczbę istniejących tokenów od dowolnego wywołującego na dany adres.47 function transfer(address receiver, uint amount) public {48 // Nadawca musi mieć wystarczającą liczbę tokenów do wysłania49 require(amount <= balances[msg.sender], "Niewystarczające saldo.");5051 // Dostosowuje salda tokenów obu adresów52 balances[msg.sender] -= amount;53 balances[receiver] += amount;5455 // Emituje zdarzenie zdefiniowane wcześniej56 emit Transfer(msg.sender, receiver, amount);57 }58}Pokaż wszystkoUnikalny zasób cyfrowy
1pragma solidity ^0.5.10;23// Importuje symbole z innych plików do bieżącego kontraktu.4// W tym przypadku jest to seria kontraktów pomocniczych z OpenZeppelin.5// Dowiedz się więcej: 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// Słowo kluczowe `is` służy do dziedziczenia funkcji i słów kluczowych z kontraktów zewnętrznych.13// W tym przypadku `CryptoPizza` dziedziczy po kontraktach `IERC721` i `ERC165`.14// Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#inheritance15contract CryptoPizza is IERC721, ERC165 {16 // Używa biblioteki SafeMath z OpenZeppelin do bezpiecznego wykonywania operacji arytmetycznych.17 // Dowiedz się więcej: https://docs.openzeppelin.com/contracts/2.x/api/math#SafeMath18 using SafeMath for uint256;1920 // Stałe zmienne stanu w Solidity są podobne do tych w innych językach,21 // ale musisz przypisać im wartość z wyrażenia, które jest stałe w czasie kompilacji.22 // Dowiedz się więcej: 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 // Typy `struct` pozwalają definiować własne typy28 // Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/types.html#structs29 struct Pizza {30 string name;31 uint256 dna;32 }3334 // Tworzy pustą tablicę struktur Pizza35 Pizza[] public pizzas;3637 // Mapowanie z ID pizzy na adres jej właściciela38 mapping(uint256 => address) public pizzaToOwner;3940 // Mapowanie z adresu właściciela na liczbę posiadanych tokenów41 mapping(address => uint256) public ownerPizzaCount;4243 // Mapowanie z ID tokenu na zatwierdzony adres44 mapping(uint256 => address) pizzaApprovals;4546 // Możesz zagnieżdżać mapowania, ten przykład mapuje właściciela na zatwierdzenia operatora47 mapping(address => mapping(address => bool)) private operatorApprovals;4849 // Wewnętrzna funkcja do tworzenia losowej Pizzy z ciągu znaków (nazwa) i DNA50 function _createPizza(string memory _name, uint256 _dna)51 // Słowo kluczowe `internal` oznacza, że ta funkcja jest widoczna tylko52 // w obrębie tego kontraktu i kontraktów, które z niego dziedziczą53 // Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#visibility-and-getters54 internal55 // `isUnique` to modyfikator funkcji, który sprawdza, czy pizza już istnieje56 // Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers57 isUnique(_name, _dna)58 {59 // Dodaje Pizzę do tablicy Pizz i pobiera id60 uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1);6162 // Sprawdza, czy właściciel Pizzy jest taki sam jak bieżący użytkownik63 // Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions6465 // zauważ, że address(0) to adres zerowy,66 // co oznacza, że pizza[id] nie jest jeszcze przydzielona do konkretnego użytkownika.6768 assert(pizzaToOwner[id] == address(0));6970 // Mapuje Pizzę na właściciela71 pizzaToOwner[id] = msg.sender;72 ownerPizzaCount[msg.sender] = SafeMath.add(73 ownerPizzaCount[msg.sender],74 175 );76 }7778 // Tworzy losową Pizzę z ciągu znaków (nazwa)79 function createRandomPizza(string memory _name) public {80 uint256 randDna = generateRandomDna(_name, msg.sender);81 _createPizza(_name, randDna);82 }8384 // Generuje losowe DNA z ciągu znaków (nazwa) i adresu właściciela (twórcy)85 function generateRandomDna(string memory _str, address _owner)86 public87 // Funkcje oznaczone jako `pure` obiecują nie odczytywać ani nie modyfikować stanu88 // Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions89 pure90 returns (uint256)91 {92 // Generuje losowy uint z ciągu znaków (nazwa) + adres (właściciel)93 uint256 rand = uint256(keccak256(abi.encodePacked(_str))) +94 uint256(_owner);95 rand = rand % dnaModulus;96 return rand;97 }9899 // Zwraca tablicę Pizz znalezionych przez właściciela100 function getPizzasByOwner(address _owner)101 public102 // Funkcje oznaczone jako `view` obiecują nie modyfikować stanu103 // Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions104 view105 returns (uint256[] memory)106 {107 // Używa lokalizacji `memory` do przechowywania wartości tylko na czas108 // trwania tego wywołania funkcji.109 // Dowiedz się więcej: 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 // Przenosi Pizzę i własność na inny adres122 function transferFrom(address _from, address _to, uint256 _pizzaId) public {123 require(_from != address(0) && _to != address(0), "Nieprawidłowy adres.");124 require(_exists(_pizzaId), "Pizza nie istnieje.");125 require(_from != _to, "Nie można przenieść na ten sam adres.");126 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Adres nie jest zatwierdzony.");127128 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);129 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);130 pizzaToOwner[_pizzaId] = _to;131132 // Emituje zdarzenie zdefiniowane w zaimportowanym kontrakcie IERC721133 emit Transfer(_from, _to, _pizzaId);134 _clearApproval(_to, _pizzaId);135 }136137 /**138 * Bezpiecznie przenosi własność danego ID tokenu na inny adres139 * Jeśli adres docelowy jest kontraktem, musi on implementować `onERC721Received`,140 * która jest wywoływana podczas bezpiecznego transferu i zwraca magiczną wartość141 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;142 * w przeciwnym razie transfer jest cofany.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 * Bezpiecznie przenosi własność danego ID tokenu na inny adres153 * Jeśli adres docelowy jest kontraktem, musi on implementować `onERC721Received`,154 * która jest wywoływana podczas bezpiecznego transferu i zwraca magiczną wartość155 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;156 * w przeciwnym razie transfer jest cofany.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), "Należy zaimplementować onERC721Received.");166 }167168 /**169 * Wewnętrzna funkcja do wywoływania `onERC721Received` na adresie docelowym170 * Wywołanie nie jest wykonywane, jeśli adres docelowy nie jest kontraktem171 */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 // Pali Pizzę - całkowicie niszczy Token192 // Modyfikator funkcji `external` oznacza, że ta funkcja jest193 // częścią interfejsu kontraktu i inne kontrakty mogą ją wywoływać194 function burn(uint256 _pizzaId) external {195 require(msg.sender != address(0), "Nieprawidłowy adres.");196 require(_exists(_pizzaId), "Pizza nie istnieje.");197 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Adres nie jest zatwierdzony.");198199 ownerPizzaCount[msg.sender] = SafeMath.sub(200 ownerPizzaCount[msg.sender],201 1202 );203 pizzaToOwner[_pizzaId] = address(0);204 }205206 // Zwraca liczbę Pizz według adresu207 function balanceOf(address _owner) public view returns (uint256 _balance) {208 return ownerPizzaCount[_owner];209 }210211 // Zwraca właściciela Pizzy znalezionego po id212 function ownerOf(uint256 _pizzaId) public view returns (address _owner) {213 address owner = pizzaToOwner[_pizzaId];214 require(owner != address(0), "Nieprawidłowe ID Pizzy.");215 return owner;216 }217218 // Zatwierdza inny adres do przeniesienia własności Pizzy219 function approve(address _to, uint256 _pizzaId) public {220 require(msg.sender == pizzaToOwner[_pizzaId], "Musisz być właścicielem Pizzy.");221 pizzaApprovals[_pizzaId] = _to;222 emit Approval(msg.sender, _to, _pizzaId);223 }224225 // Zwraca zatwierdzony adres dla określonej Pizzy226 function getApproved(uint256 _pizzaId)227 public228 view229 returns (address operator)230 {231 require(_exists(_pizzaId), "Pizza nie istnieje.");232 return pizzaApprovals[_pizzaId];233 }234235 /**236 * Prywatna funkcja do wyczyszczenia bieżącego zatwierdzenia dla danego ID tokenu237 * Cofa, jeśli podany adres nie jest faktycznie właścicielem tokenu238 */239 function _clearApproval(address owner, uint256 _pizzaId) private {240 require(pizzaToOwner[_pizzaId] == owner, "Musisz być właścicielem Pizzy.");241 require(_exists(_pizzaId), "Pizza nie istnieje.");242 if (pizzaApprovals[_pizzaId] != address(0)) {243 pizzaApprovals[_pizzaId] = address(0);244 }245 }246247 /*248 * Ustawia lub usuwa zatwierdzenie dla danego operatora249 * Operator może w imieniu nadawcy przenieść wszystkie jego tokeny250 */251 function setApprovalForAll(address to, bool approved) public {252 require(to != msg.sender, "Nie można zatwierdzić własnego adresu");253 operatorApprovals[msg.sender][to] = approved;254 emit ApprovalForAll(msg.sender, to, approved);255 }256257 // Informuje, czy operator jest zatwierdzony przez danego właściciela258 function isApprovedForAll(address owner, address operator)259 public260 view261 returns (bool)262 {263 return operatorApprovals[owner][operator];264 }265266 // Przejmuje własność Pizzy - tylko dla zatwierdzonych użytkowników267 function takeOwnership(uint256 _pizzaId) public {268 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Adres nie jest zatwierdzony.");269 address owner = this.ownerOf(_pizzaId);270 this.transferFrom(owner, msg.sender, _pizzaId);271 }272273 // Sprawdza, czy Pizza istnieje274 function _exists(uint256 pizzaId) internal view returns (bool) {275 address owner = pizzaToOwner[pizzaId];276 return owner != address(0);277 }278279 // Sprawdza, czy adres jest właścicielem lub jest zatwierdzony do przeniesienia Pizzy280 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 // Sprawdź, czy Pizza jest unikalna i jeszcze nie istnieje295 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 o takiej nazwie już istnieje.");307 _;308 }309310 // Zwraca informację, czy adres docelowy jest kontraktem311 function isContract(address account) internal view returns (bool) {312 uint256 size;313 // Obecnie nie ma lepszego sposobu na sprawdzenie, czy pod danym adresem znajduje się kontrakt,314 // niż sprawdzenie rozmiaru kodu pod tym adresem.315 // Zobacz https://ethereum.stackexchange.com/a/14016/36603316 // aby uzyskać więcej szczegółów na temat działania.317 // TODO Sprawdź to ponownie przed wydaniem Serenity, ponieważ wtedy wszystkie adresy będą318 // kontraktami.319 // solium-disable-next-line security/no-inline-assembly320 assembly {321 size := extcodesize(account)322 }323 return size > 0;324 }325}Pokaż wszystkoDalsza lektura
Sprawdź dokumentację Solidity i Vyper, aby uzyskać pełniejszy przegląd inteligentnych kontraktów:
Powiązane tematy
Powiązane samouczki
- Zmniejszanie kontraktów w celu obejścia limitu rozmiaru kontraktu – kilka praktycznych wskazówek dotyczących zmniejszania rozmiaru Twojego inteligentnego kontraktu.
- Rejestrowanie danych z inteligentnych kontraktów za pomocą zdarzeń – wprowadzenie do zdarzeń inteligentnych kontraktów i sposobu ich wykorzystania do rejestrowania danych.
- Interakcja z innymi kontraktami z poziomu Solidity – jak wdrożyć inteligentny kontrakt z istniejącego kontraktu i wejść z nim w interakcję.