Ruka hadi kwenye maudhui makuu

Mwongozo wa Mkataba wa Vyper ERC-721

Vyper
erc-721
Python
Mwanzilishi
Ori Pomerantz
1 Aprili 2021
18 dakika za kusoma

Utangulizi

Kiwango cha ERC-721 kinatumika kushikilia umiliki wa Tokeni Zisizoweza Kubadilishana (NFT). Tokeni za ERC-20 hufanya kazi kama bidhaa, kwa sababu hakuna tofauti kati ya tokeni moja na nyingine. Tofauti na hilo, tokeni za ERC-721 zimeundwa kwa ajili ya rasilimali zinazofanana lakini si sawa kabisa, kama vile katuni tofauti za paka (inafunguka katika kichupo kipya) au hati miliki za vipande tofauti vya ardhi.

Katika makala haya tutachambua mkataba wa ERC-721 wa Ryuya Nakamura (inafunguka katika kichupo kipya). Mkataba huu umeandikwa kwa Vyper (inafunguka katika kichupo kipya), lugha ya mkataba inayofanana na Python iliyoundwa kufanya iwe vigumu kuandika msimbo usio salama kuliko ilivyo katika Solidity.

Mkataba

# @dev Utekelezaji wa kiwango cha tokeni isiyofungika cha ERC-721.
# @author Ryuya Nakamura (@nrryuya)
# Imebadilishwa kutoka: https://github.com/vyperlang/vyper/blob/de74722bf2d8718cca46902be165f9fe0e3641dd/examples/tokens/ERC721.vy

Maoni katika Vyper, kama ilivyo katika Python, huanza na heshi (ethereum.ercs) na kuendelea hadi mwisho wa mstari. Maoni yanayojumuisha @<keyword> hutumiwa na NatSpec (inafunguka katika kichupo kipya) kutoa nyaraka zinazosomeka na binadamu.

from vyper.interfaces import ERC721

implements: ERC721

Kiolesura cha ERC-721 kimejengwa ndani ya lugha ya Vyper. Unaweza kuona ufafanuzi wa msimbo hapa (inafunguka katika kichupo kipya). Ufafanuzi wa kiolesura umeandikwa kwa Python, badala ya Vyper, kwa sababu violesura havitumiki tu ndani ya mnyororo wa vitalu, bali pia wakati wa kutuma muamala kwenye mnyororo wa vitalu kutoka kwa mteja wa nje, ambao unaweza kuwa umeandikwa kwa Python.

Mstari wa kwanza unaingiza kiolesura, na wa pili unabainisha kuwa tunakitekeleza hapa.

#pragma version >0.3.10
#pragma version >0.3.10

Kiolesura cha ERC721Receiver

# Kiolesura cha mkataba kinachoitwa na safeTransferFrom()
interface ERC721Receiver:
    def onERC721Received(

ERC-721 inasaidia aina mbili za hamisho:

  • transferFrom, ambayo inamruhusu mtumaji kubainisha anwani yoyote ya mwisho na kuweka jukumu la hamisho kwa mtumaji. Hii inamaanisha kuwa unaweza kuhamisha kwenda kwenye anwani batili, ambapo NFT itapotea kabisa.
  • safeTransferFrom, ambayo inakagua ikiwa anwani ya mwisho ni mkataba. Ikiwa ndivyo, mkataba wa ERC-721 unauliza mkataba unaopokea ikiwa unataka kupokea NFT.

Ili kujibu maombi ya safeTransferFrom mkataba unaopokea unapaswa kutekeleza ERC721Receiver.

            _operator: address,
            _from: address,

Anwani ya _from ni mmiliki wa sasa wa tokeni. Anwani ya _operator ni ile iliyoomba hamisho (hizo mbili zinaweza zisiwe sawa, kwa sababu ya vibali). Kwa kawaida, vigezo vingi vya kazi katika mkataba huu huanza na mstari wa chini (_).

            _tokenId: uint256,

Vitambulisho vya tokeni za ERC-721 ni biti 256. Kwa kawaida huundwa kwa kuheshi maelezo ya chochote ambacho tokeni inawakilisha.

            _data: Bytes[1024]

Ombi linaweza kuwa na hadi baiti 1024 za data ya mtumiaji.

        ) -> bytes4: nonpayable

