Przejdź do głównej zawartości
Change page

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 Solidity
2contract SimpleStorage {
3 uint storedData; // Zmienna stanu
4 // ...
5}
1# Przykład Vyper
2storedData: int128

Jeś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:

PropZmienna stanuOpis
block.timestampuint256Aktualny blok — znacznik czasu epoki
msg.senderaddressNadawca 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 f nie może być wywoływana wewnętrznie (tj. f() nie działa, ale this.f() działa).

Mogą być również public lub private

  • Funkcje public mogą być wywoływane wewnętrznie z poziomu kontraktu lub zewnętrznie za pomocą wiadomości
  • Funkcje private są 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 Solidity
2function update_name(string value) public {
3 dapp_name = value;
4}
  • Parametr value typu string jest 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 Solidity
2function balanceOf(address _owner) public view returns (uint256 _balance) {
3 return ownerPizzaCount[_owner];
4}
1dappName: public(string)
2
3@view
4@public
5def readName() -> string:
6 return dappName

Co jest uważane za modyfikację stanu:

  1. Zapis do zmiennych stanu.
  2. Emitowanie zdarzeńopens in a new tab.
  3. Tworzenie innych kontraktówopens in a new tab.
  4. Używanie selfdestruct.
  5. Wysyłanie etheru za pomocą wywołań.
  6. Wywoływanie dowolnej funkcji nieoznaczonej jako view lub pure.
  7. Używanie wywołań niskiego poziomu.
  8. 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 Solidity
2// 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-properties
9 owner = msg.sender;
10}
Pokaż wszystko
1# Przykład Vyper
2
3@external
4def __init__(_beneficiary: address, _bidding_time: uint256):
5 self.beneficiary = _beneficiary
6 self.auctionStart = block.timestamp
7 self.auctionEnd = self.auctionStart + _bidding_time

Funkcje wbudowane

Oprócz zmiennych i funkcji, które definiujesz w kontrakcie, istnieje kilka specjalnych wbudowanych funkcji. Najbardziej oczywistym przykładem jest:

  • address.send() – Solidity
  • send(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;
2
3contract ExampleDapp {
4 string dapp_name; // zmienna stanu
5
6 // Wywoływane podczas wdrażania kontraktu, inicjalizuje wartość
7 constructor() public {
8 dapp_name = "Moja przykładowa dapka";
9 }
10
11 // Funkcja pobierająca
12 function read_name() public view returns(string) {
13 return dapp_name;
14 }
15
16 // Funkcja ustawiająca
17 function update_name(string value) public {
18 dapp_name = value;
19 }
20}
Pokaż wszystko

Peł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#pragma
3pragma solidity ^0.5.10;
4
5// 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.html
9contract HelloWorld {
10
11 // 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 kontraktu
14 // i tworzy funkcję, którą inne kontrakty lub klienci mogą wywołać, aby uzyskać dostęp do wartości.
15 string public message;
16
17 // Podobnie jak w wielu obiektowych językach programowania opartych na klasach, konstruktor jest
18 // 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#constructors
21 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 }
26
27 // Funkcja publiczna, która akceptuje argument typu string
28 // i aktualizuje zmienną `message` w pamięci kontraktu (storage).
29 function update(string memory newMessage) public {
30 message = newMessage;
31 }
32}
Pokaż wszystko

Token

1pragma solidity ^0.5.10;
2
3contract 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#address
7 address public owner;
8
9 // `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-types
12 mapping (address => uint) public balances;
13
14 // 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#events
17 event Transfer(address from, address to, uint amount);
18
19 // 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-properties
26 owner = msg.sender;
27 }
28
29 // 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-exceptions
35
36 // Tylko właściciel kontraktu może wywołać tę funkcję
37 require(msg.sender == owner, "Nie jesteś właścicielem.");
38
39 // Wymusza maksymalną liczbę tokenów
40 require(amount < 1e60, "Przekroczono maksymalną emisję");
41
42 // Zwiększa saldo `receiver` o `amount`
43 balances[receiver] += amount;
44 }
45
46 // 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łania
49 require(amount <= balances[msg.sender], "Niewystarczające saldo.");
50
51 // Dostosowuje salda tokenów obu adresów
52 balances[msg.sender] -= amount;
53 balances[receiver] += amount;
54
55 // Emituje zdarzenie zdefiniowane wcześniej
56 emit Transfer(msg.sender, receiver, amount);
57 }
58}
Pokaż wszystko

