Mwongozo wa mkataba wa daraja la kawaida la Optimism
Optimismopens in a new tab ni Optimistic Rollup. Optimistic rollups zinaweza kuchakata miamala kwa bei ya chini zaidi kuliko Mtandao Mkuu wa Ethereum (pia inajulikana kama safu 1 au L1) kwa sababu miamala inachakatwa na nodi chache tu, badala ya kila nodi kwenye mtandao. Wakati huo huo, data yote imeandikwa kwa L1 ili kila kitu kiweze kuthibitishwa na kujengwa upya kwa uadilifu wote na dhamana ya upatikanaji wa Mtandao Mkuu.
Ili kutumia rasilimali za L1 kwenye Optimism (au L2 nyingine yoyote), rasilimali zinahitaji kuvushwa kwa daraja. Njia moja ya kufanikisha hili ni kwa watumiaji kufunga rasilimali (ETH na tokeni za ERC-20 ndizo za kawaida zaidi) kwenye L1, na kupokea rasilimali sawa za kutumia kwenye L2. Hatimaye, yeyote atakayeishia nazo anaweza kutaka kuzivusha kwa daraja kurudi L1. Wakati wa kufanya hivi, rasilimali huchomwa kwenye L2 na kisha kurejeshwa kwa mtumiaji kwenye L1.
Hivi ndivyo daraja la kawaida la Optimismopens in a new tab linavyofanya kazi. Katika makala haya tunapitia msimbo chanzo wa daraja hilo ili kuona jinsi linavyofanya kazi na kulichunguza kama mfano wa msimbo wa Solidity ulioandikwa vizuri.
Mtiririko wa udhibiti
Daraja lina mitiririko mikuu miwili:
- Kuweka (kutoka L1 hadi L2)
- Kutoa (kutoka L2 hadi L1)
Mtiririko wa uwekaji
Safu 1
- Ikiwa unaweka ERC-20, mwekaji anatoa ruhusa kwa daraja kutumia kiasi kinachowekwa
- Mwekaji anapiga simu daraja la L1 (
depositERC20,depositERC20To,depositETH, audepositETHTo) - Daraja la L1 linachukua umiliki wa rasilimali iliyovushwa kwa daraja
- ETH: Rasilimali inahamishwa na mwekaji kama sehemu ya simu
- ERC-20: Rasilimali inahamishwa na daraja kwake yenyewe kwa kutumia ruhusa iliyotolewa na mwekaji
- Daraja la L1 linatumia utaratibu wa ujumbe wa vikoa tofauti kupiga simu
finalizeDepositkwenye daraja la L2
Safu 2
- Daraja la L2 huhakikisha simu kwa
finalizeDepositni halali:- Imetoka kwenye mkataba wa ujumbe wa vikoa tofauti
- Hapo awali ilitoka kwenye daraja kwenye L1
- Daraja la L2 huangalia ikiwa mkataba wa tokeni ya ERC-20 kwenye L2 ni sahihi:
- Mkataba wa L2 unaripoti kuwa mwenzake wa L1 ni sawa na ule ambao tokeni zilitoka kwenye L1
- Mkataba wa L2 unaripoti kuwa unaauni kiolesura sahihi (kwa kutumia ERC-165opens in a new tab).
- Ikiwa mkataba wa L2 ni sahihi, piga simu ili kutoa idadi ifaayo ya tokeni kwa anwani ifaayo. Ikiwa sivyo, anza mchakato wa kutoa ili kumruhusu mtumiaji kudai tokeni kwenye L1.
Mtiririko wa utoaji
Safu 2
- Mtoaji anapiga simu daraja la L2 (
withdrawauwithdrawTo) - Daraja la L2 huchoma idadi ifaayo ya tokeni za
msg.sender - Daraja la L2 hutumia utaratibu wa ujumbe wa vikoa tofauti kupiga simu
finalizeETHWithdrawalaufinalizeERC20Withdrawalkwenye daraja la L1
Safu 1
- Daraja la L1 huhakikisha simu kwa
finalizeETHWithdrawalaufinalizeERC20Withdrawalni halali:- Imetoka kwenye utaratibu wa ujumbe wa vikoa tofauti
- Hapo awali ilitoka kwenye daraja kwenye L2
- Daraja la L1 huhamisha rasilimali ifaayo (ETH au ERC-20) kwa anwani ifaayo
Msimbo wa Safu 1
Huu ndio msimbo unaoendeshwa kwenye L1, Mtandao Mkuu wa Ethereum.
IL1ERC20Bridge
Kiolesura hiki kimefafanuliwa hapaopens in a new tab. Inajumuisha kazi na ufafanuzi unaohitajika kwa kuvusha tokeni za ERC-20 kwa daraja.
1// SPDX-License-Identifier: MITSehemu kubwa ya msimbo wa Optimism hutolewa chini ya leseni ya MITopens in a new tab.
1pragma solidity >0.5.0 <0.9.0;Wakati wa kuandika toleo la hivi karibuni la Solidity ni 0.8.12. Hadi toleo la 0.9.0 litolewe, hatujui kama msimbo huu unaendana nalo au la.
1/**2 * @title IL1ERC20Bridge3 */4interface IL1ERC20Bridge {5 /**********6 * Matukio *7 **********/89 event ERC20DepositInitiated(Onyesha yoteKatika istilahi za daraja la Optimism kuweka kunamaanisha uhamisho kutoka L1 hadi L2, na kutoa kunamaanisha uhamisho kutoka L2 hadi L1.
1 anwani iliyoorodheshwa _l1Token,2 anwani iliyoorodheshwa _l2Token,Katika hali nyingi anwani ya ERC-20 kwenye L1 si sawa na anwani ya ERC-20 inayolingana kwenye L2.
Unaweza kuona orodha ya anwani za tokeni hapaopens in a new tab.
Anwani yenye chainId 1 iko kwenye L1 (Mtandao Mkuu) na anwani yenye chainId 10 iko kwenye L2 (Optimism).
Thamani zingine mbili za chainId ni za mtandao wa majaribio wa Kovan (42) na mtandao wa majaribio wa Optimistic Kovan (69).
1 anwani iliyoorodheshwa _from,2 anwani _to,3 uint256 _amount,4 bytes _data5 );Inawezekana kuongeza maelezo kwenye uhamisho, ambapo huongezwa kwenye matukio yanayoyaripoti.
1 event ERC20WithdrawalFinalized(2 anwani iliyoorodheshwa _l1Token,3 anwani iliyoorodheshwa _l2Token,4 anwani iliyoorodheshwa _from,5 anwani _to,6 uint256 _amount,7 bytes _data8 );Mkataba huo huo wa daraja hushughulikia uhamisho katika pande zote mbili. Kwa upande wa daraja la L1, hii inamaanisha uanzishaji wa uwekaji na ukamilishaji wa utoaji.
12 /********************3 * Kazi za Umma *4 ********************/56 /**7 * @dev pata anwani ya mkataba wa daraja la L2 unaolingana.8 * @return Anwani ya mkataba wa daraja la L2 unaolingana.9 */10 function l2TokenBridge() external returns (anwani);Onyesha yoteKazi hii haihitajiki sana, kwa sababu kwenye L2 ni mkataba uliotumwa awali, kwa hivyo huwa kwenye anwani 0x4200000000000000000000000000000000000010.
Iko hapa kwa ulinganifu na daraja la L2, kwa sababu anwani ya daraja la L1 si rahisi kujua.
1 /**2 * @dev weka kiasi cha ERC20 kwenye salio la mpigaji simu kwenye L2.3 * @param _l1Token Anwani ya ERC20 ya L1 tunayoweka4 * @param _l2Token Anwani ya ERC20 ya L2 inayolingana na L15 * @param _amount Kiasi cha ERC20 cha kuweka6 * @param _l2Gas Kikomo cha gesi kinachohitajika kukamilisha uwekaji kwenye L2.7 * @param _data Data ya hiari ya kupeleka kwa L2. Data hii hutolewa8 * kama urahisi tu kwa mikataba ya nje. Mbali na kutekeleza urefu wa juu,9 * mikataba hii haitoi dhamana yoyote kuhusu maudhui yake.10 */11 function depositERC20(12 anwani _l1Token,13 anwani _l2Token,14 uint256 _amount,15 uint32 _l2Gas,16 bytes calldata _data17 ) external;Onyesha yoteKigezo cha _l2Gas ni kiasi cha gesi ya L2 ambacho muamala unaruhusiwa kutumia.
Hadi kikomo fulani (cha juu), hii ni bureopens in a new tab, kwa hivyo isipokuwa mkataba wa ERC-20 unafanya jambo la ajabu sana wakati wa kutoa, haipaswi kuwa suala.
Kazi hii inashughulikia hali ya kawaida, ambapo mtumiaji huvusha rasilimali kwa daraja kwenda anwani ileile kwenye mnyororo wa bloku tofauti.
1 /**2 * @dev weka kiasi cha ERC20 kwenye salio la mpokeaji kwenye L2.3 * @param _l1Token Anwani ya ERC20 ya L1 tunayoweka4 * @param _l2Token Anwani ya ERC20 ya L2 inayolingana na L15 * @param _to Anwani ya L2 ya kuweka utoaji.6 * @param _amount Kiasi cha ERC20 cha kuweka.7 * @param _l2Gas Kikomo cha gesi kinachohitajika kukamilisha uwekaji kwenye L2.8 * @param _data Data ya hiari ya kupeleka kwa L2. Data hii hutolewa9 * kama urahisi tu kwa mikataba ya nje. Mbali na kutekeleza urefu wa juu,10 * mikataba hii haitoi dhamana yoyote kuhusu maudhui yake.11 */12 function depositERC20To(13 anwani _l1Token,14 anwani _l2Token,15 anwani _to,16 uint256 _amount,17 uint32 _l2Gas,18 bytes calldata _data19 ) external;Onyesha yoteKazi hii ni karibu sawa na depositERC20, lakini inakuwezesha kutuma ERC-20 kwa anwani tofauti.
1 /*************************2 * Kazi za Mnyororo-Msalaba *3 *************************/45 /**6 * @dev Kamilisha utoaji kutoka L2 hadi L1, na weka fedha kwenye salio la mpokeaji la7 * tokeni ya L1 ERC20.8 * Simu hii itashindwa ikiwa utoaji ulioanzishwa kutoka L2 haujakamilishwa.9 *10 * @param _l1Token Anwani ya tokeni ya L1 ya kukamilisha utoaji.11 * @param _l2Token Anwani ya tokeni ya L2 ambapo utoaji ulianzishwa.12 * @param _from Anwani ya L2 inayoanzisha uhamisho.13 * @param _to Anwani ya L1 ya kuweka utoaji.14 * @param _amount Kiasi cha ERC20 cha kuweka.15 * @param _data Data iliyotolewa na mtumaji kwenye L2. Data hii hutolewa16 * kama urahisi tu kwa mikataba ya nje. Mbali na kutekeleza urefu wa juu,17 * mikataba hii haitoi dhamana yoyote kuhusu maudhui yake.18 */19 function finalizeERC20Withdrawal(20 anwani _l1Token,21 anwani _l2Token,22 anwani _from,23 anwani _to,24 uint256 _amount,25 bytes calldata _data26 ) external;27}Onyesha yoteUtoaji (na ujumbe mwingine kutoka L2 hadi L1) katika Optimism ni mchakato wa hatua mbili:
- Muamala wa kuanzisha kwenye L2.
- Muamala wa ukamilishaji au kudai kwenye L1. Muamala huu unahitaji kufanyika baada ya kipindi cha changamoto ya makosaopens in a new tab kwa muamala wa L2 kuisha.
IL1StandardBridge
Kiolesura hiki kimefafanuliwa hapaopens in a new tab.
Faili hili lina ufafanuzi wa matukio na kazi kwa ETH.
Ufafanuzi huu unafanana sana na ule uliofafanuliwa katika IL1ERC20Bridge hapo juu kwa ERC-20.
Kiolesura cha daraja kimegawanywa kati ya faili mbili kwa sababu baadhi ya tokeni za ERC-20 zinahitaji usindikaji maalum na haziwezi kushughulikiwa na daraja la kawaida.
Kwa njia hii daraja maalum linaloshughulikia tokeni kama hiyo linaweza kutekeleza IL1ERC20Bridge na sio lazima pia kuvusha ETH kwa daraja.
1// SPDX-License-Identifier: MIT2pragma solidity >0.5.0 <0.9.0;34import "./IL1ERC20Bridge.sol";56/**7 * @title IL1StandardBridge8 */9interface IL1StandardBridge is IL1ERC20Bridge {10 /**********11 * Matukio *12 **********/13 event ETHDepositInitiated(14 anwani iliyoorodheshwa _from,15 anwani iliyoorodheshwa _to,16 uint256 _amount,17 bytes _data18 );Onyesha yoteTukio hili ni karibu sawa na toleo la ERC-20 (ERC20DepositInitiated), isipokuwa bila anwani za tokeni za L1 na L2.
Hali kadhalika kwa matukio mengine na kazi.
1 event ETHWithdrawalFinalized(2 .3 .4 .5 );67 /********************8 * Kazi za Umma *9 ********************/1011 /**12 * @dev Weka kiasi cha ETH kwenye salio la mpigaji simu kwenye L2.13 .14 .15 .16 */17 function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;1819 /**20 * @dev Weka kiasi cha ETH kwenye salio la mpokeaji kwenye L2.21 .22 .23 .24 */25 function depositETHTo(26 anwani _to,27 uint32 _l2Gas,28 bytes calldata _data29 ) external payable;3031 /*************************32 * Kazi za Mnyororo-Msalaba *33 *************************/3435 /**36 * @dev Kamilisha utoaji kutoka L2 hadi L1, na weka fedha kwenye salio la mpokeaji la37 * tokeni ya L1 ETH. Kwa kuwa ni xDomainMessenger pekee anayeweza kupiga simu kazi hii, haitapigwa kamwe38 * kabla ya utoaji kukamilishwa.39 .40 .41 .42 */43 function finalizeETHWithdrawal(44 anwani _from,45 anwani _to,46 uint256 _amount,47 bytes calldata _data48 ) external;49}Onyesha yoteCrossDomainEnabled
Mkataba huuopens in a new tab unarithiwa na madaraja yote mawili (L1 na L2) kutuma ujumbe kwa safu nyingine.
1// SPDX-License-Identifier: MIT2pragma solidity >0.5.0 <0.9.0;34/* Interface Imports */5import { ICrossDomainMessenger } from "./ICrossDomainMessenger.sol";Kiolesura hikiopens in a new tab kinaeleza mkataba jinsi ya kutuma ujumbe kwa safu nyingine, kwa kutumia mtumaji ujumbe wa vikoa tofauti. Mtumaji ujumbe huu wa vikoa tofauti ni mfumo mwingine kabisa, na unastahili makala yake, ambayo natumai kuandika katika siku zijazo.
1/**2 * @title CrossDomainEnabled3 * @dev Mkataba msaidizi kwa mikataba inayofanya mawasiliano ya vikoa tofauti4 *5 * Mkusanyaji uliotumika: umefafanuliwa na mkataba unaorithi6 */7contract CrossDomainEnabled {8 /*************9 * Vigeu *10 *************/1112 // Mkataba wa Mtumaji Ujumbe unaotumika kutuma na kupokea ujumbe kutoka kwa kikoa kingine.13 anwani public messenger;1415 /***************16 * Kijenzi *17 ***************/1819 /**20 * @param _messenger Anwani ya CrossDomainMessenger kwenye safu ya sasa.21 */22 constructor(anwani _messenger) {23 messenger = _messenger;24 }Onyesha yoteKigezo kimoja ambacho mkataba unahitaji kujua, anwani ya mtumaji ujumbe wa vikoa tofauti kwenye safu hii. Kigezo hiki kinawekwa mara moja, katika kijenzi, na hakibadiliki kamwe.
12 /**********************3 * Virekebishaji Kazi *4 **********************/56 /**7 * Hutekeleza kwamba kazi iliyorekebishwa inaweza kupigwa simu tu na akaunti maalum ya kikoa tofauti.8 * @param _sourceDomainAccount Akaunti pekee kwenye kikoa cha asili ambayo9 * imethibitishwa kupiga simu kazi hii.10 */11 modifier onlyFromCrossDomainAccount(anwani _sourceDomainAccount) {Onyesha yoteUjumbe wa vikoa tofauti unaweza kufikiwa na mkataba wowote kwenye mnyororo wa bloku ambapo unaendeshwa (iwe Mtandao Mkuu wa Ethereum au Optimism). Lakini tunahitaji daraja kwa kila upande tu kuamini ujumbe fulani ikiwa unatoka kwenye daraja kwa upande mwingine.
1 require(2 msg.sender == address(getCrossDomainMessenger()),3 "OVM_XCHAIN: mkataba wa mtumaji ujumbe haujathibitishwa"4 );Ujumbe tu kutoka kwa mtumaji ujumbe wa vikoa tofauti unaofaa (messenger, kama unavyoona hapa chini) unaweza kuaminiwa.
12 require(3 getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,4 "OVM_XCHAIN: mtumaji asiye sahihi wa ujumbe wa kikoa tofauti"5 );Njia ambayo mtumaji ujumbe wa vikoa tofauti anatoa anwani iliyotuma ujumbe na safu nyingine ni kazi ya .xDomainMessageSender()opens in a new tab.
Muda wote inapoitwa katika muamala ulioanzishwa na ujumbe inaweza kutoa habari hii.
Tunahitaji kuhakikisha kuwa ujumbe tuliopokea ulitoka kwenye daraja lingine.
12 _;3 }45 /**********************6 * Kazi za Ndani *7 **********************/89 /**10 * Hupata mtumaji ujumbe, kawaida kutoka kwenye hifadhi. Kazi hii inawekwa wazi iwapo mkataba mtoto11 * unahitaji kubatilisha.12 * @rejesha Anwani ya mkataba wa mtumaji ujumbe wa vikoa tofauti ambayo inapaswa kutumika.13 */14 function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {15 return ICrossDomainMessenger(messenger);16 }Onyesha yoteKazi hii inarejesha mtumaji ujumbe wa vikoa tofauti.
Tunatumia kazi badala ya kigezo messenger kuruhusu mikataba inayorithi kutoka kwa hii kutumia algoriti kubainisha ni mtumaji ujumbe gani wa vikoa tofauti wa kutumia.
12 /**3 * Hutuma ujumbe kwa akaunti kwenye kikoa kingine4 * @param _crossDomainTarget Mpokeaji aliyekusudiwa kwenye kikoa lengwa5 * @param _message Data ya kutuma kwa lengo (kawaida calldata kwa kazi yenye6 * `onlyFromCrossDomainAccount()`)7 * @param _gasLimit Kikomo cha gesi kwa risiti ya ujumbe kwenye kikoa lengwa.8 */9 function sendCrossDomainMessage(10 anwani _crossDomainTarget,11 uint32 _gasLimit,12 bytes memory _messageOnyesha yoteHatimaye, kazi inayotuma ujumbe kwa safu nyingine.
1 ) internal {2 // slither-disable-next-line reentrancy-events, reentrancy-benignSlitheropens in a new tab ni kichanganuzi tuli ambacho Optimism huendesha kwenye kila mkataba kutafuta udhaifu na matatizo mengine yanayoweza kutokea. Katika kesi hii, mstari unaofuata unasababisha udhaifu mbili:
1 getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);2 }3}Katika kesi hii hatuna wasiwasi kuhusu kuingia tena tunajua getCrossDomainMessenger() inarejesha anwani inayoaminika, hata kama Slither haina njia ya kujua hilo.
Mkataba wa daraja la L1
Msimbo chanzo wa mkataba huu uko hapaopens in a new tab.
1// SPDX-License-Identifier: MIT2pragma solidity ^0.8.9;Violesura vinaweza kuwa sehemu ya mikataba mingine, kwa hivyo vinapaswa kuunga mkono anuwai ya matoleo ya Solidity. Lakini daraja lenyewe ni mkataba wetu, na tunaweza kuwa wakali kuhusu toleo gani la Solidity linatumia.
1/* Interface Imports */2import { IL1StandardBridge } from "./IL1StandardBridge.sol";3import { IL1ERC20Bridge } from "./IL1ERC20Bridge.sol";IL1ERC20Bridge na IL1StandardBridge zimeelezwa hapo juu.
1import { IL2ERC20Bridge } from "../../L2/messaging/IL2ERC20Bridge.sol";Kiolesura hikiopens in a new tab kinaturuhusu kuunda ujumbe wa kudhibiti daraja la kawaida kwenye L2.
1import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";Kiolesura hikiopens in a new tab kinaturuhusu kudhibiti mikataba ya ERC-20. Unaweza kusoma zaidi kuhusu hilo hapa.
1/* Library Imports */2import { CrossDomainEnabled } from "../../libraries/bridge/CrossDomainEnabled.sol";Kama ilivyoelezwa hapo juu, mkataba huu unatumika kwa ujumbe wa kati ya safu.
1import { Lib_PredeployAddresses } from "../../libraries/constants/Lib_PredeployAddresses.sol";Lib_PredeployAddressesopens in a new tab ina anwani za mikataba ya L2 ambayo huwa na anwani sawa kila wakati. Hii inajumuisha daraja la kawaida kwenye L2.
1import { Address } from "@openzeppelin/contracts/utils/Address.sol";Huduma za Anwani za OpenZeppelinopens in a new tab. Inatumika kutofautisha kati ya anwani za mkataba na zile za akaunti zinazomilikiwa na watu wa nje (EOA).
Kumbuka kuwa hili si suluhisho kamilifu, kwa sababu hakuna njia ya kutofautisha kati ya simu za moja kwa moja na simu zilizopigwa kutoka kwa kijenzi cha mkataba, lakini angalau hii inatuwezesha kutambua na kuzuia baadhi ya makosa ya kawaida ya watumiaji.
1import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";Kiwango cha ERC-20opens in a new tab kinaauni njia mbili kwa mkataba kuripoti kutofaulu:
- Batilisha
- Rejesha
false
Kushughulikia kesi zote mbili kungefanya msimbo wetu kuwa mgumu zaidi, kwa hivyo badala yake tunatumia SafeERC20 ya OpenZeppelinopens in a new tab, ambayo inahakikisha kushindwa kote kunasababisha ubatilishajiopens in a new tab.
1/**2 * @title L1StandardBridge3 * @dev L1 ETH na ERC20 Bridge ni mkataba unaohifadhi fedha za L1 zilizowekwa na tokeni za kawaida4 * ambazo zinatumika kwenye L2. Inasawazisha Daraja la L2 linalolingana, kulijulisha kuhusu uwekaji5 * na kulisikiliza kwa utoaji mpya uliokamilishwa.6 *7 */8contract L1StandardBridge is IL1StandardBridge, CrossDomainEnabled {9 using SafeERC20 for IERC20;Onyesha yoteMstari huu ndivyo tunavyobainisha kutumia kifuniko cha SafeERC20 kila tunapotumia kiolesura cha IERC20.
12 /********************************3 * Marejeleo ya Mkataba wa Nje *4 ********************************/56 anwani public l2TokenBridge;Anwani ya L2StandardBridge.
12 // Ramani za tokeni ya L1 kwa tokeni ya L2 kwa salio la tokeni ya L1 iliyowekwa3 mapping(anwani => mapping(anwani => uint256)) public deposits;Ramani maradufu kama hii ndiyo njia unayofafanua safu ya pande mbili isiyo na mpangilioopens in a new tab.
Thamani katika muundo huu wa data zinatambuliwa kama deposit[anwani ya tokeni ya L1][anwani ya tokeni ya L2].
Thamani chaguo-msingi ni sufuri.
Seli tu zilizowekwa kwa thamani tofauti ndizo huandikwa kwenye hifadhi.
12 /***************3 * Kijenzi *4 ***************/56 // Mkataba huu unaishi nyuma ya wakala, kwa hivyo vigezo vya kijenzi havitatumika.7 constructor() CrossDomainEnabled(anwani(0)) {}Ili kutaka kuweza kusasisha mkataba huu bila kulazimika kunakili vigezo vyote kwenye hifadhi.
Ili kufanya hivyo tunatumia Wakalaopens in a new tab, mkataba unaotumia delegatecallopens in a new tab kuhamisha simu kwa mkataba tofauti ambao anwani yake imehifadhiwa na mkataba wa wakala (unaposasisha unamwambia wakala kubadilisha anwani hiyo).
Unapotumia delegatecall hifadhi inabaki kuwa hifadhi ya mkataba unaopiga simu, kwa hivyo thamani za vigezo vyote vya hali ya mkataba haziathiriwi.
Moja ya athari za muundo huu ni kwamba hifadhi ya mkataba ambao ni uliopigiwa simu wa delegatecall haitumiwi na kwa hivyo thamani za kijenzi zilizopitishwa kwake hazijalishi.
Hii ndiyo sababu tunaweza kutoa thamani isiyo na maana kwa kijenzi cha CrossDomainEnabled.
Pia ndiyo sababu uanzishaji hapa chini umetenganishwa na kijenzi.
1 /******************2 * Uanzishaji *3 ******************/45 /**6 * @param _l1messenger Anwani ya L1 Messenger inayotumika kwa mawasiliano ya mnyororo-msalaba.7 * @param _l2TokenBridge Anwani ya daraja la kawaida la L2.8 */9 // slither-disable-next-line external-functionOnyesha yoteJaribio hili la Slitheropens in a new tab linatambua kazi ambazo hazipigwi simu kutoka kwa msimbo wa mkataba na kwa hivyo zinaweza kutangazwa kuwa za nje badala ya za umma.
Gharama ya gesi ya kazi za nje inaweza kuwa chini, kwa sababu zinaweza kupewa vigezo katika calldata.
Kazi zilizotangazwa kuwa za umma zinapaswa kufikiwa kutoka ndani ya mkataba.
Mikataba haiwezi kurekebisha calldata zao wenyewe, kwa hivyo vigezo vinapaswa kuwa kwenye kumbukumbu.
Wakati kazi kama hiyo inapoitwa kutoka nje, ni muhimu kunakili calldata kwenye kumbukumbu, ambayo inagharimu gesi.
Katika kesi hii kazi inaitwa mara moja tu, kwa hivyo ufanisi haujalishi kwetu.
1 function initialize(anwani _l1messenger, anwani _l2TokenBridge) public {2 require(messenger == address(0), "Mkataba tayari umeanzishwa.");Kazi ya initialize inapaswa kuitwa mara moja tu.
Ikiwa anwani ya mtumaji ujumbe wa vikoa tofauti wa L1 au daraja la tokeni la L2 itabadilika, tunaunda wakala mpya na daraja jipya linaloiita.
Hili haliwezekani kutokea isipokuwa mfumo mzima unaposasishwa, tukio la nadra sana.
Kumbuka kuwa kazi hii haina utaratibu wowote unaozuia nani anaweza kuiita.
Hii inamaanisha kuwa kwa nadharia mshambuliaji anaweza kusubiri hadi tutumie wakala na toleo la kwanza la daraja na kisha kufanya shughuli harakaopens in a new tab kufikia kazi ya initialize kabla ya mtumiaji halali kufanya hivyo. Lakini kuna njia mbili za kuzuia hili:
- Ikiwa mikataba haitumwi moja kwa moja na EOA lakini katika muamala ambao una mkataba mwingine uwaumbeopens in a new tab mchakato mzima unaweza kuwa wa atomiki, na kumalizika kabla ya muamala mwingine wowote kutekelezwa.
- Ikiwa simu halali kwa
initializeitashindwa daima inawezekana kupuuza wakala na daraja jipya lililoundwa na kuunda mpya.
1 messenger = _l1messenger;2 l2TokenBridge = _l2TokenBridge;3 }Hivi ni vigezo viwili ambavyo daraja linahitaji kujua.
12 /**************3 * Uwekaji *4 **************/56 /** @dev Kirekebishaji kinachohitaji mtumaji awe EOA. Ukaguzi huu unaweza kuepukwa na mkataba hasidi7 * kupitia initcode, lakini inashughulikia kosa la mtumiaji tunalotaka kuepuka.8 */9 modifier onlyEOA() {10 // Inatumika kusimamisha uwekaji kutoka kwa mikataba (epuka tokeni zilizopotea kwa bahati mbaya)11 require(!Address.isContract(msg.sender), "Akaunti si EOA");12 _;13 }Onyesha yoteHii ndiyo sababu tulihitaji huduma za Anwani za OpenZeppelin.
1 /**2 * @dev Kazi hii inaweza kuitwa bila data3 * kuweka kiasi cha ETH kwenye salio la mpigaji simu kwenye L2.4 * Kwa kuwa kazi ya kupokea haichukui data, kiasi5 * chaguo-msingi cha kihafidhina hupelekwa L2.6 */7 receive() external payable onlyEOA {8 _initiateETHDeposit(msg.sender, msg.sender, 200_000, bytes(""));9 }Onyesha yoteKazi hii ipo kwa madhumuni ya majaribio. Kumbuka kuwa haionekani katika ufafanuzi wa kiolesura - si kwa matumizi ya kawaida.
1 /**2 * @inheritdoc IL1StandardBridge3 */4 function depositETH(uint32 _l2Gas, bytes calldata _data) external payable onlyEOA {5 _initiateETHDeposit(msg.sender, msg.sender, _l2Gas, _data);6 }78 /**9 * @inheritdoc IL1StandardBridge10 */11 function depositETHTo(12 anwani _to,13 uint32 _l2Gas,14 bytes calldata _data15 ) external payable {16 _initiateETHDeposit(msg.sender, _to, _l2Gas, _data);17 }Onyesha yoteKazi hizi mbili ni vifuniko vinavyozunguka _initiateETHDeposit, kazi inayoshughulikia uwekaji halisi wa ETH.
1 /**2 * @dev Hufanya mantiki ya uwekaji kwa kuhifadhi ETH na kumjulisha Lango la ETH la L2 kuhusu3 * uwekaji.4 * @param _from Akaunti ya kuchukua uwekaji kutoka L1.5 * @param _to Akaunti ya kumpa uwekaji kwenye L2.6 * @param _l2Gas Kikomo cha gesi kinachohitajika kukamilisha uwekaji kwenye L2.7 * @param _data Data ya hiari ya kupeleka kwa L2. Data hii hutolewa8 * kama urahisi tu kwa mikataba ya nje. Mbali na kutekeleza urefu wa juu,9 * mikataba hii haitoi dhamana yoyote kuhusu maudhui yake.10 */11 function _initiateETHDeposit(12 anwani _from,13 anwani _to,14 uint32 _l2Gas,15 bytes memory _data16 ) internal {17 // Jenga calldata kwa simu ya finalizeDeposit18 bytes memory message = abi.encodeWithSelector(Onyesha yoteNjia ambayo ujumbe wa vikoa tofauti hufanya kazi ni kwamba mkataba lengwa unaitwa na ujumbe kama calldata yake.
Mikataba ya Solidity daima hutafsiri calldata zao kulingana na
vipimo vya ABIopens in a new tab.
Kazi ya Solidity abi.encodeWithSelectoropens in a new tab huunda calldata hiyo.
1 IL2ERC20Bridge.finalizeDeposit.selector,2 anwani(0),3 Lib_PredeployAddresses.OVM_ETH,4 _from,5 _to,6 msg.value,7 _data8 );Ujumbe hapa ni kupiga simu kazi ya finalizeDepositopens in a new tab na vigezo hivi:
| Kigezo | Thamani | Maana |
|---|---|---|
| _l1Token | anwani(0) | Thamani maalum ya kuwakilisha ETH (ambayo si tokeni ya ERC-20) kwenye L1 |
| _l2Token | Lib_PredeployAddresses.OVM_ETH | Mkataba wa L2 unaosimamia ETH kwenye Optimism, 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000 (mkataba huu ni kwa matumizi ya ndani ya Optimism pekee) |
| _kutoka | _kutoka | Anwani kwenye L1 inayotuma ETH |
| _kwa | _kwa | Anwani kwenye L2 inayopokea ETH |
| kiasi | msg.value | Kiasi cha wei kilichotumwa (ambacho tayari kimetumwa kwenye daraja) |
| _data | _data | Data ya ziada ya kuambatisha kwenye uwekaji |
1 // Tuma calldata kwenye L22 // slither-disable-next-line reentrancy-events3 sendCrossDomainMessage(l2TokenBridge, _l2Gas, ujumbe);Tuma ujumbe kupitia mtumaji ujumbe wa vikoa tofauti.
1 // slither-disable-next-line reentrancy-events2 emit ETHDepositInitiated(_from, _to, msg.value, _data);3 }Toa tukio la kujulisha programu yoyote iliyogatuliwa inayosikiliza kuhusu uhamisho huu.
1 /**2 * @inheritdoc IL1ERC20Bridge3 */4 function depositERC20(5 .6 .7 .8 ) external virtual onlyEOA {9 _initiateERC20Deposit(_l1Token, _l2Token, msg.sender, msg.sender, _amount, _l2Gas, _data);10 }1112 /**13 * @inheritdoc IL1ERC20Bridge14 */15 function depositERC20To(16 .17 .18 .19 ) external virtual {20 _initiateERC20Deposit(_l1Token, _l2Token, msg.sender, _to, _amount, _l2Gas, _data);21 }Onyesha yoteKazi hizi mbili ni vifuniko vinavyozunguka _initiateERC20Deposit, kazi inayoshughulikia uwekaji halisi wa ERC-20.
1 /**2 * @dev Hufanya mantiki ya uwekaji kwa kumjulisha mkataba wa Tokeni Iliyowekwa ya L23 * kuhusu uwekaji na kuita mshughulikiaji kufunga fedha za L1. (k.m., transferFrom)4 *5 * @param _l1Token Anwani ya ERC20 ya L1 tunayoweka6 * @param _l2Token Anwani ya ERC20 ya L2 inayolingana na L17 * @param _from Akaunti ya kuchukua uwekaji kutoka L18 * @param _to Akaunti ya kumpa uwekaji kwenye L29 * @param _amount Kiasi cha ERC20 cha kuweka.10 * @param _l2Gas Kikomo cha gesi kinachohitajika kukamilisha uwekaji kwenye L2.11 * @param _data Data ya hiari ya kupeleka kwa L2. Data hii hutolewa12 * kama urahisi tu kwa mikataba ya nje. Mbali na kutekeleza urefu wa juu,13 * mikataba hii haitoi dhamana yoyote kuhusu maudhui yake.14 */15 function _initiateERC20Deposit(16 anwani _l1Token,17 anwani _l2Token,18 anwani _from,19 anwani _to,20 uint256 _amount,21 uint32 _l2Gas,22 bytes calldata _data23 ) internal {Onyesha yoteKazi hii inafanana na _initiateETHDeposit hapo juu, na tofauti chache muhimu.
Tofauti ya kwanza ni kwamba kazi hii inapokea anwani za tokeni na kiasi cha kuhamisha kama vigezo.
Kwa upande wa ETH simu kwa daraja tayari inajumuisha uhamisho wa rasilimali kwenda akaunti ya daraja (msg.value).
1 // Uwekaji unapoanzishwa kwenye L1, Daraja la L1 huhamisha fedha kwake lenyewe kwa ajili ya2 // utoaji wa siku zijazo. safeTransferFrom pia huangalia ikiwa mkataba una msimbo, kwa hivyo hii itashindwa ikiwa3 // _from ni EOA au anwani(0).4 // slither-disable-next-line reentrancy-events, reentrancy-benign5 IERC20(_l1Token).safeTransferFrom(_from, address(this), _amount);Uhamisho wa tokeni za ERC-20 hufuata mchakato tofauti na ETH:
- Mtumiaji (
_from) anatoa ruhusa kwa daraja kuhamisha tokeni zinazofaa. - Mtumiaji anapiga simu daraja na anwani ya mkataba wa tokeni, kiasi, n.k.
- Daraja linahamisha tokeni (kwake lenyewe) kama sehemu ya mchakato wa uwekaji.
Hatua ya kwanza inaweza kutokea katika muamala tofauti na mbili za mwisho.
Hata hivyo, uendeshaji-wa-mbele si tatizo kwa sababu kazi mbili zinazoita _initiateERC20Deposit (depositERC20 na depositERC20To) huita kazi hii tu na msg.sender kama kigezo cha _from.
1 // Jenga calldata kwa _l2Token.finalizeDeposit(_to, _amount)2 bytes memory message = abi.encodeWithSelector(3 IL2ERC20Bridge.finalizeDeposit.selector,4 _l1Token,5 _l2Token,6 _from,7 _to,8 _amount,9 _data10 );1112 // Tuma calldata kwenye L213 // slither-disable-next-line reentrancy-events, reentrancy-benign14 sendCrossDomainMessage(l2TokenBridge, _l2Gas, ujumbe);1516 // slither-disable-next-line reentrancy-benign17 deposits[_l1Token][_l2Token] = deposits[_l1Token][_l2Token] + _amount;Onyesha yoteOngeza kiasi cha tokeni zilizowekwa kwenye muundo wa data wa deposits.
Kunaweza kuwa na anwani nyingi kwenye L2 zinazolingana na tokeni ileile ya L1 ERC-20, kwa hivyo haitoshi kutumia salio la daraja la tokeni ya L1 ERC-20 kufuatilia uwekaji.
12 // slither-disable-next-line reentrancy-events3 emit ERC20DepositInitiated(_l1Token, _l2Token, _from, _to, _amount, _data);4 }56 /*************************7 * Kazi za Mnyororo-Msalaba *8 *************************/910 /**11 * @inheritdoc IL1StandardBridge12 */13 function finalizeETHWithdrawal(14 anwani _from,15 anwani _to,16 uint256 _amount,17 bytes calldata _dataOnyesha yoteDaraja la L2 hutuma ujumbe kwa mtumaji ujumbe wa vikoa tofauti wa L2 ambao husababisha mtumaji ujumbe wa vikoa tofauti wa L1 kupiga simu kazi hii (mara tu muamala unaokamilisha ujumbeopens in a new tab utakapowasilishwa kwenye L1, bila shaka).
1 ) external onlyFromCrossDomainAccount(l2TokenBridge) {Hakikisha kuwa huu ni ujumbe halali, unaotoka kwa mtumaji ujumbe wa vikoa tofauti na unaotokana na daraja la tokeni la L2. Kazi hii inatumika kutoa ETH kutoka kwa daraja, kwa hivyo tunapaswa kuhakikisha inaitwa tu na mpigaji simu aliyeidhinishwa.
1 // slither-disable-next-line reentrancy-events2 (bool success, ) = _to.call{ value: _amount }(new bytes(0));Njia ya kuhamisha ETH ni kumpigia simu mpokeaji na kiasi cha wei katika msg.value.
1 require(success, "TransferHelper::safeTransferETH: Uhamisho wa ETH umeshindwa");23 // slither-disable-next-line reentrancy-events4 emit ETHWithdrawalFinalized(_from, _to, _amount, _data);Toa tukio kuhusu utoaji.
1 }23 /**4 * @inheritdoc IL1ERC20Bridge5 */6 function finalizeERC20Withdrawal(7 anwani _l1Token,8 anwani _l2Token,9 anwani _from,10 anwani _to,11 uint256 _amount,12 bytes calldata _data13 ) external onlyFromCrossDomainAccount(l2TokenBridge) {Onyesha yoteKazi hii inafanana na finalizeETHWithdrawal hapo juu, na mabadiliko muhimu kwa tokeni za ERC-20.
1 deposits[_l1Token][_l2Token] = deposits[_l1Token][_l2Token] - _amount;Sasisha muundo wa data wa deposits.
1 // Utoaji unapokamilishwa kwenye L1, Daraja la L1 huhamisha fedha kwa mtoaji2 // slither-disable-next-line reentrancy-events3 IERC20(_l1Token).safeTransfer(_to, _amount);45 // slither-disable-next-line reentrancy-events6 emit ERC20WithdrawalFinalized(_l1Token, _l2Token, _from, _to, _amount, _data);7 }8910 /*****************************11 * Ya muda - Kuhamisha ETH *12 *****************************/1314 /**15 * @dev Huongeza salio la ETH kwenye akaunti. Hii inakusudiwa kuruhusu ETH16 * kuhamishwa kutoka lango la zamani hadi lango jipya.17 * KUMBUKA: Hii imeachwa kwa sasisho moja tu ili tuweze kupokea ETH iliyohamishwa kutoka18 * mkataba wa zamani19 */20 function donateETH() external payable {}21}Onyesha yoteKulikuwa na utekelezaji wa awali wa daraja.
Tulipohamia kutoka kwa utekelezaji huo hadi huu, tulilazimika kuhamisha rasilimali zote.
Tokeni za ERC-20 zinaweza tu kuhamishwa.
Hata hivyo, ili kuhamisha ETH kwa mkataba unahitaji idhini ya mkataba huo, ambayo ndiyo donateETH inatupatia.
Tokeni za ERC-20 kwenye L2
Ili tokeni ya ERC-20 iingie kwenye daraja la kawaida, inahitaji kuruhusu daraja la kawaida, na tu daraja la kawaida, kutoa tokeni. Hii ni muhimu kwa sababu madaraja yanahitaji kuhakikisha kuwa idadi ya tokeni zinazozunguka kwenye Optimism ni sawa na idadi ya tokeni zilizofungwa ndani ya mkataba wa daraja la L1. Ikiwa kuna tokeni nyingi sana kwenye L2 baadhi ya watumiaji wasingeweza kuvusha rasilimali zao kwa daraja kurudi L1. Badala ya daraja linaloaminika, kimsingi tungeunda upya benki ya hifadhi ya sehemuopens in a new tab. Ikiwa kuna tokeni nyingi sana kwenye L1, baadhi ya tokeni hizo zingebaki zimefungwa ndani ya mkataba wa daraja milele kwa sababu hakuna njia ya kuzitoa bila kuchoma tokeni za L2.
IL2StandardERC20
Kila tokeni ya ERC-20 kwenye L2 inayotumia daraja la kawaida inahitaji kutoa kiolesura hikiopens in a new tab, ambacho kina kazi na matukio ambayo daraja la kawaida linahitaji.
1// SPDX-License-Identifier: MIT2pragma solidity ^0.8.9;34import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";Kiolesura cha kawaida cha ERC-20opens in a new tab hakijumuishi kazi za mint na burn.
Njia hizo hazihitajiki na kiwango cha ERC-20opens in a new tab, ambacho kinaacha taratibu za kuunda na kuharibu tokeni bila kubainishwa.
1import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";Kiolesura cha ERC-165opens in a new tab kinatumika kubainisha kazi ambazo mkataba unatoa. Unaweza kusoma kiwango hapaopens in a new tab.
1interface IL2StandardERC20 is IERC20, IERC165 {2 function l1Token() external returns (anwani);Kazi hii inatoa anwani ya tokeni ya L1 ambayo imevushwa kwa daraja kwenda mkataba huu. Kumbuka kuwa hatuna kazi kama hiyo kwa upande mwingine. Tunahitaji kuweza kuvusha kwa daraja tokeni yoyote ya L1, bila kujali kama msaada wa L2 ulipangwa wakati ilitekelezwa au la.
12 function mint(anwani _to, uint256 _amount) external;34 function burn(anwani _from, uint256 _amount) external;56 event Mint(anwani iliyoorodheshwa _account, uint256 _amount);7 event Burn(anwani iliyoorodheshwa _account, uint256 _amount);8}Kazi na matukio ya kutoa (kuunda) na kuchoma (kuharibu) tokeni. Daraja linapaswa kuwa chombo pekee kinachoweza kuendesha kazi hizi ili kuhakikisha idadi ya tokeni ni sahihi (sawa na idadi ya tokeni zilizofungwa kwenye L1).
L2StandardERC20
Huu ndio utekelezaji wetu wa kiolesura cha IL2StandardERC20opens in a new tab.
Isipokuwa unahitaji aina fulani ya mantiki maalum, unapaswa kutumia hii.
1// SPDX-License-Identifier: MIT2pragma solidity ^0.8.9;34import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";Mkataba wa OpenZeppelin ERC-20opens in a new tab. Optimism haiamini katika kuunda upya gurudumu, hasa wakati gurudumu limekaguliwa vizuri na linahitaji kuwa la kuaminika vya kutosha kushikilia rasilimali.
1import "./IL2StandardERC20.sol";23contract L2StandardERC20 is IL2StandardERC20, ERC20 {4 anwani public l1Token;5 anwani public l2Bridge;Hivi ni vigezo viwili vya ziada vya usanidi ambavyo tunahitaji na ERC-20 kawaida haihitaji.
12 /**3 * @param _l2Bridge Anwani ya daraja la kawaida la L2.4 * @param _l1Token Anwani ya tokeni ya L1 inayolingana.5 * @param _name jina la ERC20.6 * @param _symbol alama ya ERC20.7 */8 constructor(9 anwani _l2Bridge,10 anwani _l1Token,11 string memory _name,12 string memory _symbol13 ) ERC20(_name, _symbol) {14 l1Token = _l1Token;15 l2Bridge = _l2Bridge;16 }Onyesha yoteKwanza piga simu kijenzi cha mkataba tunachorithi kutoka (ERC20(_name, _symbol)) na kisha weka vigezo vyetu wenyewe.
12 modifier onlyL2Bridge() {3 require(msg.sender == l2Bridge, "Ni Daraja la L2 pekee linaweza kutoa na kuchoma");4 _;5 }678 // slither-disable-next-line external-function9 function supportsInterface(bytes4 _interfaceId) public pure returns (bool) {10 bytes4 firstSupportedInterface = bytes4(keccak256("supportsInterface(bytes4)")); // ERC16511 bytes4 secondSupportedInterface = IL2StandardERC20.l1Token.selector ^12 IL2StandardERC20.mint.selector ^13 IL2StandardERC20.burn.selector;14 return _interfaceId == firstSupportedInterface || _interfaceId == secondSupportedInterface;15 }Onyesha yoteHivi ndivyo ERC-165opens in a new tab inavyofanya kazi. Kila kiolesura ni idadi ya kazi zinazoungwa mkono, na kinatambuliwa kama au ya kipekeeopens in a new tab ya viteuzi vya kazi vya ABIopens in a new tab vya kazi hizo.
Daraja la L2 linatumia ERC-165 kama ukaguzi wa usalama kuhakikisha kuwa mkataba wa ERC-20 ambao linatuma rasilimali ni IL2StandardERC20.
Kumbuka: Hakuna kinachozuia mkataba hasidi kutoa majibu ya uwongo kwa supportsInterface, kwa hivyo huu ni utaratibu wa ukaguzi wa usalama, sio utaratibu wa usalama.
1 // slither-disable-next-line external-function2 function mint(anwani _to, uint256 _amount) public virtual onlyL2Bridge {3 _mint(_to, _amount);45 emit Mint(_to, _amount);6 }78 // slither-disable-next-line external-function9 function burn(anwani _from, uint256 _amount) public virtual onlyL2Bridge {10 _burn(_from, _amount);1112 emit Burn(_from, _amount);13 }14}Onyesha yoteNi daraja la L2 pekee linaloruhusiwa kutoa na kuchoma rasilimali.
_mint na _burn kwa kweli zimefafanuliwa katika mkataba wa OpenZeppelin ERC-20.
Mkataba huo hauwaweki wazi nje, kwa sababu masharti ya kutoa na kuchoma tokeni ni tofauti kama idadi ya njia za kutumia ERC-20.
Msimbo wa Daraja la L2
Huu ni msimbo unaoendesha daraja kwenye Optimism. Chanzo cha mkataba huu kiko hapaopens in a new tab.
1// SPDX-License-Identifier: MIT2pragma solidity ^0.8.9;34/* Interface Imports */5import { IL1StandardBridge } from "../../L1/messaging/IL1StandardBridge.sol";6import { IL1ERC20Bridge } from "../../L1/messaging/IL1ERC20Bridge.sol";7import { IL2ERC20Bridge } from "./IL2ERC20Bridge.sol";Kiolesura cha IL2ERC20Bridgeopens in a new tab kinafanana sana na sawa ya L1 tuliyoona hapo juu. Kuna tofauti mbili muhimu:
- Kwenye L1 unaanzisha uwekaji na kukamilisha utoaji. Hapa unaanzisha utoaji na kukamilisha uwekaji.
- Kwenye L1 ni muhimu kutofautisha kati ya ETH na tokeni za ERC-20. Kwenye L2 tunaweza kutumia kazi zile zile kwa zote mbili kwa sababu ndani ya Optimism salio za ETH hushughulikiwa kama tokeni ya ERC-20 yenye anwani 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000opens in a new tab.
1/* Library Imports */2import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";3import { CrossDomainEnabled } from "../../libraries/bridge/CrossDomainEnabled.sol";4import { Lib_PredeployAddresses } from "../../libraries/constants/Lib_PredeployAddresses.sol";56/* Contract Imports */7import { IL2StandardERC20 } from "../../standards/IL2StandardERC20.sol";89/**10 * @title L2StandardBridge11 * @dev Daraja la Kawaida la L2 ni mkataba unaofanya kazi pamoja na daraja la Kawaida la L112 * kuwezesha mabadiliko ya ETH na ERC20 kati ya L1 na L2.13 * Mkataba huu hufanya kazi kama mtoaji wa tokeni mpya inaposikia kuhusu uwekaji kwenye daraja la Kawaida la L114 *.15 * Mkataba huu pia hufanya kazi kama mchomaji wa tokeni zilizokusudiwa kwa utoaji, ukijulisha daraja la L116 * kutoa fedha za L1.17 */18contract L2StandardBridge is IL2ERC20Bridge, CrossDomainEnabled {19 /********************************20 * Marejeleo ya Mkataba wa Nje *21 ********************************/2223 anwani public l1TokenBridge;Onyesha yoteFuatilia anwani ya daraja la L1. Kumbuka kuwa tofauti na sawa ya L1, hapa tunahitaji kigezo hiki. Anwani ya daraja la L1 haijulikani mapema.
12 /***************3 * Kijenzi *4 ***************/56 /**7 * @param _l2CrossDomainMessenger Mtumaji ujumbe wa vikoa tofauti unaotumiwa na mkataba huu.8 * @param _l1TokenBridge Anwani ya daraja la L1 iliyotumwa kwenye mnyororo mkuu.9 */10 constructor(anwani _l2CrossDomainMessenger, anwani _l1TokenBridge)11 CrossDomainEnabled(_l2CrossDomainMessenger)12 {13 l1TokenBridge = _l1TokenBridge;14 }1516 /***************17 * Utoaji *18 ***************/1920 /**21 * @inheritdoc IL2ERC20Bridge22 */23 function withdraw(24 anwani _l2Token,25 uint256 _amount,26 uint32 _l1Gas,27 bytes calldata _data28 ) external virtual {29 _initiateWithdrawal(_l2Token, msg.sender, msg.sender, _amount, _l1Gas, _data);30 }3132 /**33 * @inheritdoc IL2ERC20Bridge34 */35 function withdrawTo(36 anwani _l2Token,37 anwani _to,38 uint256 _amount,39 uint32 _l1Gas,40 bytes calldata _data41 ) external virtual {42 _initiateWithdrawal(_l2Token, msg.sender, _to, _amount, _l1Gas, _data);43 }Onyesha yoteKazi hizi mbili zinaanzisha utoaji. Kumbuka kuwa hakuna haja ya kubainisha anwani ya tokeni ya L1. Tokeni za L2 zinatarajiwa kutuambia anwani sawa ya L1.
12 /**3 * @dev Hufanya mantiki ya utoaji kwa kuchoma tokeni na kumjulisha4 * Lango la tokeni la L1 kuhusu utoaji.5 * @param _l2Token Anwani ya tokeni ya L2 ambapo utoaji unaanzishwa.6 * @param _from Akaunti ya kuchukua utoaji kutoka L2.7 * @param _to Akaunti ya kumpa utoaji kwenye L1.8 * @param _amount Kiasi cha tokeni ya kutoa.9 * @param _l1Gas Haijatumiwa, lakini imejumuishwa kwa mazingatio ya utangamano wa mbele.10 * @param _data Data ya hiari ya kupeleka kwa L1. Data hii hutolewa11 * kama urahisi tu kwa mikataba ya nje. Mbali na kutekeleza urefu wa juu,12 * mikataba hii haitoi dhamana yoyote kuhusu maudhui yake.13 */14 function _initiateWithdrawal(15 anwani _l2Token,16 anwani _from,17 anwani _to,18 uint256 _amount,19 uint32 _l1Gas,20 bytes calldata _data21 ) internal {22 // Utoaji unapoanzishwa, tunachoma fedha za mtoaji ili kuzuia matumizi ya L223 //.24 // slither-disable-next-line reentrancy-events25 IL2StandardERC20(_l2Token).burn(msg.sender, _amount);Onyesha yoteKumbuka kuwa hatutegemei kigezo cha _from bali msg.sender ambayo ni ngumu zaidi kughushi (haiwezekani, kwa kadiri ninavyojua).
12 // Jenga calldata kwa l1TokenBridge.finalizeERC20Withdrawal(_to, _amount)3 // slither-disable-next-line reentrancy-events4 anwani l1Token = IL2StandardERC20(_l2Token).l1Token();5 bytes memory message;67 if (_l2Token == Lib_PredeployAddresses.OVM_ETH) {Kwenye L1 ni muhimu kutofautisha kati ya ETH na ERC-20.
1 ujumbe = abi.encodeWithSelector(2 IL1StandardBridge.finalizeETHWithdrawal.selector,3 _from,4 _to,5 _amount,6 _data7 );8 } else {9 ujumbe = abi.encodeWithSelector(10 IL1ERC20Bridge.finalizeERC20Withdrawal.selector,11 l1Token,12 _l2Token,13 _from,14 _to,15 _amount,16 _data17 );18 }1920 // Tuma ujumbe hadi daraja la L121 // slither-disable-next-line reentrancy-events22 sendCrossDomainMessage(l1TokenBridge, _l1Gas, ujumbe);2324 // slither-disable-next-line reentrancy-events25 emit WithdrawalInitiated(l1Token, _l2Token, msg.sender, _to, _amount, _data);26 }2728 /************************************29 * Kazi ya Mnyororo-Msalaba: Uwekaji *30 ************************************/3132 /**33 * @inheritdoc IL2ERC20Bridge34 */35 function finalizeDeposit(36 anwani _l1Token,37 anwani _l2Token,38 anwani _from,39 anwani _to,40 uint256 _amount,41 bytes calldata _dataOnyesha yoteKazi hii inaitwa na L1StandardBridge.
1 ) external virtual onlyFromCrossDomainAccount(l1TokenBridge) {Hakikisha chanzo cha ujumbe ni halali.
Hii ni muhimu kwa sababu kazi hii huita _mint na inaweza kutumika kutoa tokeni ambazo hazifunikwa na tokeni ambazo daraja linamiliki kwenye L1.
1 // Angalia tokeni lengwa inatii na2 // hakikisha tokeni iliyowekwa kwenye L1 inalingana na uwakilishi wa tokeni iliyowekwa ya L2 hapa3 if (4 // slither-disable-next-line reentrancy-events5 ERC165Checker.supportsInterface(_l2Token, 0x1d1d8b63) &&6 _l1Token == IL2StandardERC20(_l2Token).l1Token()Ukaguzi wa usalama:
- Kiolesura sahihi kinaauniwa
- Anwani ya L1 ya mkataba wa L2 ERC-20 inalingana na chanzo cha L1 cha tokeni
1 ) {2 // Uwekaji unapokamilishwa, tunaweka kiasi sawa cha3 // tokeni kwenye akaunti kwenye L2.4 // slither-disable-next-line reentrancy-events5 IL2StandardERC20(_l2Token).mint(_to, _amount);6 // slither-disable-next-line reentrancy-events7 emit DepositFinalized(_l1Token, _l2Token, _from, _to, _amount, _data);Ikiwa ukaguzi wa usalama utapita, kamilisha uwekaji:
- Toa tokeni
- Toa tukio linalofaa
1 } else {2 // Labda tokeni ya L2 ambayo inawekwa-ndani haikubaliani kuhusu anwani sahihi3 // ya tokeni yake ya L1, au haiauni kiolesura sahihi.4 // Hii inapaswa kutokea tu ikiwa kuna tokeni hasidi ya L2, au ikiwa mtumiaji kwa namna fulani5 // alibainisha anwani isiyo sahihi ya tokeni ya L2 ya kuweka.6 // Katika hali yoyote, tunasimamisha mchakato hapa na kuunda ujumbe wa7 // utoaji ili watumiaji waweze kutoa fedha zao katika baadhi ya kesi.8 // Hakuna njia ya kuzuia mikataba ya tokeni hasidi kabisa, lakini hii inapunguza9 // kosa la mtumiaji na kupunguza baadhi ya aina za tabia ya mkataba hasidi.Onyesha yoteIkiwa mtumiaji alifanya kosa linaloweza kugunduliwa kwa kutumia anwani isiyo sahihi ya tokeni ya L2, tunataka kughairi uwekaji na kurudisha tokeni kwenye L1. Njia pekee tunayoweza kufanya hivi kutoka L2 ni kutuma ujumbe ambao utalazimika kusubiri kipindi cha changamoto ya makosa, lakini hiyo ni bora zaidi kwa mtumiaji kuliko kupoteza tokeni kabisa.
1 bytes memory message = abi.encodeWithSelector(2 IL1ERC20Bridge.finalizeERC20Withdrawal.selector,3 _l1Token,4 _l2Token,5 _to, // tulibadilisha _to na _from hapa kurudisha uwekaji kwa mtumaji6 _from,7 _amount,8 _data9 );1011 // Tuma ujumbe hadi daraja la L112 // slither-disable-next-line reentrancy-events13 sendCrossDomainMessage(l1TokenBridge, 0, ujumbe);14 // slither-disable-next-line reentrancy-events15 emit DepositFailed(_l1Token, _l2Token, _from, _to, _amount, _data);16 }17 }18}Onyesha yoteHitimisho
Daraja la kawaida ndio utaratibu unaobadilika zaidi kwa uhamisho wa rasilimali. Hata hivyo, kwa sababu ni ya jumla sana si rahisi kila wakati kutumia utaratibu huu. Hasa kwa utoaji, watumiaji wengi wanapendelea kutumia madaraja ya watu wengineopens in a new tab ambayo hayasubiri kipindi cha changamoto na hayahitaji uthibitisho wa Merkle kukamilisha utoaji.
Madaraja haya kwa kawaida hufanya kazi kwa kuwa na rasilimali kwenye L1, ambazo hutoa mara moja kwa ada ndogo (mara nyingi chini ya gharama ya gesi kwa utoaji wa daraja la kawaida). Wakati daraja (au watu wanaoliendesha) linapotarajia kupungukiwa na rasilimali za L1 linahamisha rasilimali za kutosha kutoka L2. Kwa kuwa haya ni utoaji mkubwa sana, gharama ya utoaji inapunguzwa kwa kiasi kikubwa na ni asilimia ndogo zaidi.
Tunatumai makala hii imekusaidia kuelewa zaidi kuhusu jinsi safu 2 inavyofanya kazi, na jinsi ya kuandika msimbo wa Solidity ulio wazi na salama.
Tazama hapa kwa kazi zangu zaidiopens in a new tab.
Ukurasa ulihaririwa mwisho: 22 Oktoba 2025