Ili kuzuia visa ambapo mkataba unakubali hamisho kwa bahati mbaya, thamani inayorejeshwa si boolean, bali ni thamani maalum ya baiti nne, kiteuzi cha kazi cha onERC721Received. Kazi hii ni nonpayable kwa sababu mkataba unaopokea unaweza kubadilisha hali yake wenyewe unapokubali tokeni.

Matukio

Matukio hutolewa ili kuwajulisha watumiaji na seva zilizo nje ya mnyororo wa vitalu kuhusu matukio. Kumbuka kwamba maudhui ya matukio hayapatikani kwa mikataba kwenye mnyororo wa vitalu. Matukio matatu ya ERC-721 yamefafanuliwa na kiolesura cha IERC721 tulichoingiza, kwa hivyo mkataba huu hauyatangazi wenyewe; unayatoa kwa log IERC721.<Event>(...), kama tutakavyoona katika kazi za hamisho hapa chini.

Transfer (sender, receiver, token_id) inaripoti mabadiliko katika umiliki wa NFT. Hii inafanana na tukio la Hamisho la ERC-20, isipokuwa kwamba tunaripoti token_id badala ya kiasi. Hakuna anayemiliki anwani sifuri, kwa hivyo kwa kawaida tunaitumia kuripoti uundaji na uteketezaji wa tokeni. Ubaguzi mmoja ni uundaji wa mkataba, ambapo idadi yoyote ya NFT inaweza kuundwa na kugawiwa bila kutoa Transfer.

Idhini ya ERC-721 inafanana na kibali cha ERC-20: anwani maalum inaruhusiwa kuhamisha tokeni maalum, na Approval (owner, approved, token_id) hutolewa kila wakati anwani hiyo iliyoidhinishwa inapowekwa au kuthibitishwa tena. Hii inatoa utaratibu kwa mikataba kujibu inapokubali tokeni. Mikataba haiwezi kusikiliza matukio, kwa hivyo ikiwa utaihamishia tokeni tu "haijui" kuihusu. Kwa njia hii mmiliki kwanza anawasilisha idhini na kisha kutuma ombi kwa mkataba: "Nimekuidhinisha kuhamisha tokeni X, tafadhali fanya ...". Hili ni chaguo la muundo ili kufanya kiwango cha ERC-721 kifanane na kiwango cha ERC-20. Kwa sababu tokeni za ERC-721 hazifungiki, mkataba unaweza pia kutambua kwamba ulipata tokeni maalum kwa kuangalia umiliki wa tokeni.

Hatimaye, ApprovalForAll (owner, operator, approved) hutolewa wakati mhudumu anapowezeshwa au kulemazwa kwa mmiliki. Wakati mwingine ni muhimu kuwa na mhudumu anayeweza kusimamia tokeni zote za akaunti za aina maalum (zile zinazosimamiwa na mkataba maalum), sawa na nguvu ya kisheria. Kwa mfano, ninaweza kutaka kutoa nguvu kama hiyo kwa mkataba ambao unakagua ikiwa sijawasiliana nao kwa miezi sita, na ikiwa ndivyo unasambaza rasilimali zangu kwa warithi wangu (ikiwa mmoja wao ataiomba, mikataba haiwezi kufanya chochote bila kuitwa na muamala). Katika ERC-20 tunaweza tu kutoa kibali kikubwa kwa mkataba wa urithi, lakini hiyo haifanyi kazi kwa ERC-721 kwa sababu tokeni hazifungiki. Hii ndiyo sawa yake. Thamani ya approved inatuambia ikiwa tukio ni la idhini, au utoaji wa idhini.

Vigezo vya Hali