Unikalny zasób cyfrowy

1pragma solidity ^0.5.10;
2
3// 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-files
6
7import "../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";
11
12// 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#inheritance
15contract 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#SafeMath
18 using SafeMath for uint256;
19
20 // 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-variables
23 uint256 constant dnaDigits = 10;
24 uint256 constant dnaModulus = 10 ** dnaDigits;
25 bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
26
27 // Typy `struct` pozwalają definiować własne typy
28 // Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/types.html#structs
29 struct Pizza {
30 string name;
31 uint256 dna;
32 }
33
34 // Tworzy pustą tablicę struktur Pizza
35 Pizza[] public pizzas;
36
37 // Mapowanie z ID pizzy na adres jej właściciela
38 mapping(uint256 => address) public pizzaToOwner;
39
40 // Mapowanie z adresu właściciela na liczbę posiadanych tokenów
41 mapping(address => uint256) public ownerPizzaCount;
42
43 // Mapowanie z ID tokenu na zatwierdzony adres
44 mapping(uint256 => address) pizzaApprovals;
45
46 // Możesz zagnieżdżać mapowania, ten przykład mapuje właściciela na zatwierdzenia operatora
47 mapping(address => mapping(address => bool)) private operatorApprovals;
48
49 // Wewnętrzna funkcja do tworzenia losowej Pizzy z ciągu znaków (nazwa) i DNA
50 function _createPizza(string memory _name, uint256 _dna)
51 // Słowo kluczowe `internal` oznacza, że ta funkcja jest widoczna tylko
52 // 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-getters
54 internal
55 // `isUnique` to modyfikator funkcji, który sprawdza, czy pizza już istnieje
56 // Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers
57 isUnique(_name, _dna)
58 {
59 // Dodaje Pizzę do tablicy Pizz i pobiera id
60 uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1);
61
62 // Sprawdza, czy właściciel Pizzy jest taki sam jak bieżący użytkownik
63 // Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
64
65 // zauważ, że address(0) to adres zerowy,
66 // co oznacza, że pizza[id] nie jest jeszcze przydzielona do konkretnego użytkownika.
67
68 assert(pizzaToOwner[id] == address(0));
69
70 // Mapuje Pizzę na właściciela
71 pizzaToOwner[id] = msg.sender;
72 ownerPizzaCount[msg.sender] = SafeMath.add(
73 ownerPizzaCount[msg.sender],
74 1
75 );
76 }
77
78 // 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 }
83
84 // 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 public
87 // Funkcje oznaczone jako `pure` obiecują nie odczytywać ani nie modyfikować stanu
88 // Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions
89 pure
90 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 }
98
99 // Zwraca tablicę Pizz znalezionych przez właściciela
100 function getPizzasByOwner(address _owner)
101 public
102 // Funkcje oznaczone jako `view` obiecują nie modyfikować stanu
103 // Dowiedz się więcej: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions
104 view
105 returns (uint256[] memory)
106 {
107 // Używa lokalizacji `memory` do przechowywania wartości tylko na czas
108 // 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-stack
110 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 }
120
121 // Przenosi Pizzę i własność na inny adres
122 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.");
127
128 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);
129 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);
130 pizzaToOwner[_pizzaId] = _to;
131
132 // Emituje zdarzenie zdefiniowane w zaimportowanym kontrakcie IERC721
133 emit Transfer(_from, _to, _pizzaId);
134 _clearApproval(_to, _pizzaId);
135 }
136
137 /**
138 * Bezpiecznie przenosi własność danego ID tokenu na inny adres
139 * 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 public
146 {
147 // solium-disable-next-line arg-overflow
148 this.safeTransferFrom(from, to, pizzaId, "");
149 }
150
151 /**
152 * Bezpiecznie przenosi własność danego ID tokenu na inny adres
153 * 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 _data
163 ) public {
164 this.transferFrom(from, to, pizzaId);
165 require(_checkOnERC721Received(from, to, pizzaId, _data), "Należy zaimplementować onERC721Received.");
166 }
167
168 /**
169 * Wewnętrzna funkcja do wywoływania `onERC721Received` na adresie docelowym
170 * Wywołanie nie jest wykonywane, jeśli adres docelowy nie jest kontraktem
171 */
172 function _checkOnERC721Received(
173 address from,
174 address to,
175 uint256 pizzaId,
176 bytes memory _data
177 ) internal returns (bool) {
178 if (!isContract(to)) {
179 return true;
180 }
181
182 bytes4 retval = IERC721Receiver(to).onERC721Received(
183 msg.sender,
184 from,
185 pizzaId,
186 _data
187 );
188 return (retval == _ERC721_RECEIVED);
189 }
190
191 // Pali Pizzę - całkowicie niszczy Token
192 // Modyfikator funkcji `external` oznacza, że ta funkcja jest
193 // 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.");
198
199 ownerPizzaCount[msg.sender] = SafeMath.sub(
200 ownerPizzaCount[msg.sender],
201 1
202 );
203 pizzaToOwner[_pizzaId] = address(0);
204 }
205
206 // Zwraca liczbę Pizz według adresu
207 function balanceOf(address _owner) public view returns (uint256 _balance) {
208 return ownerPizzaCount[_owner];
209 }
210
211 // Zwraca właściciela Pizzy znalezionego po id
212 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 }
217
218 // Zatwierdza inny adres do przeniesienia własności Pizzy
219 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 }
224
225 // Zwraca zatwierdzony adres dla określonej Pizzy
226 function getApproved(uint256 _pizzaId)
227 public
228 view
229 returns (address operator)
230 {
231 require(_exists(_pizzaId), "Pizza nie istnieje.");
232 return pizzaApprovals[_pizzaId];
233 }
234
235 /**
236 * Prywatna funkcja do wyczyszczenia bieżącego zatwierdzenia dla danego ID tokenu
237 * Cofa, jeśli podany adres nie jest faktycznie właścicielem tokenu
238 */
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 }
246
247 /*
248 * Ustawia lub usuwa zatwierdzenie dla danego operatora
249 * Operator może w imieniu nadawcy przenieść wszystkie jego tokeny
250 */
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 }
256
257 // Informuje, czy operator jest zatwierdzony przez danego właściciela
258 function isApprovedForAll(address owner, address operator)
259 public
260 view
261 returns (bool)
262 {
263 return operatorApprovals[owner][operator];
264 }
265
266 // Przejmuje własność Pizzy - tylko dla zatwierdzonych użytkowników
267 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 }
272
273 // Sprawdza, czy Pizza istnieje
274 function _exists(uint256 pizzaId) internal view returns (bool) {
275 address owner = pizzaToOwner[pizzaId];
276 return owner != address(0);
277 }
278
279 // Sprawdza, czy adres jest właścicielem lub jest zatwierdzony do przeniesienia Pizzy
280 function _isApprovedOrOwner(address spender, uint256 pizzaId)
281 internal
282 view
283 returns (bool)
284 {
285 address owner = pizzaToOwner[pizzaId];
286 // Disable solium check because of
287 // https://github.com/duaraghav8/Solium/issues/175
288 // solium-disable-next-line operator-whitespace
289 return (spender == owner ||
290 this.getApproved(pizzaId) == spender ||
291 this.isApprovedForAll(owner, spender));
292 }
293
294 // Sprawdź, czy Pizza jest unikalna i jeszcze nie istnieje
295 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 == _dna
302 ) {
303 result = false;
304 }
305 }
306 require(result, "Pizza o takiej nazwie już istnieje.");
307 _;
308 }
309
310 // Zwraca informację, czy adres docelowy jest kontraktem
311 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/36603
316 // 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-assembly
320 assembly {
321 size := extcodesize(account)
322 }
323 return size > 0;
324 }
325}
Pokaż wszystko

Dalsza lektura

Sprawdź dokumentację Solidity i Vyper, aby uzyskać pełniejszy przegląd inteligentnych kontraktów:

Czy ten artykuł był pomocny?