Vigezo hivi vina hali ya sasa ya tokeni: zipi zinapatikana na nani anazimiliki. Vingi vya hivi ni vitu vya HashMap, ramani za mwelekeo mmoja zilizopo kati ya aina mbili (inafunguka katika kichupo kipya).

# @dev Ramani kutoka Kitambulisho cha NFT hadi anwani inayoimiliki.
idToOwner: HashMap[uint256, address]

# @dev Ramani kutoka Kitambulisho cha NFT hadi anwani iliyoidhinishwa.
idToApprovals: HashMap[uint256, address]

Vitambulisho vya mtumiaji na mkataba katika Ethereum vinawakilishwa na anwani za biti 160. Vigezo hivi viwili vinachora ramani kutoka kwa vitambulisho vya tokeni hadi kwa wamiliki wake na wale walioidhinishwa kuzihamisha (kwa kiwango cha juu cha mmoja kwa kila moja). Katika Ethereum, data ambayo haijaanzishwa kila wakati ni sifuri, kwa hivyo ikiwa hakuna mmiliki au mhamishaji aliyeidhinishwa thamani ya tokeni hiyo ni sifuri.

# @dev Ramani kutoka anwani ya mmiliki hadi idadi ya tokeni zake.
ownerToNFTokenCount: HashMap[address, uint256]

Kigezo hiki kinashikilia idadi ya tokeni kwa kila mmiliki. Hakuna ramani kutoka kwa wamiliki hadi tokeni, kwa hivyo njia pekee ya kutambua tokeni ambazo mmiliki maalum anamiliki ni kuangalia nyuma katika historia ya matukio ya mnyororo wa vitalu na kuona matukio yanayofaa ya Transfer. Tunaweza kutumia kigezo hiki kujua wakati tuna NFT zote na hatuhitaji kuangalia zaidi nyuma kwa wakati.

Kumbuka kwamba algoriti hii inafanya kazi tu kwa violesura vya mtumiaji na seva za nje. Msimbo unaoendeshwa kwenye mnyororo wa vitalu wenyewe hauwezi kusoma matukio yaliyopita.

# @dev Ramani kutoka anwani ya mmiliki hadi ramani ya anwani za wahudumu.
ownerToOperators: HashMap[address, HashMap[address, bool]]

Akaunti inaweza kuwa na zaidi ya mhudumu mmoja. HashMap rahisi haitoshi kufuatilia, kwa sababu kila ufunguo unaongoza kwenye thamani moja. Badala yake, unaweza kutumia HashMap[address, bool] kama thamani. Kwa chaguo-msingi thamani ya kila anwani ni False, ambayo inamaanisha si mhudumu. Unaweza kuweka thamani kuwa True kama inavyohitajika.

# @dev Anwani ya mfuaji, anayeweza kufua tokeni
minter: address

Tokeni mpya zinapaswa kuundwa kwa namna fulani. Katika mkataba huu kuna chombo kimoja kinachoruhusiwa kufanya hivyo, minter. Hii inawezekana inatosha kwa mchezo, kwa mfano. Kwa madhumuni mengine, inaweza kuwa muhimu kuunda mantiki ngumu zaidi ya biashara.

# @dev Orodha tuli ya vitambulisho vya kiolesura vya ERC165 vinavyotumika
SUPPORTED_INTERFACES: constant(bytes4[2]) = [
    # Kitambulisho cha kiolesura cha ERC165 cha ERC165
    0x01ffc9a7,
    # Kitambulisho cha kiolesura cha ERC165 cha ERC721
    0x80ac58cd,
]

ERC-165 (inafunguka katika kichupo kipya) inabainisha utaratibu wa mkataba kufichua jinsi programu zinavyoweza kuwasiliana nao, ni ERC zipi unazofuata. SUPPORTED_INTERFACES ni orodha isiyobadilika ya vitambulisho viwili vya kiolesura vya baiti nne ambavyo mkataba huu unafuata: ERC-165 yenyewe na ERC-721.

Kazi

Hizi ndizo kazi ambazo zinatekeleza ERC-721 haswa.

Konstrukta

@deploy
def __init__():

Katika Vyper, kama ilivyo katika Python, kazi ya konstrukta inaitwa __init__. Imewekwa alama ya mapambo ya @deploy, ambayo inamaanisha inaendeshwa mara moja, wakati mkataba unaposambazwa.

    """
    @dev Konstrukta ya mkataba.
    """

Katika Python, na katika Vyper, unaweza pia kuunda maoni kwa kubainisha mfuatano wa mistari mingi (ambao huanza na kuishia na """), na kutoutumia kwa njia yoyote. Maoni haya yanaweza pia kujumuisha NatSpec (inafunguka katika kichupo kipya).

    self.minter = msg.sender

Ili kufikia vigezo vya hali unatumia self.<variable name> (tena, sawa na katika Python). Konstrukta inarekodi akaunti iliyosambaza mkataba kama minter.

Kazi za Kutazama

Hizi ni kazi ambazo hazibadilishi hali ya mnyororo wa vitalu, na kwa hivyo zinaweza kutekelezwa bila malipo ikiwa zinaitwa kutoka nje. Ikiwa kazi za kutazama zinaitwa na mkataba bado zinapaswa kutekelezwa kwenye kila nodi na kwa hivyo zinagharimu gesi.

@view
@external

Maneno haya muhimu kabla ya ufafanuzi wa kazi ambayo huanza na alama ya at (@) yanaitwa mapambo. Yanabainisha mazingira ambayo kazi inaweza kuitwa.

  • @view inabainisha kuwa kazi hii ni ya kutazama.
  • @external inabainisha kuwa kazi hii maalum inaweza kuitwa na miamala na mikataba mingine.
def supportsInterface(interface_id: bytes4) -> bool:

Tofauti na Python, Vyper ni lugha yenye aina tuli (inafunguka katika kichupo kipya). Huwezi kutangaza kigezo, au kigezo cha kazi, bila kutambua aina ya data (inafunguka katika kichupo kipya). Katika kesi hii kigezo cha kuingiza ni bytes4, thamani ya baiti nne, na pato ni thamani ya boolean.

    """
    @dev Utambulisho wa kiolesura umebainishwa katika ERC-165.
    @param interface_id Kitambulisho cha kiolesura
    """
    return interface_id in SUPPORTED_INTERFACES

Rejesha True ikiwa interface_id ni mojawapo ya vitambulisho vya kiolesura katika orodha ya SUPPORTED_INTERFACES.

### KAZI ZA KUTAZAMA ###

Hizi ni kazi za kutazama zinazofanya taarifa kuhusu tokeni zipatikane kwa watumiaji na mikataba mingine.

Mstari huu unathibitisha (inafunguka katika kichupo kipya) kwamba _owner si anwani sifuri, iliyoandikwa kama empty(address). Ikiwa ndivyo, kuna kosa na operesheni inatenguliwa.

Katika Mashine Pepe ya Ethereum (EVM) hifadhi yoyote ambayo haina thamani iliyohifadhiwa ndani yake ni sifuri. Ikiwa hakuna tokeni kwenye _tokenId basi thamani ya self.idToOwner[_tokenId] ni sifuri. Katika kesi hiyo kazi inatengua.

Kumbuka kwamba getApproved inaweza kurejesha sifuri. Ikiwa tokeni ni halali inarejesha self.idToApprovals[_tokenId]. Ikiwa hakuna muidhinishaji thamani hiyo ni sifuri.

Kazi hii inakagua ikiwa _operator inaruhusiwa kusimamia tokeni zote za _owner katika mkataba huu. Kwa sababu kunaweza kuwa na wahudumu wengi, hii ni HashMap ya viwango viwili.

Kazi za Kusaidia Hamisho

Kazi hizi zinatekeleza operesheni ambazo ni sehemu ya kuhamisha au kusimamia tokeni.


### WASAIDIZI WA KAZI ZA HAMISHO ###

@view
@internal

Pambo hili, @internal, linamaanisha kuwa kazi inapatikana tu kutoka kwa kazi zingine ndani ya mkataba huo huo. Kwa kawaida, majina ya kazi hizi pia huanza na mstari wa chini (_).

Kuna njia tatu ambazo anwani inaweza kuruhusiwa kuhamisha tokeni:

  1. Anwani ni mmiliki wa tokeni
  2. Anwani imeidhinishwa kutumia tokeni hiyo
  3. Anwani ni mhudumu kwa mmiliki wa tokeni

Kazi iliyo hapo juu inaweza kuwa ya kutazama kwa sababu haibadilishi hali. Ili kupunguza gharama za uendeshaji, kazi yoyote ambayo inaweza kuwa ya kutazama inapaswa kuwa ya kutazama.

Kunapokuwa na tatizo na hamisho tunatengua wito.

Badilisha thamani tu ikiwa ni lazima. Vigezo vya hali huishi kwenye hifadhi. Kuandika kwenye hifadhi ni mojawapo ya operesheni ghali zaidi ambazo EVM (Mashine Pepe ya Ethereum) hufanya (kwa upande wa gesi). Kwa hivyo, ni wazo zuri kuipunguza, hata kuandika thamani iliyopo kuna gharama kubwa.

Tuna kazi hii ya ndani kwa sababu kuna njia mbili za kuhamisha tokeni (ya kawaida na salama), lakini tunataka eneo moja tu katika msimbo ambapo tunafanya hivyo ili kurahisisha ukaguzi.

Ili kutoa tukio katika Vyper unatumia taarifa ya log (tazama hapa kwa maelezo zaidi (inafunguka katika kichupo kipya)). Kwa sababu matukio ni ya kiolesura kilichoingizwa, tunayarejelea kama IERC721.Transfer na kupitisha nyanja zake kwa neno muhimu.

Kazi za Hamisho

Kazi hii inakuwezesha kuhamisha kwenda kwenye anwani yoyote. Isipokuwa anwani ni mtumiaji, au mkataba unaojua jinsi ya kuhamisha tokeni, tokeni yoyote unayohamisha itakwama kwenye anwani hiyo na kukosa faida.

Pambo la @payable liko hapa kwa sababu kiolesura cha IERC721 kinatangaza transferFrom, safeTransferFrom, na approve kama zinazolipwa, kwa hivyo mkataba unaotekeleza kiolesura unapaswa kulingana na saini hizo.

Ni Sawa kufanya hamisho kwanza kwa sababu ikiwa kuna tatizo tutatengua hata hivyo, kwa hivyo kila kitu kilichofanywa katika wito kitaghairiwa.

    if _to.is_contract: # kagua ikiwa `_to` ni anwani ya mkataba

Kwanza kagua ili kuona ikiwa anwani ni mkataba (ikiwa ina msimbo). Ikiwa sivyo, chukulia ni anwani ya mtumiaji na mtumiaji ataweza kutumia tokeni au kuihamisha. Lakini usiruhusu ikupe hisia potofu za usalama. Unaweza kupoteza tokeni, hata kwa safeTransferFrom, ikiwa utazihamisha kwenye anwani ambayo hakuna anayejua ufunguo wa siri wake.

        returnValue: bytes4 = extcall ERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data)

Ita mkataba lengwa ili kuona ikiwa unaweza kupokea tokeni za ERC-721. Vyper 0.4 inahitaji wito kwa mikataba mingine kuwekewa alama, kwa hivyo wito unawekewa kiambishi awali cha extcall.

        # Inatupa kosa ikiwa mwisho wa hamisho ni mkataba ambao hautekelezi 'onERC721Received'
        assert returnValue == method_id("onERC721Received(address,address,uint256,bytes)", output_type=bytes4)

Ikiwa mwisho ni mkataba, lakini ambao haukubali tokeni za ERC-721 (au ambao umeamua kutokubali hamisho hili maalum), tengua.

Kwa kawaida ikiwa hutaki kuwa na muidhinishaji unateua anwani sifuri, si wewe mwenyewe.

    # Kagua mahitaji
    senderIsOwner: bool = self.idToOwner[_tokenId] == msg.sender
    senderIsApprovedForAll: bool = (self.ownerToOperators[owner])[msg.sender]
    assert (senderIsOwner or senderIsApprovedForAll)

Ili kuweka idhini unaweza kuwa mmiliki, au mhudumu aliyeidhinishwa na mmiliki.

Kufua Tokeni Mpya na Kuteketeza Zilizopo

Akaunti iliyounda mkataba ni minter, mtumiaji mkuu ambaye ameidhinishwa kufua NFT mpya. Hata hivyo, hata yeye haruhusiwi kuteketeza tokeni zilizopo. Mmiliki pekee, au chombo kilichoidhinishwa na mmiliki, ndiye anayeweza kufanya hivyo.

### KAZI ZA KUFUA NA KUTEKETEZA ###

@external
def mint(_to: address, _tokenId: uint256) -> bool:

Kazi hii kila wakati inarejesha True, kwa sababu ikiwa operesheni itashindwa inatenguliwa.

Mfuaji pekee (akaunti iliyounda mkataba wa ERC-721) ndiye anayeweza kufua tokeni mpya. Hili linaweza kuwa tatizo katika siku zijazo ikiwa tunataka kubadilisha utambulisho wa mfuaji. Katika mkataba wa uzalishaji labda ungetaka kazi inayomruhusu mfuaji kuhamisha mapendeleo ya mfuaji kwa mtu mwingine.

    # Hutengua ikiwa `_to` ni anwani sifuri
    assert _to != ZERO_ADDRESS
    # Ongeza NFT. Hutengua ikiwa `_tokenId` inamilikiwa na mtu
    self._addTokenTo(_to, _tokenId)
    log Transfer(ZERO_ADDRESS, _to, _tokenId)
    return True

Kwa kawaida, ufuzi wa tokeni mpya huhesabiwa kama hamisho kutoka kwenye anwani sifuri.

Mtu yeyote anayeruhusiwa kuhamisha tokeni anaruhusiwa kuiteketeza. Ingawa uteketezaji unaonekana sawa na hamisho kwenda kwenye anwani sifuri, anwani sifuri haipokei tokeni haswa. Hii inaturuhusu kufungua hifadhi yote iliyotumika kwa tokeni, ambayo inaweza kupunguza gharama ya gesi ya muamala.

Kutumia Mkataba Huu

Tofauti na Solidity, Vyper haina urithi. Huu ni uamuzi wa makusudi wa muundo ili kufanya msimbo uwe wazi zaidi na kwa hivyo rahisi kulinda. Kwa hivyo ili kuunda mkataba wako wa Vyper ERC-721 unachukua mkataba huu (inafunguka katika kichupo kipya) na kuubadilisha ili kutekeleza mantiki ya biashara unayotaka.

Hitimisho

Kwa ukaguzi, haya ni baadhi ya mawazo muhimu zaidi katika mkataba huu:

  • Ili kupokea tokeni za ERC-721 kwa hamisho salama, mikataba inapaswa kutekeleza kiolesura cha ERC721Receiver.
  • Hata kama unatumia hamisho salama, tokeni bado zinaweza kukwama ikiwa utazituma kwenye anwani ambayo ufunguo wa siri wake haujulikani.
  • Kunapokuwa na tatizo na operesheni ni wazo zuri kutumia revert kwa wito, badala ya kurejesha tu thamani ya kushindwa.
  • Tokeni za ERC-721 huwepo zinapokuwa na mmiliki.
  • Kuna njia tatu za kuidhinishwa kuhamisha NFT. Unaweza kuwa mmiliki, kuidhinishwa kwa tokeni maalum, au kuwa mwendeshaji kwa tokeni zote za mmiliki.
  • Matukio yaliyopita yanaonekana tu nje ya mnyororo wa vitalu. Msimbo unaoendeshwa ndani ya mnyororo wa vitalu hauwezi kuyaona.

Sasa nenda katekeleze mikataba salama ya Vyper.

Tazama hapa kwa kazi zangu zaidi (inafunguka katika kichupo kipya).