Optimism நிலையான பால ஒப்பந்தத்தின் (standard bridge contract) வழிகாட்டி
Optimism (opens in a new tab) என்பது ஒரு Optimistic Rollup ஆகும். நெட்வொர்க்கில் உள்ள ஒவ்வொரு நோடுக்கும் பதிலாக சில நோடுகளால் மட்டுமே பரிவர்த்தனைகள் செயலாக்கப்படுவதால், Ethereum Mainnet-ஐ (அடுக்கு 1 அல்லது L1 என்றும் அழைக்கப்படுகிறது) விட மிகக் குறைந்த விலையில் Optimistic rollup-களால் பரிவர்த்தனைகளைச் செயலாக்க முடியும். அதே நேரத்தில், தரவுகள் அனைத்தும் L1-ல் எழுதப்படுவதால், Mainnet-ன் அனைத்து ஒருமைப்பாடு மற்றும் கிடைக்கும் தன்மைக்கான உத்தரவாதங்களுடன் அனைத்தையும் நிரூபிக்கவும் மறுகட்டமைக்கவும் முடியும்.
Optimism-ல் (அல்லது வேறு ஏதேனும் L2-ல்) L1 சொத்துகளைப் பயன்படுத்த, சொத்துகள் பாலம் (bridged) செய்யப்பட வேண்டும். இதை அடைவதற்கான ஒரு வழி, பயனர்கள் L1-ல் சொத்துகளை (ETH மற்றும் ERC-20 டோக்கன்கள் மிகவும் பொதுவானவை) லாக் செய்து, L2-ல் பயன்படுத்த சமமான சொத்துகளைப் பெறுவதாகும். இறுதியில், அவற்றை வைத்திருப்பவர்கள் அவற்றை மீண்டும் L1-க்கு பாலம் செய்ய விரும்பலாம். இதைச் செய்யும்போது, சொத்துகள் L2-ல் எரிக்கப்பட்டு (burned), பின்னர் L1-ல் பயனருக்கு மீண்டும் வெளியிடப்படும்.
Optimism நிலையான பாலம் (standard bridge) (opens in a new tab) இவ்வாறுதான் செயல்படுகிறது. இந்தக் கட்டுரையில், அந்தப் பாலம் எவ்வாறு செயல்படுகிறது என்பதைப் பார்க்க அதன் மூலக் குறியீட்டை (source code) மதிப்பாய்வு செய்கிறோம், மேலும் நன்கு எழுதப்பட்ட Solidity குறியீட்டிற்கு ஒரு உதாரணமாக அதைப் படிக்கிறோம்.
கட்டுப்பாட்டு ஓட்டங்கள் (Control flows)
பாலம் இரண்டு முக்கிய ஓட்டங்களைக் கொண்டுள்ளது:
- டெபாசிட் (L1-லிருந்து L2-க்கு)
- திரும்பப் பெறுதல் (L2-லிருந்து L1-க்கு)
டெபாசிட் ஓட்டம்
அடுக்கு 1
- ERC-20-ஐ டெபாசிட் செய்தால், டெபாசிட் செய்பவர் டெபாசிட் செய்யப்படும் தொகையைச் செலவிட பாலத்திற்கு ஒரு அனுமதியை (allowance) வழங்குகிறார்
- டெபாசிட் செய்பவர் L1 பாலத்தை அழைக்கிறார் (
depositERC20,depositERC20To,depositETH, அல்லதுdepositETHTo) - L1 பாலம் பாலம் செய்யப்பட்ட சொத்தை தன் வசம் எடுத்துக்கொள்கிறது
- ETH: அழைப்பின் ஒரு பகுதியாக டெபாசிட் செய்பவரால் சொத்து மாற்றப்படுகிறது
- ERC-20: டெபாசிட் செய்பவர் வழங்கிய அனுமதியைப் பயன்படுத்தி பாலம் தனக்குத்தானே சொத்தை மாற்றிக்கொள்கிறது
- L1 பாலம் L2 பாலத்தில்
finalizeDeposit-ஐ அழைக்க குறுக்கு-டொமைன் (cross-domain) செய்தி பொறிமுறையைப் பயன்படுத்துகிறது
அடுக்கு 2
finalizeDeposit-க்கான அழைப்பு சட்டபூர்வமானதா என்பதை L2 பாலம் சரிபார்க்கிறது:- குறுக்கு டொமைன் செய்தி ஒப்பந்தத்திலிருந்து வந்ததா
- முதலில் L1-ல் உள்ள பாலத்திலிருந்து வந்ததா
- L2-ல் உள்ள ERC-20 டோக்கன் ஒப்பந்தம் சரியானதா என்பதை L2 பாலம் சரிபார்க்கிறது:
- L2 ஒப்பந்தம் அதன் L1 இணையானது L1-ல் டோக்கன்கள் வந்த அதே ஒப்பந்தம் தான் என்று தெரிவிக்கிறது
- L2 ஒப்பந்தம் சரியான இடைமுகத்தை ஆதரிக்கிறது என்று தெரிவிக்கிறது (ERC-165-ஐப் பயன்படுத்தி (opens in a new tab)).
- L2 ஒப்பந்தம் சரியானதாக இருந்தால், பொருத்தமான முகவரிக்கு பொருத்தமான எண்ணிக்கையிலான டோக்கன்களை உருவாக்க (mint) அதை அழைக்கவும். இல்லையெனில், L1-ல் டோக்கன்களைப் பெற பயனரை அனுமதிக்க திரும்பப் பெறும் செயல்முறையைத் தொடங்கவும்.
திரும்பப் பெறும் ஓட்டம்
அடுக்கு 2
- திரும்பப் பெறுபவர் L2 பாலத்தை அழைக்கிறார் (
withdrawஅல்லதுwithdrawTo) - L2 பாலம்
msg.sender-க்கு சொந்தமான பொருத்தமான எண்ணிக்கையிலான டோக்கன்களை எரிக்கிறது - L2 பாலம் L1 பாலத்தில்
finalizeETHWithdrawalஅல்லதுfinalizeERC20Withdrawal-ஐ அழைக்க குறுக்கு-டொமைன் செய்தி பொறிமுறையைப் பயன்படுத்துகிறது
அடுக்கு 1
finalizeETHWithdrawalஅல்லதுfinalizeERC20Withdrawal-க்கான அழைப்பு சட்டபூர்வமானதா என்பதை L1 பாலம் சரிபார்க்கிறது:- குறுக்கு டொமைன் செய்தி பொறிமுறையிலிருந்து வந்ததா
- முதலில் L2-ல் உள்ள பாலத்திலிருந்து வந்ததா
- L1 பாலம் பொருத்தமான சொத்தை (ETH அல்லது ERC-20) பொருத்தமான முகவரிக்கு மாற்றுகிறது
அடுக்கு 1 குறியீடு
இது L1-ல், அதாவது Ethereum Mainnet-ல் இயங்கும் குறியீடாகும்.
IL1ERC20Bridge
இந்த இடைமுகம் இங்கே வரையறுக்கப்பட்டுள்ளது (opens in a new tab). இது ERC-20 டோக்கன்களைப் பாலம் செய்வதற்குத் தேவையான செயல்பாடுகள் மற்றும் வரையறைகளை உள்ளடக்கியது.
1// SPDX-License-Identifier: MITOptimism-ன் பெரும்பாலான குறியீடுகள் MIT உரிமத்தின் கீழ் வெளியிடப்படுகின்றன (opens in a new tab).
1pragma solidity >0.5.0 <0.9.0;இதை எழுதும் போது Solidity-ன் சமீபத்திய பதிப்பு 0.8.12 ஆகும். பதிப்பு 0.9.0 வெளியிடப்படும் வரை, இந்தக் குறியீடு அதனுடன் இணக்கமாக உள்ளதா இல்லையா என்பது எங்களுக்குத் தெரியாது.
1/* *2 * @title IL1ERC20Bridge */3interface IL1ERC20Bridge {4 /* *********5 * நிகழ்வுகள் *6 ********* */78 event ERC20DepositInitiated(Optimism பாலம் சொற்களஞ்சியத்தில் டெபாசிட் என்பது L1-லிருந்து L2-க்கு மாற்றுவதைக் குறிக்கிறது, மேலும் திரும்பப் பெறுதல் என்பது L2-லிருந்து L1-க்கு மாற்றுவதைக் குறிக்கிறது.
1 address indexed _l1Token,2 address indexed _l2Token,பெரும்பாலான சந்தர்ப்பங்களில் L1-ல் உள்ள ERC-20-ன் முகவரியும் L2-ல் உள்ள சமமான ERC-20-ன் முகவரியும் ஒன்றாக இருக்காது.
டோக்கன் முகவரிகளின் பட்டியலை நீங்கள் இங்கே பார்க்கலாம் (opens in a new tab).
chainId 1 கொண்ட முகவரி L1-ல் (Mainnet) உள்ளது மற்றும் chainId 10 கொண்ட முகவரி L2-ல் (Optimism) உள்ளது.
மற்ற இரண்டு chainId மதிப்புகள் Kovan சோதனை நெட்வொர்க் (42) மற்றும் Optimistic Kovan சோதனை நெட்வொர்க் (69) ஆகியவற்றுக்கானவை.
1 address indexed _from,2 address _to,3 uint256 _amount,4 bytes _data5 );பரிமாற்றங்களில் குறிப்புகளைச் சேர்க்க முடியும், அவ்வாறான நிலையில் அவை அவற்றைப் புகாரளிக்கும் நிகழ்வுகளில் சேர்க்கப்படும்.
1 event ERC20WithdrawalFinalized(2 address indexed _l1Token,3 address indexed _l2Token,4 address indexed _from,5 address _to,6 uint256 _amount,7 bytes _data8 );அதே பால ஒப்பந்தம் இரு திசைகளிலும் பரிமாற்றங்களைக் கையாளுகிறது. L1 பாலத்தைப் பொறுத்தவரை, இது டெபாசிட்களைத் தொடங்குவது மற்றும் திரும்பப் பெறுதல்களை முடிப்பது என்பதாகும்.
12 /* *******************3 * பொதுவான செயல்பாடுகள் *4 ******************* */56 /* *7 * @dev தொடர்புடைய L2 பிரிட்ஜ் ஒப்பந்தத்தின் முகவரியைப் பெறுகிறது.8 * @return தொடர்புடைய L2 பிரிட்ஜ் ஒப்பந்தத்தின் முகவரி. */9 function l2TokenBridge() external returns (address);அனைத்தையும் காட்டுஇந்தச் செயல்பாடு உண்மையில் தேவையில்லை, ஏனெனில் L2-ல் இது முன்பே பயன்படுத்தப்பட்ட ஒப்பந்தமாகும், எனவே இது எப்போதும் 0x4200000000000000000000000000000000000010 என்ற முகவரியில் இருக்கும்.
L1 பாலத்தின் முகவரியை அறிவது எளிதானது அல்ல என்பதால், L2 பாலத்துடனான சமச்சீர்மைக்காக இது இங்கே உள்ளது.
1 /* *2 * @dev அழைப்பாளரின் L2 இருப்பில் குறிப்பிட்ட அளவு ERC20-ஐ டெபாசிட் செய்கிறது.3 * @param _l1Token நாம் டெபாசிட் செய்யும் L1 ERC20-இன் முகவரி4 * @param _l2Token L1-க்கு தொடர்புடைய L2 ERC20-இன் முகவரி5 * @param _amount டெபாசிட் செய்ய வேண்டிய ERC20-இன் அளவு6 * @param _l2Gas L2-இல் டெபாசிட்டை முடிக்கத் தேவையான கேஸ் வரம்பு (Gas limit).7 * @param _data L2-க்கு அனுப்ப வேண்டிய விருப்பத் தரவு. இந்தத் தரவு வெளிப்புற ஒப்பந்தங்களின் வசதிக்காக மட்டுமே வழங்கப்படுகிறது. அதிகபட்ச நீளத்தை செயல்படுத்துவதைத் தவிர, இந்த ஒப்பந்தங்கள் அதன் உள்ளடக்கத்தைப் பற்றி எந்த உத்தரவாதத்தையும் வழங்காது. */8 function depositERC20(9 address _l1Token,10 address _l2Token,11 uint256 _amount,12 uint32 _l2Gas,13 bytes calldata _data14 ) external;அனைத்தையும் காட்டு_l2Gas அளவுரு என்பது பரிவர்த்தனை செலவிட அனுமதிக்கப்படும் L2 கேஸ் அளவாகும்.
ஒரு குறிப்பிட்ட (உயர்) வரம்பு வரை, இது இலவசம் (opens in a new tab), எனவே ERC-20 ஒப்பந்தம் உருவாக்கும் போது (minting) மிகவும் விசித்திரமான ஒன்றைச் செய்யாவிட்டால், இது ஒரு பிரச்சினையாக இருக்கக்கூடாது.
ஒரு பயனர் வேறு பிளாக்செயினில் உள்ள அதே முகவரிக்கு சொத்துகளைப் பாலம் செய்யும் பொதுவான சூழ்நிலையை இந்தச் செயல்பாடு கவனித்துக்கொள்கிறது.
1 /* *2 * @dev பெறுநரின் L2 இருப்பில் குறிப்பிட்ட அளவு ERC20-ஐ டெபாசிட் செய்கிறது.3 * @param _l1Token நாம் டெபாசிட் செய்யும் L1 ERC20-இன் முகவரி4 * @param _l2Token L1-க்கு தொடர்புடைய L2 ERC20-இன் முகவரி5 * @param _to திரும்பப் பெறுதலை வரவு வைக்க வேண்டிய L2 முகவரி.6 * @param _amount டெபாசிட் செய்ய வேண்டிய ERC20-இன் அளவு.7 * @param _l2Gas L2-இல் டெபாசிட்டை முடிக்கத் தேவையான கேஸ் வரம்பு.8 * @param _data L2-க்கு அனுப்ப வேண்டிய விருப்பத் தரவு. இந்தத் தரவு வெளிப்புற ஒப்பந்தங்களின் வசதிக்காக மட்டுமே வழங்கப்படுகிறது. அதிகபட்ச நீளத்தை செயல்படுத்துவதைத் தவிர, இந்த ஒப்பந்தங்கள் அதன் உள்ளடக்கத்தைப் பற்றி எந்த உத்தரவாதத்தையும் வழங்காது. */9 function depositERC20To(10 address _l1Token,11 address _l2Token,12 address _to,13 uint256 _amount,14 uint32 _l2Gas,15 bytes calldata _data16 ) external;அனைத்தையும் காட்டுஇந்தச் செயல்பாடு depositERC20-ஐப் போலவே இருக்கும், ஆனால் இது ERC-20-ஐ வேறு முகவரிக்கு அனுப்ப உங்களை அனுமதிக்கிறது.
1 /* ************************2 * கிராஸ்-செயின் செயல்பாடுகள் *3 ************************ */45 /* *6 * @dev L2-இலிருந்து L1-க்கு திரும்பப் பெறுதலை (withdrawal) முடித்து, பெறுநரின் L1 ERC20 டோக்கன் இருப்பில் நிதியை வரவு வைக்கிறது.7 * L2-இல் தொடங்கப்பட்ட திரும்பப் பெறுதல் இறுதி செய்யப்படாவிட்டால் இந்த அழைப்பு தோல்வியடையும்.8 *9 * @param _l1Token திரும்பப் பெறுதலை இறுதி செய்வதற்கான L1 டோக்கனின் முகவரி.10 * @param _l2Token திரும்பப் பெறுதல் தொடங்கப்பட்ட L2 டோக்கனின் முகவரி.11 * @param _from பரிமாற்றத்தைத் தொடங்கும் L2 முகவரி.12 * @param _to திரும்பப் பெறுதலை வரவு வைக்க வேண்டிய L1 முகவரி.13 * @param _amount டெபாசிட் செய்ய வேண்டிய ERC20-இன் அளவு.14 * @param _data L2-இல் அனுப்புநரால் வழங்கப்பட்ட தரவு. இந்தத் தரவு வெளிப்புற ஒப்பந்தங்களின் வசதிக்காக மட்டுமே வழங்கப்படுகிறது. அதிகபட்ச நீளத்தை செயல்படுத்துவதைத் தவிர, இந்த ஒப்பந்தங்கள் அதன் உள்ளடக்கத்தைப் பற்றி எந்த உத்தரவாதத்தையும் வழங்காது. */15 function finalizeERC20Withdrawal(16 address _l1Token,17 address _l2Token,18 address _from,19 address _to,20 uint256 _amount,21 bytes calldata _data22 ) external;23}அனைத்தையும் காட்டுOptimism-ல் திரும்பப் பெறுதல்கள் (மற்றும் L2-லிருந்து L1-க்கு வரும் பிற செய்திகள்) இரண்டு படி செயல்முறையாகும்:
- L2-ல் ஒரு தொடக்கப் பரிவர்த்தனை.
- L1-ல் ஒரு இறுதி அல்லது கோரும் பரிவர்த்தனை. L2 பரிவர்த்தனைக்கான தவறு சவால் காலம் (fault challenge period) (opens in a new tab) முடிவடைந்த பிறகு இந்தப் பரிவர்த்தனை நடக்க வேண்டும்.
IL1StandardBridge
இந்த இடைமுகம் இங்கே வரையறுக்கப்பட்டுள்ளது (opens in a new tab).
இந்தக் கோப்பு ETH-க்கான நிகழ்வு மற்றும் செயல்பாட்டு வரையறைகளைக் கொண்டுள்ளது.
இந்த வரையறைகள் ERC-20-க்காக மேலே உள்ள IL1ERC20Bridge-ல் வரையறுக்கப்பட்டவற்றுக்கு மிகவும் ஒத்தவை.
சில ERC-20 டோக்கன்களுக்கு தனிப்பயன் செயலாக்கம் தேவைப்படுவதாலும், நிலையான பாலத்தால் அவற்றைக் கையாள முடியாததாலும் பால இடைமுகம் இரண்டு கோப்புகளாகப் பிரிக்கப்பட்டுள்ளது.
இதன் மூலம் அத்தகைய டோக்கனைக் கையாளும் தனிப்பயன் பாலம் IL1ERC20Bridge-ஐச் செயல்படுத்தலாம் மற்றும் ETH-ஐயும் பாலம் செய்ய வேண்டியதில்லை.
1// SPDX-License-Identifier: MIT2pragma solidity >0.5.0 <0.9.0;34import "./IL1ERC20Bridge.sol";56/* *7 * @title IL1StandardBridge */8interface IL1StandardBridge is IL1ERC20Bridge {9 /* *********10 * நிகழ்வுகள் *11 ********* */12 event ETHDepositInitiated(13 address indexed _from,14 address indexed _to,15 uint256 _amount,16 bytes _data17 );அனைத்தையும் காட்டுL1 மற்றும் L2 டோக்கன் முகவரிகள் இல்லாமல் இருப்பதைத் தவிர, இந்த நிகழ்வு ERC-20 பதிப்பிற்கு (ERC20DepositInitiated) கிட்டத்தட்ட ஒத்ததாகும்.
மற்ற நிகழ்வுகள் மற்றும் செயல்பாடுகளுக்கும் இது பொருந்தும்.
1 event ETHWithdrawalFinalized(2 .3 .4 .5 );67 /* *******************8 * பொதுவான செயல்பாடுகள் *9 ******************* */1011 /* *12 * @dev அழைப்பாளரின் L2 இருப்பில் குறிப்பிட்ட அளவு ETH-ஐ டெபாசிட் செய்கிறது.13 .14 .15 . */16 function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;1718 /* *19 * @dev பெறுநரின் L2 இருப்பில் குறிப்பிட்ட அளவு ETH-ஐ டெபாசிட் செய்கிறது.20 .21 .22 . */23 function depositETHTo(24 address _to,25 uint32 _l2Gas,26 bytes calldata _data27 ) external payable;2829 /* ************************30 * கிராஸ்-செயின் செயல்பாடுகள் *31 ************************ */3233 /* *34 * @dev L2-இலிருந்து L1-க்கு திரும்பப் பெறுதலை முடித்து, பெறுநரின் L1 ETH டோக்கன் இருப்பில் நிதியை வரவு வைக்கிறது. xDomainMessenger மட்டுமே இந்தச் செயல்பாட்டை அழைக்க முடியும் என்பதால், திரும்பப் பெறுதல் இறுதி செய்யப்படுவதற்கு முன்பு இது ஒருபோதும் அழைக்கப்படாது.35 .36 .37 . */38 function finalizeETHWithdrawal(39 address _from,40 address _to,41 uint256 _amount,42 bytes calldata _data43 ) external;44}அனைத்தையும் காட்டுCrossDomainEnabled
மற்ற அடுக்குக்குச் செய்திகளை அனுப்ப இரு பாலங்களாலும் (L1 மற்றும் L2) இந்த ஒப்பந்தம் (opens in a new tab) மரபுரிமையாகப் பெறப்படுகிறது.
1// SPDX-License-Identifier: MIT2pragma solidity >0.5.0 <0.9.0;34/* இடைமுக இறக்குமதிகள் */5import { ICrossDomainMessenger } from "./ICrossDomainMessenger.sol";குறுக்கு டொமைன் மெசஞ்சரைப் பயன்படுத்தி மற்ற அடுக்குக்கு எவ்வாறு செய்திகளை அனுப்புவது என்பதை இந்த இடைமுகம் (opens in a new tab) ஒப்பந்தத்திற்குச் சொல்கிறது. இந்தக் குறுக்கு டொமைன் மெசஞ்சர் முற்றிலும் வேறுபட்ட ஒரு அமைப்பாகும், மேலும் இது தனக்கென ஒரு கட்டுரைக்குத் தகுதியானது, அதை நான் எதிர்காலத்தில் எழுதுவேன் என்று நம்புகிறேன்.
1/* *2 * @title CrossDomainEnabled3 * @dev கிராஸ்-டொமைன் தகவல்தொடர்புகளைச் செய்யும் ஒப்பந்தங்களுக்கான உதவி ஒப்பந்தம்4 *5 * பயன்படுத்தப்பட்ட கம்பைலர்: மரபுரிமையாகப் பெறும் ஒப்பந்தத்தால் வரையறுக்கப்படுகிறது */6contract CrossDomainEnabled {7 /* ************8 * மாறிகள் *9 ************ */1011 // மற்ற டொமைனிலிருந்து செய்திகளை அனுப்பவும் பெறவும் பயன்படுத்தப்படும் மெசஞ்சர் ஒப்பந்தம்.12 address public messenger;1314 /* **************15 * கன்ஸ்ட்ரக்டர் *16 ************** */1718 /* *19 * @param _messenger தற்போதைய லேயரில் உள்ள CrossDomainMessenger-இன் முகவரி. */20 constructor(address _messenger) {21 messenger = _messenger;22 }அனைத்தையும் காட்டுஒப்பந்தம் தெரிந்து கொள்ள வேண்டிய ஒரு அளவுரு, இந்த அடுக்கில் உள்ள குறுக்கு டொமைன் மெசஞ்சரின் முகவரி. இந்த அளவுரு கன்ஸ்ட்ரக்டரில் (constructor) ஒரு முறை அமைக்கப்படுகிறது, மேலும் இது ஒருபோதும் மாறாது.
12 /* *********************3 * ஃபங்ஷன் மாடிஃபையர்கள் *4 ********************* */56 /* *7 * மாற்றியமைக்கப்பட்ட செயல்பாட்டை ஒரு குறிப்பிட்ட கிராஸ்-டொமைன் கணக்கு மட்டுமே அழைக்க முடியும் என்பதைச் செயல்படுத்துகிறது.8 * @param _sourceDomainAccount இந்தச் செயல்பாட்டை அழைக்க அங்கீகரிக்கப்பட்ட, தொடங்கும் டொமைனில் உள்ள ஒரே கணக்கு. */9 modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {அனைத்தையும் காட்டுகுறுக்கு டொமைன் செய்தியிடல் அது இயங்கும் பிளாக்செயினில் உள்ள எந்தவொரு ஒப்பந்தத்தாலும் (Ethereum mainnet அல்லது Optimism) அணுகக்கூடியது. ஆனால் ஒவ்வொரு பக்கத்திலும் உள்ள பாலம் மற்ற பக்கத்தில் உள்ள பாலத்திலிருந்து வரும் குறிப்பிட்ட செய்திகளை மட்டுமே நம்ப வேண்டும்.
1 require(2 msg.sender == address(getCrossDomainMessenger()),3 "OVM_XCHAIN: messenger contract unauthenticated"4 );பொருத்தமான குறுக்கு டொமைன் மெசஞ்சரிலிருந்து (messenger, நீங்கள் கீழே பார்ப்பது போல்) வரும் செய்திகளை மட்டுமே நம்ப முடியும்.
12 require(3 getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,4 "OVM_XCHAIN: wrong sender of cross-domain message"5 );குறுக்கு டொமைன் மெசஞ்சர் மற்ற அடுக்குடன் செய்தியை அனுப்பிய முகவரியை வழங்கும் வழி .xDomainMessageSender() செயல்பாடு (opens in a new tab) ஆகும்.
செய்தியால் தொடங்கப்பட்ட பரிவர்த்தனையில் இது அழைக்கப்படும் வரை இந்தத் தகவலை வழங்க முடியும்.
நாம் பெற்ற செய்தி மற்ற பாலத்திலிருந்து வந்ததா என்பதை உறுதிப்படுத்த வேண்டும்.
12 _;3 }45 /* *********************6 * உள் செயல்பாடுகள் *7 ********************* */89 /* *10 * வழக்கமாக சேமிப்பகத்திலிருந்து மெசஞ்சரைப் பெறுகிறது. ஒரு துணை ஒப்பந்தம் மேலெழுத (override) வேண்டியிருந்தால் இந்தச் செயல்பாடு வெளிப்படுத்தப்படுகிறது.11 * @return பயன்படுத்த வேண்டிய கிராஸ்-டொமைன் மெசஞ்சர் ஒப்பந்தத்தின் முகவரி. */12 function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {13 return ICrossDomainMessenger(messenger);14 }அனைத்தையும் காட்டுஇந்தச் செயல்பாடு குறுக்கு டொமைன் மெசஞ்சரை வழங்குகிறது.
எந்தக் குறுக்கு டொமைன் மெசஞ்சரைப் பயன்படுத்த வேண்டும் என்பதைக் குறிப்பிட ஒரு அல்காரிதத்தைப் பயன்படுத்த இதிலிருந்து மரபுரிமையாகப் பெறும் ஒப்பந்தங்களை அனுமதிக்க, messenger மாறிக்கு பதிலாக ஒரு செயல்பாட்டைப் பயன்படுத்துகிறோம்.
12 /* *3 * மற்றொரு டொமைனில் உள்ள கணக்கிற்கு ஒரு செய்தியை அனுப்புகிறது4 * @param _crossDomainTarget இலக்கு டொமைனில் உள்ள உத்தேசிக்கப்பட்ட பெறுநர்5 * @param _message இலக்கிற்கு அனுப்ப வேண்டிய தரவு (வழக்கமாக `onlyFromCrossDomainAccount()` உள்ள செயல்பாட்டிற்கான calldata)6 * @param _gasLimit இலக்கு டொமைனில் செய்தியைப் பெறுவதற்கான gasLimit. */7 function sendCrossDomainMessage(8 address _crossDomainTarget,9 uint32 _gasLimit,10 bytes memory _messageஅனைத்தையும் காட்டுஇறுதியாக, மற்ற அடுக்குக்குச் செய்தியை அனுப்பும் செயல்பாடு.
1 ) internal {2 // slither-disable-next-line reentrancy-events, reentrancy-benignSlither (opens in a new tab) என்பது பாதிப்புகள் மற்றும் பிற சாத்தியமான சிக்கல்களைத் தேட ஒவ்வொரு ஒப்பந்தத்திலும் Optimism இயக்கும் ஒரு நிலையான பகுப்பாய்வி (static analyzer) ஆகும். இந்த நிலையில், பின்வரும் வரி இரண்டு பாதிப்புகளைத் தூண்டுகிறது:
- ரீஎன்ட்ரன்சி நிகழ்வுகள் (Reentrancy events) (opens in a new tab)
- தீங்கற்ற ரீஎன்ட்ரன்சி (Benign reentrancy) (opens in a new tab)
1 getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);2 }3}இந்த நிலையில் ரீஎன்ட்ரன்சி பற்றி நாங்கள் கவலைப்படவில்லை, Slither-க்கு அதை அறிய வழி இல்லாவிட்டாலும், getCrossDomainMessenger() நம்பகமான முகவரியை வழங்குகிறது என்பது எங்களுக்குத் தெரியும்.
L1 பால ஒப்பந்தம்
இந்த ஒப்பந்தத்திற்கான மூலக் குறியீடு இங்கே உள்ளது (opens in a new tab).
1// SPDX-License-Identifier: MIT2pragma solidity ^0.8.9;இடைமுகங்கள் பிற ஒப்பந்தங்களின் ஒரு பகுதியாக இருக்கலாம், எனவே அவை பரந்த அளவிலான Solidity பதிப்புகளை ஆதரிக்க வேண்டும். ஆனால் பாலம் என்பது நமது ஒப்பந்தமாகும், மேலும் அது எந்த Solidity பதிப்பைப் பயன்படுத்துகிறது என்பதில் நாம் கண்டிப்பாக இருக்க முடியும்.
1/* இடைமுக இறக்குமதிகள் */2import { IL1StandardBridge } from "./IL1StandardBridge.sol";3import { IL1ERC20Bridge } from "./IL1ERC20Bridge.sol";IL1ERC20Bridge மற்றும் IL1StandardBridge ஆகியவை மேலே விளக்கப்பட்டுள்ளன.
1import { IL2ERC20Bridge } from "../../L2/messaging/IL2ERC20Bridge.sol";L2-ல் நிலையான பாலத்தைக் கட்டுப்படுத்த செய்திகளை உருவாக்க இந்த இடைமுகம் (opens in a new tab) நம்மை அனுமதிக்கிறது.
1import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";ERC-20 ஒப்பந்தங்களைக் கட்டுப்படுத்த இந்த இடைமுகம் (opens in a new tab) நம்மை அனுமதிக்கிறது. இதைப் பற்றி நீங்கள் இங்கே மேலும் படிக்கலாம்.
1/* நூலக இறக்குமதிகள் */2import { CrossDomainEnabled } from "../../libraries/bridge/CrossDomainEnabled.sol";மேலே விளக்கியபடி, இந்த ஒப்பந்தம் அடுக்ககளுக்கிடையேயான (interlayer) செய்தியிடலுக்குப் பயன்படுத்தப்படுகிறது.
1import { Lib_PredeployAddresses } from "../../libraries/constants/Lib_PredeployAddresses.sol";Lib_PredeployAddresses (opens in a new tab) எப்போதும் ஒரே முகவரியைக் கொண்ட L2 ஒப்பந்தங்களுக்கான முகவரிகளைக் கொண்டுள்ளது. இதில் L2-ல் உள்ள நிலையான பாலமும் அடங்கும்.
1import { Address } from "@openzeppelin/contracts/utils/Address.sol";OpenZeppelin-ன் முகவரி பயன்பாடுகள் (Address utilities) (opens in a new tab). இது ஒப்பந்த முகவரிகள் மற்றும் வெளிப்புறமாகச் சொந்தமான கணக்குகளுக்கு (EOA) சொந்தமான முகவரிகளை வேறுபடுத்தப் பயன்படுகிறது.
இது ஒரு சரியான தீர்வு அல்ல என்பதை நினைவில் கொள்ளவும், ஏனெனில் நேரடி அழைப்புகள் மற்றும் ஒப்பந்தத்தின் கன்ஸ்ட்ரக்டரிலிருந்து செய்யப்படும் அழைப்புகளை வேறுபடுத்த வழி இல்லை, ஆனால் குறைந்தபட்சம் இது சில பொதுவான பயனர் பிழைகளை அடையாளம் காணவும் தடுக்கவும் அனுமதிக்கிறது.
1import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";ERC-20 தரநிலை (opens in a new tab) ஒரு ஒப்பந்தம் தோல்வியைப் புகாரளிக்க இரண்டு வழிகளை ஆதரிக்கிறது:
- Revert
false-ஐ வழங்குதல்
இரண்டு நிகழ்வுகளையும் கையாள்வது நமது குறியீட்டை மிகவும் சிக்கலாக்கும், எனவே அதற்குப் பதிலாக OpenZeppelin-ன் SafeERC20 (opens in a new tab)-ஐப் பயன்படுத்துகிறோம், இது அனைத்து தோல்விகளும் revert-ல் முடிவடைவதை (opens in a new tab) உறுதி செய்கிறது.
1/* *2 * @title L1StandardBridge3 * @dev L1 ETH மற்றும் ERC20 பிரிட்ஜ் என்பது டெபாசிட் செய்யப்பட்ட L1 நிதிகளையும் L2-இல் பயன்பாட்டில் உள்ள நிலையான டோக்கன்களையும் சேமிக்கும் ஒரு ஒப்பந்தமாகும். இது தொடர்புடைய L2 பிரிட்ஜை ஒத்திசைக்கிறது, டெபாசிட்டுகளைப் பற்றி அதற்குத் தெரிவிக்கிறது மற்றும் புதிதாக இறுதி செய்யப்பட்ட திரும்பப் பெறுதல்களுக்காக அதைக் கண்காணிக்கிறது.4 * */5contract L1StandardBridge is IL1StandardBridge, CrossDomainEnabled {6 using SafeERC20 for IERC20;IERC20 இடைமுகத்தைப் பயன்படுத்தும் ஒவ்வொரு முறையும் SafeERC20 ரேப்பரைப் (wrapper) பயன்படுத்த வேண்டும் என்பதை இந்த வரியில்தான் குறிப்பிடுகிறோம்.
12 /* *******************************3 * வெளிப்புற ஒப்பந்த குறிப்புகள் *4 ******************************* */56 address public l2TokenBridge;L2StandardBridge-ன் முகவரி.
12 // டெபாசிட் செய்யப்பட்ட L1 டோக்கனின் இருப்பிற்கு L1 டோக்கனை L2 டோக்கனுடன் மேப் செய்கிறது3 mapping(address => mapping(address => uint256)) public deposits;இது போன்ற இரட்டை மேப்பிங் (mapping) (opens in a new tab) என்பது இரு பரிமாண ஸ்பார்ஸ் வரிசையை (two-dimensional sparse array) (opens in a new tab) வரையறுக்கும் வழியாகும்.
இந்தத் தரவுக் கட்டமைப்பில் உள்ள மதிப்புகள் deposit[L1 token addr][L2 token addr] என அடையாளம் காணப்படுகின்றன.
இயல்புநிலை மதிப்பு பூஜ்ஜியமாகும்.
வேறு மதிப்பிற்கு அமைக்கப்பட்ட செல்கள் மட்டுமே சேமிப்பகத்தில் எழுதப்படும்.
12 /* **************3 * கன்ஸ்ட்ரக்டர் *4 ************** */56 // இந்த ஒப்பந்தம் ஒரு ப்ராக்ஸிக்குப் பின்னால் இயங்குகிறது, எனவே கன்ஸ்ட்ரக்டர் அளவுருக்கள் பயன்படுத்தப்படாது.7 constructor() CrossDomainEnabled(address(0)) {}சேமிப்பகத்தில் உள்ள அனைத்து மாறிகளையும் நகலெடுக்காமல் இந்த ஒப்பந்தத்தை மேம்படுத்த முடியும்.
அதைச் செய்ய, ப்ராக்ஸி ஒப்பந்தத்தால் சேமிக்கப்பட்ட முகவரியைக் கொண்ட ஒரு தனி ஒப்பந்தத்திற்கு அழைப்புகளை மாற்ற delegatecall (opens in a new tab)-ஐப் பயன்படுத்தும் ஒப்பந்தமான Proxy (opens in a new tab)-ஐப் பயன்படுத்துகிறோம் (நீங்கள் மேம்படுத்தும்போது அந்த முகவரியை மாற்ற ப்ராக்ஸியிடம் கூறுகிறீர்கள்).
நீங்கள் delegatecall-ஐப் பயன்படுத்தும்போது, சேமிப்பகம் அழைக்கும் ஒப்பந்தத்தின் சேமிப்பகமாகவே இருக்கும், எனவே அனைத்து ஒப்பந்த நிலை மாறிகளின் மதிப்புகளும் பாதிக்கப்படாது.
இந்த முறையின் ஒரு விளைவு என்னவென்றால், delegatecall-ஆல் அழைக்கப்படும் ஒப்பந்தத்தின் சேமிப்பகம் பயன்படுத்தப்படுவதில்லை, எனவே அதற்கு அனுப்பப்படும் கன்ஸ்ட்ரக்டர் மதிப்புகள் ஒரு பொருட்டல்ல.
CrossDomainEnabled கன்ஸ்ட்ரக்டருக்கு நாம் ஒரு அர்த்தமற்ற மதிப்பை வழங்க இதுவே காரணம்.
கீழே உள்ள துவக்கம் கன்ஸ்ட்ரக்டரிலிருந்து தனித்தனியாக இருப்பதற்கும் இதுவே காரணம்.
1 /* *****************2 * துவக்கம் *3 ***************** */45 /* *6 * @param _l1messenger கிராஸ்-செயின் தகவல்தொடர்புகளுக்குப் பயன்படுத்தப்படும் L1 மெசஞ்சர் முகவரி.7 * @param _l2TokenBridge L2 நிலையான பிரிட்ஜ் முகவரி. */8 // slither-disable-next-line external-functionஇந்த Slither சோதனை (opens in a new tab) ஒப்பந்தக் குறியீட்டிலிருந்து அழைக்கப்படாத செயல்பாடுகளை அடையாளம் காட்டுகிறது, எனவே அவற்றை public-க்கு பதிலாக external என அறிவிக்கலாம்.
external செயல்பாடுகளின் கேஸ் செலவு குறைவாக இருக்கலாம், ஏனெனில் அவற்றுக்கு கால்டேட்டாவில் (calldata) அளவுருக்கள் வழங்கப்படலாம்.
public என அறிவிக்கப்பட்ட செயல்பாடுகள் ஒப்பந்தத்திற்குள்ளிருந்து அணுகக்கூடியதாக இருக்க வேண்டும்.
ஒப்பந்தங்கள் அவற்றின் சொந்த கால்டேட்டாவை மாற்ற முடியாது, எனவே அளவுருக்கள் நினைவகத்தில் இருக்க வேண்டும்.
அத்தகைய செயல்பாடு வெளிப்புறமாக அழைக்கப்படும்போது, கால்டேட்டாவை நினைவகத்திற்கு நகலெடுப்பது அவசியமாகும், இதற்கு கேஸ் செலவாகும்.
இந்த நிலையில் செயல்பாடு ஒரு முறை மட்டுமே அழைக்கப்படுகிறது, எனவே திறமையின்மை நமக்கு ஒரு பொருட்டல்ல.
1 function initialize(address _l1messenger, address _l2TokenBridge) public {2 require(messenger == address(0), "Contract has already been initialized.");initialize செயல்பாடு ஒரு முறை மட்டுமே அழைக்கப்பட வேண்டும்.
L1 குறுக்கு டொமைன் மெசஞ்சர் அல்லது L2 டோக்கன் பாலத்தின் முகவரி மாறினால், நாங்கள் ஒரு புதிய ப்ராக்ஸியையும் அதை அழைக்கும் புதிய பாலத்தையும் உருவாக்குகிறோம்.
முழு அமைப்பும் மேம்படுத்தப்படும் போது தவிர இது நடக்க வாய்ப்பில்லை, இது மிகவும் அரிதான நிகழ்வாகும்.
இந்தச் செயல்பாட்டை யார் அழைக்கலாம் என்பதைக் கட்டுப்படுத்தும் எந்தப் பொறிமுறையும் இதில் இல்லை என்பதை நினைவில் கொள்ளவும்.
இதன் பொருள், கோட்பாட்டளவில் ஒரு தாக்குபவர் நாங்கள் ப்ராக்ஸியையும் பாலத்தின் முதல் பதிப்பையும் பயன்படுத்தும் வரை காத்திருந்து, பின்னர் முறையான பயனர் செய்வதற்கு முன் initialize செயல்பாட்டை அடைய முன்கூட்டியே செயல்படலாம் (front-run) (opens in a new tab). ஆனால் இதைத் தடுக்க இரண்டு முறைகள் உள்ளன:
- ஒப்பந்தங்கள் நேரடியாக ஒரு EOA-ஆல் பயன்படுத்தப்படாமல், மற்றொரு ஒப்பந்தம் அவற்றை உருவாக்கும் பரிவர்த்தனையில் (opens in a new tab) பயன்படுத்தப்பட்டால், முழு செயல்முறையும் அணுவாக (atomic) இருக்கலாம், மேலும் வேறு எந்தப் பரிவர்த்தனையும் செயல்படுத்தப்படுவதற்கு முன்பு முடிவடையும்.
initialize-க்கான முறையான அழைப்பு தோல்வியுற்றால், புதிதாக உருவாக்கப்பட்ட ப்ராக்ஸி மற்றும் பாலத்தைப் புறக்கணித்து புதியவற்றை உருவாக்குவது எப்போதும் சாத்தியமாகும்.
1 messenger = _l1messenger;2 l2TokenBridge = _l2TokenBridge;3 }பாலம் தெரிந்து கொள்ள வேண்டிய இரண்டு அளவுருக்கள் இவை.
12 /* *************3 * டெபாசிட் செய்தல் *4 ************* */56 /* * @dev அனுப்புநர் EOA ஆக இருக்க வேண்டும் என்று கோரும் மாடிஃபையர். இந்தச் சரிபார்ப்பை initcode மூலம் ஒரு தீங்கிழைக்கும் ஒப்பந்தத்தால் தவிர்க்க முடியும், ஆனால் நாம் தவிர்க்க விரும்பும் பயனர் பிழையை இது கவனித்துக்கொள்கிறது. */7 modifier onlyEOA() {8 // ஒப்பந்தங்களிலிருந்து டெபாசிட்டுகளை நிறுத்தப் பயன்படுகிறது (தவறுதலாக டோக்கன்கள் இழக்கப்படுவதைத் தவிர்க்க)9 require(!Address.isContract(msg.sender), "Account not EOA");10 _;11 }அனைத்தையும் காட்டுOpenZeppelin-ன் Address பயன்பாடுகள் நமக்குத் தேவைப்பட்டதற்கு இதுவே காரணம்.
1 /* *2 * @dev அழைப்பாளரின் L2 இருப்பில் குறிப்பிட்ட அளவு ETH-ஐ டெபாசிட் செய்ய3 * எந்தத் தரவும் இல்லாமல் இந்தச் செயல்பாட்டை அழைக்கலாம்.4 * receive செயல்பாடு தரவை எடுத்துக்கொள்ளாது என்பதால், ஒரு பழமைவாத5 * இயல்புநிலை அளவு L2-க்கு அனுப்பப்படுகிறது. */6 receive() external payable onlyEOA {7 _initiateETHDeposit(msg.sender, msg.sender, 200_000, bytes(""));8 }இந்தச் செயல்பாடு சோதனை நோக்கங்களுக்காக உள்ளது. இது இடைமுக வரையறைகளில் தோன்றவில்லை என்பதைக் கவனியுங்கள் - இது சாதாரண பயன்பாட்டிற்கானது அல்ல.
1 /* *2 * @inheritdoc IL1StandardBridge */3 function depositETH(uint32 _l2Gas, bytes calldata _data) external payable onlyEOA {4 _initiateETHDeposit(msg.sender, msg.sender, _l2Gas, _data);5 }67 /* *8 * @inheritdoc IL1StandardBridge */9 function depositETHTo(10 address _to,11 uint32 _l2Gas,12 bytes calldata _data13 ) external payable {14 _initiateETHDeposit(msg.sender, _to, _l2Gas, _data);15 }அனைத்தையும் காட்டுஇந்த இரண்டு செயல்பாடுகளும் உண்மையான ETH டெபாசிட்டைக் கையாளும் செயல்பாடான _initiateETHDeposit-ஐச் சுற்றியுள்ள ரேப்பர்கள் ஆகும்.
1 /* *2 * @dev ETH-ஐ சேமித்து, டெபாசிட் பற்றி L2 ETH கேட்வேக்கு தெரிவிப்பதன் மூலம் டெபாசிட்டுகளுக்கான தர்க்கத்தைச் செய்கிறது.3 * @param _from L1-இல் டெபாசிட்டைப் பெற வேண்டிய கணக்கு.4 * @param _to L2-இல் டெபாசிட்டை வழங்க வேண்டிய கணக்கு.5 * @param _l2Gas L2-இல் டெபாசிட்டை முடிக்கத் தேவையான கேஸ் வரம்பு.6 * @param _data L2-க்கு அனுப்ப வேண்டிய விருப்பத் தரவு. இந்தத் தரவு வெளிப்புற ஒப்பந்தங்களின் வசதிக்காக மட்டுமே வழங்கப்படுகிறது. அதிகபட்ச நீளத்தை செயல்படுத்துவதைத் தவிர, இந்த ஒப்பந்தங்கள் அதன் உள்ளடக்கத்தைப் பற்றி எந்த உத்தரவாதத்தையும் வழங்காது. */7 function _initiateETHDeposit(8 address _from,9 address _to,10 uint32 _l2Gas,11 bytes memory _data12 ) internal {13 // finalizeDeposit அழைப்பிற்கான calldata-வை உருவாக்குகிறது14 bytes memory message = abi.encodeWithSelector(அனைத்தையும் காட்டுகுறுக்கு டொமைன் செய்திகள் செயல்படும் விதம் என்னவென்றால், இலக்கு ஒப்பந்தம் செய்தியை அதன் கால்டேட்டாவாகக் கொண்டு அழைக்கப்படுகிறது.
Solidity ஒப்பந்தங்கள் எப்போதும் ABI விவரக்குறிப்புகளுக்கு (opens in a new tab) ஏற்ப அவற்றின் கால்டேட்டாவை விளக்குகின்றன.
Solidity செயல்பாடு abi.encodeWithSelector (opens in a new tab) அந்த கால்டேட்டாவை உருவாக்குகிறது.
1 IL2ERC20Bridge.finalizeDeposit.selector,2 address(0),3 Lib_PredeployAddresses.OVM_ETH,4 _from,5 _to,6 msg.value,7 _data8 );இந்த அளவுருக்களுடன் finalizeDeposit செயல்பாட்டை (opens in a new tab) அழைப்பதே இங்குள்ள செய்தியாகும்:
| அளவுரு | மதிப்பு | பொருள் |
|---|---|---|
| _l1Token | address(0) | L1-ல் ETH-ஐக் (இது ERC-20 டோக்கன் அல்ல) குறிக்கும் சிறப்பு மதிப்பு |
| _l2Token | Lib_PredeployAddresses.OVM_ETH | Optimism-ல் ETH-ஐ நிர்வகிக்கும் L2 ஒப்பந்தம், 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000 (இந்த ஒப்பந்தம் உள் Optimism பயன்பாட்டிற்கு மட்டுமே) |
| _from | _from | ETH-ஐ அனுப்பும் L1-ல் உள்ள முகவரி |
| _to | _to | ETH-ஐப் பெறும் L2-ல் உள்ள முகவரி |
| amount | msg.value | அனுப்பப்பட்ட wei-ன் அளவு (இது ஏற்கனவே பாலத்திற்கு அனுப்பப்பட்டுள்ளது) |
| _data | _data | டெபாசிட்டுடன் இணைக்க வேண்டிய கூடுதல் தரவு |
1 // L2-க்குள் calldata-வை அனுப்புகிறது2 // slither-disable-next-line reentrancy-events3 sendCrossDomainMessage(l2TokenBridge, _l2Gas, message);குறுக்கு டொமைன் மெசஞ்சர் மூலம் செய்தியை அனுப்பவும்.
1 // slither-disable-next-line reentrancy-events2 emit ETHDepositInitiated(_from, _to, msg.value, _data);3 }இந்தப் பரிமாற்றத்தைக் கேட்கும் எந்தவொரு பரவலாக்கப்பட்ட பயன்பாட்டிற்கும் தெரிவிக்க ஒரு நிகழ்வை வெளியிடவும்.
1 /* *2 * @inheritdoc IL1ERC20Bridge */3 function depositERC20(4 .5 .6 .7 ) external virtual onlyEOA {8 _initiateERC20Deposit(_l1Token, _l2Token, msg.sender, msg.sender, _amount, _l2Gas, _data);9 }1011 /* *12 * @inheritdoc IL1ERC20Bridge */13 function depositERC20To(14 .15 .16 .17 ) external virtual {18 _initiateERC20Deposit(_l1Token, _l2Token, msg.sender, _to, _amount, _l2Gas, _data);19 }அனைத்தையும் காட்டுஇந்த இரண்டு செயல்பாடுகளும் உண்மையான ERC-20 டெபாசிட்டைக் கையாளும் செயல்பாடான _initiateERC20Deposit-ஐச் சுற்றியுள்ள ரேப்பர்கள் ஆகும்.
1 /* *2 * @dev L2 டெபாசிட் செய்யப்பட்ட டோக்கன் ஒப்பந்தத்திற்கு டெபாசிட் பற்றி தெரிவிப்பதன் மூலமும், L1 நிதிகளைப் பூட்ட ஒரு ஹேண்ட்லரை அழைப்பதன் மூலமும் (எ.கா., transferFrom) டெபாசிட்டுகளுக்கான தர்க்கத்தைச் செய்கிறது.3 *4 * @param _l1Token நாம் டெபாசிட் செய்யும் L1 ERC20-இன் முகவரி5 * @param _l2Token L1-க்கு தொடர்புடைய L2 ERC20-இன் முகவரி6 * @param _from L1-இல் டெபாசிட்டைப் பெற வேண்டிய கணக்கு7 * @param _to L2-இல் டெபாசிட்டை வழங்க வேண்டிய கணக்கு8 * @param _amount டெபாசிட் செய்ய வேண்டிய ERC20-இன் அளவு.9 * @param _l2Gas L2-இல் டெபாசிட்டை முடிக்கத் தேவையான கேஸ் வரம்பு.10 * @param _data L2-க்கு அனுப்ப வேண்டிய விருப்பத் தரவு. இந்தத் தரவு வெளிப்புற ஒப்பந்தங்களின் வசதிக்காக மட்டுமே வழங்கப்படுகிறது. அதிகபட்ச நீளத்தை செயல்படுத்துவதைத் தவிர, இந்த ஒப்பந்தங்கள் அதன் உள்ளடக்கத்தைப் பற்றி எந்த உத்தரவாதத்தையும் வழங்காது. */11 function _initiateERC20Deposit(12 address _l1Token,13 address _l2Token,14 address _from,15 address _to,16 uint256 _amount,17 uint32 _l2Gas,18 bytes calldata _data19 ) internal {அனைத்தையும் காட்டுஇந்தச் செயல்பாடு சில முக்கியமான வேறுபாடுகளுடன் மேலே உள்ள _initiateETHDeposit-ஐப் போன்றது.
முதல் வித்தியாசம் என்னவென்றால், இந்தச் செயல்பாடு டோக்கன் முகவரிகள் மற்றும் மாற்றுவதற்கான தொகையை அளவுருக்களாகப் பெறுகிறது.
ETH-ஐப் பொறுத்தவரை, பாலத்திற்கான அழைப்பு ஏற்கனவே பாலக் கணக்கிற்கு சொத்தை மாற்றுவதை உள்ளடக்கியது (msg.value).
1 // L1-இல் ஒரு டெபாசிட் தொடங்கப்படும்போது, L1 பிரிட்ஜ் எதிர்கால2 // திரும்பப் பெறுதல்களுக்காக நிதியைத் தனக்கே மாற்றிக்கொள்கிறது. ஒப்பந்தத்தில் குறியீடு உள்ளதா என்பதையும் safeTransferFrom சரிபார்க்கிறது, எனவே3 // _from ஒரு EOA அல்லது address(0) ஆக இருந்தால் இது தோல்வியடையும்.4 // slither-disable-next-line reentrancy-events, reentrancy-benign5 IERC20(_l1Token).safeTransferFrom(_from, address(this), _amount);ERC-20 டோக்கன் பரிமாற்றங்கள் ETH-லிருந்து வேறுபட்ட செயல்முறையைப் பின்பற்றுகின்றன:
- பயனர் (
_from) பொருத்தமான டோக்கன்களை மாற்ற பாலத்திற்கு ஒரு அனுமதியை வழங்குகிறார். - பயனர் டோக்கன் ஒப்பந்தத்தின் முகவரி, தொகை போன்றவற்றுடன் பாலத்தை அழைக்கிறார்.
- டெபாசிட் செயல்முறையின் ஒரு பகுதியாக பாலம் டோக்கன்களை (தனக்குத்தானே) மாற்றுகிறது.
முதல் படி கடைசி இரண்டிலிருந்து தனிப் பரிவர்த்தனையில் நடக்கலாம்.
இருப்பினும், _initiateERC20Deposit-ஐ அழைக்கும் இரண்டு செயல்பாடுகளும் (depositERC20 மற்றும் depositERC20To) msg.sender-ஐ _from அளவுருவாகக் கொண்டு மட்டுமே இந்தச் செயல்பாட்டை அழைப்பதால், முன்கூட்டியே செயல்படுவது (front-running) ஒரு பிரச்சினையல்ல.
1 // _l2Token.finalizeDeposit(_to, _amount) க்கான calldata-வை உருவாக்குகிறது2 bytes memory message = abi.encodeWithSelector(3 IL2ERC20Bridge.finalizeDeposit.selector,4 _l1Token,5 _l2Token,6 _from,7 _to,8 _amount,9 _data10 );1112 // L2-க்குள் calldata-வை அனுப்புகிறது13 // slither-disable-next-line reentrancy-events, reentrancy-benign14 sendCrossDomainMessage(l2TokenBridge, _l2Gas, message);1516 // slither-disable-next-line reentrancy-benign17 deposits[_l1Token][_l2Token] = deposits[_l1Token][_l2Token] + _amount;அனைத்தையும் காட்டுடெபாசிட் செய்யப்பட்ட டோக்கன்களின் அளவை deposits தரவுக் கட்டமைப்பில் சேர்க்கவும்.
ஒரே L1 ERC-20 டோக்கனுக்கு ஒத்த பல முகவரிகள் L2-ல் இருக்கலாம், எனவே டெபாசிட்களைக் கண்காணிக்க L1 ERC-20 டோக்கனின் பாலத்தின் இருப்பைப் பயன்படுத்துவது போதாது.
12 // slither-disable-next-line reentrancy-events3 emit ERC20DepositInitiated(_l1Token, _l2Token, _from, _to, _amount, _data);4 }56 /* ************************7 * கிராஸ்-செயின் செயல்பாடுகள் *8 ************************ */910 /* *11 * @inheritdoc IL1StandardBridge */12 function finalizeETHWithdrawal(13 address _from,14 address _to,15 uint256 _amount,16 bytes calldata _dataஅனைத்தையும் காட்டுL2 பாலம் L2 குறுக்கு டொமைன் மெசஞ்சருக்கு ஒரு செய்தியை அனுப்புகிறது, இது L1 குறுக்கு டொமைன் மெசஞ்சரை இந்தச் செயல்பாட்டை அழைக்கச் செய்கிறது (நிச்சயமாக, செய்தியை இறுதி செய்யும் பரிவர்த்தனை (opens in a new tab) L1-ல் சமர்ப்பிக்கப்பட்டவுடன்).
1 ) external onlyFromCrossDomainAccount(l2TokenBridge) {இது குறுக்கு டொமைன் மெசஞ்சரிலிருந்து வரும் மற்றும் L2 டோக்கன் பாலத்திலிருந்து உருவாகும் ஒரு சட்டபூர்வமான செய்தி என்பதை உறுதிப்படுத்தவும். பாலத்திலிருந்து ETH-ஐத் திரும்பப் பெற இந்தச் செயல்பாடு பயன்படுத்தப்படுகிறது, எனவே இது அங்கீகரிக்கப்பட்ட அழைப்பாளரால் மட்டுமே அழைக்கப்படுகிறது என்பதை நாம் உறுதிப்படுத்த வேண்டும்.
1 // slither-disable-next-line reentrancy-events2 (bool success, ) = _to.call{ value: _amount }(new bytes(0));ETH-ஐ மாற்றுவதற்கான வழி, msg.value-ல் உள்ள wei-ன் அளவுடன் பெறுநரை அழைப்பதாகும்.
1 require(success, "TransferHelper::safeTransferETH: ETH transfer failed");23 // slither-disable-next-line reentrancy-events4 emit ETHWithdrawalFinalized(_from, _to, _amount, _data);திரும்பப் பெறுதல் பற்றிய ஒரு நிகழ்வை வெளியிடவும்.
1 }23 /* *4 * @inheritdoc IL1ERC20Bridge */5 function finalizeERC20Withdrawal(6 address _l1Token,7 address _l2Token,8 address _from,9 address _to,10 uint256 _amount,11 bytes calldata _data12 ) external onlyFromCrossDomainAccount(l2TokenBridge) {அனைத்தையும் காட்டுஇந்தச் செயல்பாடு ERC-20 டோக்கன்களுக்கான தேவையான மாற்றங்களுடன் மேலே உள்ள finalizeETHWithdrawal-ஐப் போன்றது.
1 deposits[_l1Token][_l2Token] = deposits[_l1Token][_l2Token] - _amount;deposits தரவுக் கட்டமைப்பைப் புதுப்பிக்கவும்.
12 // L1-இல் திரும்பப் பெறுதல் இறுதி செய்யப்படும்போது, L1 பிரிட்ஜ் நிதியைத் திரும்பப் பெறுபவருக்கு மாற்றுகிறது3 // slither-disable-next-line reentrancy-events4 IERC20(_l1Token).safeTransfer(_to, _amount);56 // slither-disable-next-line reentrancy-events7 emit ERC20WithdrawalFinalized(_l1Token, _l2Token, _from, _to, _amount, _data);8 }91011 /* ****************************12 * தற்காலிகமானது - ETH-ஐ இடம்பெயர்த்தல் *13 **************************** */1415 /* *16 * @dev கணக்கில் ETH இருப்பைச் சேர்க்கிறது. பழைய கேட்வேயிலிருந்து புதிய கேட்வேக்கு ETH-ஐ17 * இடம்பெயர்க்க அனுமதிக்கும் வகையில் இது வடிவமைக்கப்பட்டுள்ளது.18 * குறிப்பு: பழைய ஒப்பந்தத்திலிருந்து இடம்பெயர்ந்த ETH-ஐப் பெறுவதற்காக இது ஒரு மேம்படுத்தலுக்கு (upgrade) மட்டுமே விடப்பட்டுள்ளது */19 function donateETH() external payable {}20}அனைத்தையும் காட்டுபாலத்தின் முந்தைய செயலாக்கம் ஒன்று இருந்தது.
அந்தச் செயலாக்கத்திலிருந்து இதற்கு மாறியபோது, நாங்கள் அனைத்து சொத்துகளையும் நகர்த்த வேண்டியிருந்தது.
ERC-20 டோக்கன்களை அப்படியே நகர்த்தலாம்.
இருப்பினும், ஒரு ஒப்பந்தத்திற்கு ETH-ஐ மாற்ற உங்களுக்கு அந்த ஒப்பந்தத்தின் ஒப்புதல் தேவை, அதைத்தான் donateETH நமக்கு வழங்குகிறது.
L2-ல் ERC-20 டோக்கன்கள்
ஒரு ERC-20 டோக்கன் நிலையான பாலத்தில் பொருந்துவதற்கு, அது நிலையான பாலத்தை, மற்றும் நிலையான பாலத்தை மட்டுமே, டோக்கனை உருவாக்க (mint) அனுமதிக்க வேண்டும். Optimism-ல் புழக்கத்தில் உள்ள டோக்கன்களின் எண்ணிக்கை L1 பால ஒப்பந்தத்திற்குள் லாக் செய்யப்பட்டுள்ள டோக்கன்களின் எண்ணிக்கைக்குச் சமமாக இருப்பதை பாலங்கள் உறுதி செய்ய வேண்டியிருப்பதால் இது அவசியமாகும். L2-ல் அதிக டோக்கன்கள் இருந்தால், சில பயனர்களால் தங்கள் சொத்துகளை மீண்டும் L1-க்கு பாலம் செய்ய முடியாது. நம்பகமான பாலத்திற்குப் பதிலாக, நாங்கள் அடிப்படையில் பின்ன இருப்பு வங்கியியலை (fractional reserve banking) (opens in a new tab) மீண்டும் உருவாக்குவோம். L1-ல் அதிக டோக்கன்கள் இருந்தால், L2 டோக்கன்களை எரிக்காமல் அவற்றை வெளியிட வழி இல்லாததால், அந்த டோக்கன்களில் சில பால ஒப்பந்தத்திற்குள் என்றென்றும் லாக் செய்யப்பட்டிருக்கும்.
IL2StandardERC20
நிலையான பாலத்தைப் பயன்படுத்தும் L2-ல் உள்ள ஒவ்வொரு ERC-20 டோக்கனும் இந்த இடைமுகத்தை (opens in a new tab) வழங்க வேண்டும், இது நிலையான பாலத்திற்குத் தேவையான செயல்பாடுகள் மற்றும் நிகழ்வுகளைக் கொண்டுள்ளது.
1// SPDX-License-Identifier: MIT2pragma solidity ^0.8.9;34import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";நிலையான ERC-20 இடைமுகம் (opens in a new tab) mint மற்றும் burn செயல்பாடுகளை உள்ளடக்கவில்லை.
அந்த முறைகள் ERC-20 தரநிலையால் (opens in a new tab) தேவைப்படுவதில்லை, இது டோக்கன்களை உருவாக்குவதற்கும் அழிப்பதற்குமான வழிமுறைகளைக் குறிப்பிடாமல் விட்டுவிடுகிறது.
1import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";ஒரு ஒப்பந்தம் என்ன செயல்பாடுகளை வழங்குகிறது என்பதைக் குறிப்பிட ERC-165 இடைமுகம் (opens in a new tab) பயன்படுத்தப்படுகிறது. நீங்கள் தரநிலையை இங்கே படிக்கலாம் (opens in a new tab).
1interface IL2StandardERC20 is IERC20, IERC165 {2 function l1Token() external returns (address);இந்த ஒப்பந்தத்திற்குப் பாலம் செய்யப்பட்ட L1 டோக்கனின் முகவரியை இந்தச் செயல்பாடு வழங்குகிறது. எதிர் திசையில் இதே போன்ற செயல்பாடு எங்களிடம் இல்லை என்பதை நினைவில் கொள்ளவும். அது செயல்படுத்தப்பட்ட போது L2 ஆதரவு திட்டமிடப்பட்டதா இல்லையா என்பதைப் பொருட்படுத்தாமல், எந்தவொரு L1 டோக்கனையும் பாலம் செய்ய நாம் সক্ষমமாக இருக்க வேண்டும்.
12 function mint(address _to, uint256 _amount) external;34 function burn(address _from, uint256 _amount) external;56 event Mint(address indexed _account, uint256 _amount);7 event Burn(address indexed _account, uint256 _amount);8}டோக்கன்களை உருவாக்க (mint) மற்றும் அழிக்க (burn) செயல்பாடுகள் மற்றும் நிகழ்வுகள். டோக்கன்களின் எண்ணிக்கை சரியாக இருப்பதை (L1-ல் லாக் செய்யப்பட்டுள்ள டோக்கன்களின் எண்ணிக்கைக்குச் சமமாக) உறுதி செய்ய இந்தச் செயல்பாடுகளை இயக்கக்கூடிய ஒரே நிறுவனமாக பாலம் இருக்க வேண்டும்.
L2StandardERC20
இது IL2StandardERC20 இடைமுகத்தின் எங்கள் செயலாக்கமாகும் (opens in a new tab).
உங்களுக்கு ஏதேனும் தனிப்பயன் தர்க்கம் தேவைப்படாவிட்டால், நீங்கள் இதைப் பயன்படுத்த வேண்டும்.
1// SPDX-License-Identifier: MIT2pragma solidity ^0.8.9;34import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";OpenZeppelin ERC-20 ஒப்பந்தம் (opens in a new tab). Optimism சக்கரத்தை மீண்டும் கண்டுபிடிப்பதில் நம்பிக்கை கொள்ளவில்லை, குறிப்பாக சக்கரம் நன்கு தணிக்கை செய்யப்பட்டு சொத்துகளை வைத்திருக்க போதுமான நம்பகத்தன்மையுடன் இருக்க வேண்டியிருக்கும் போது.
1import "./IL2StandardERC20.sol";23contract L2StandardERC20 is IL2StandardERC20, ERC20 {4 address public l1Token;5 address public l2Bridge;இவை நமக்குத் தேவைப்படும் மற்றும் ERC-20-க்கு பொதுவாகத் தேவைப்படாத இரண்டு கூடுதல் உள்ளமைவு அளவுருக்கள் ஆகும்.
12 /* *3 * @param _l2Bridge L2 நிலையான பிரிட்ஜின் முகவரி.4 * @param _l1Token தொடர்புடைய L1 டோக்கனின் முகவரி.5 * @param _name ERC20 பெயர்.6 * @param _symbol ERC20 குறியீடு. */7 constructor(8 address _l2Bridge,9 address _l1Token,10 string memory _name,11 string memory _symbol12 ) ERC20(_name, _symbol) {13 l1Token = _l1Token;14 l2Bridge = _l2Bridge;15 }அனைத்தையும் காட்டுமுதலில் நாம் மரபுரிமையாகப் பெறும் ஒப்பந்தத்திற்கான கன்ஸ்ட்ரக்டரை அழைக்கவும் (ERC20(_name, _symbol)) பின்னர் நமது சொந்த மாறிகளை அமைக்கவும்.
12 modifier onlyL2Bridge() {3 require(msg.sender == l2Bridge, "Only L2 Bridge can mint and burn");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 }அனைத்தையும் காட்டுERC-165 (opens in a new tab) இவ்வாறுதான் செயல்படுகிறது. ஒவ்வொரு இடைமுகமும் ஆதரிக்கப்படும் செயல்பாடுகளின் எண்ணிக்கையாகும், மேலும் அந்தச் செயல்பாடுகளின் ABI செயல்பாட்டுத் தேர்வாளர்களின் (ABI function selectors) (opens in a new tab) பிரத்தியேக அல்லது (exclusive or) (opens in a new tab) என அடையாளம் காணப்படுகிறது.
L2 பாலம் சொத்துகளை அனுப்பும் ERC-20 ஒப்பந்தம் ஒரு IL2StandardERC20 என்பதை உறுதிப்படுத்த ERC-165-ஐ ஒரு பகுத்தறிவுச் சோதனையாகப் (sanity check) பயன்படுத்துகிறது.
குறிப்பு: முரட்டு ஒப்பந்தம் supportsInterface-க்கு தவறான பதில்களை வழங்குவதைத் தடுக்க எதுவும் இல்லை, எனவே இது ஒரு பகுத்தறிவுச் சோதனை பொறிமுறையாகும், பாதுகாப்பு பொறிமுறை அல்ல.
1 // slither-disable-next-line external-function2 function mint(address _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(address _from, uint256 _amount) public virtual onlyL2Bridge {10 _burn(_from, _amount);1112 emit Burn(_from, _amount);13 }14}அனைத்தையும் காட்டுL2 பாலம் மட்டுமே சொத்துகளை உருவாக்கவும் அழிக்கவும் அனுமதிக்கப்படுகிறது.
_mint மற்றும் _burn ஆகியவை உண்மையில் OpenZeppelin ERC-20 ஒப்பந்தத்தில் வரையறுக்கப்பட்டுள்ளன.
அந்த ஒப்பந்தம் அவற்றை வெளிப்புறமாக வெளிப்படுத்தாது, ஏனெனில் டோக்கன்களை உருவாக்குவதற்கும் அழிப்பதற்குமான நிபந்தனைகள் ERC-20-ஐப் பயன்படுத்துவதற்கான வழிகளின் எண்ணிக்கையைப் போலவே வேறுபட்டவை.
L2 பாலக் குறியீடு
இது Optimism-ல் பாலத்தை இயக்கும் குறியீடாகும். இந்த ஒப்பந்தத்திற்கான ஆதாரம் இங்கே உள்ளது (opens in a new tab).
1// SPDX-License-Identifier: MIT2pragma solidity ^0.8.9;34/* இடைமுக இறக்குமதிகள் */5import { IL1StandardBridge } from "../../L1/messaging/IL1StandardBridge.sol";6import { IL1ERC20Bridge } from "../../L1/messaging/IL1ERC20Bridge.sol";7import { IL2ERC20Bridge } from "./IL2ERC20Bridge.sol";IL2ERC20Bridge (opens in a new tab) இடைமுகம் நாம் மேலே பார்த்த L1 இணையானதற்கு மிகவும் ஒத்ததாகும். இரண்டு குறிப்பிடத்தக்க வேறுபாடுகள் உள்ளன:
- L1-ல் நீங்கள் டெபாசிட்களைத் தொடங்கி திரும்பப் பெறுதல்களை முடிக்கிறீர்கள். இங்கே நீங்கள் திரும்பப் பெறுதல்களைத் தொடங்கி டெபாசிட்களை முடிக்கிறீர்கள்.
- L1-ல் ETH மற்றும் ERC-20 டோக்கன்களை வேறுபடுத்துவது அவசியமாகும். L2-ல் நாம் இரண்டிற்கும் ஒரே செயல்பாடுகளைப் பயன்படுத்தலாம், ஏனெனில் உள்நாட்டில் Optimism-ல் உள்ள ETH இருப்புகள் 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000 (opens in a new tab) என்ற முகவரியுடன் ERC-20 டோக்கனாகக் கையாளப்படுகின்றன.
1/* நூலக இறக்குமதிகள் */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/* ஒப்பந்த இறக்குமதிகள் */7import { IL2StandardERC20 } from "../../standards/IL2StandardERC20.sol";89/* *10 * @title L2StandardBridge11 * @dev L2 நிலையான பிரிட்ஜ் என்பது L1 மற்றும் L2-க்கு இடையே ETH மற்றும் ERC20 பரிமாற்றங்களைச் செயல்படுத்த12 * L1 நிலையான பிரிட்ஜுடன் இணைந்து செயல்படும் ஒரு ஒப்பந்தமாகும்.13 * L1 நிலையான பிரிட்ஜில் டெபாசிட்டுகள் செய்யப்படுவதைப் பற்றி அறியும்போது, இந்த ஒப்பந்தம் புதிய டோக்கன்களை உருவாக்குபவராக (minter) செயல்படுகிறது.14 * திரும்பப் பெறுவதற்காக உத்தேசிக்கப்பட்ட டோக்கன்களை அழிப்பவராகவும் (burner) இந்த ஒப்பந்தம் செயல்படுகிறது, L1 நிதியை வெளியிடுமாறு L1 பிரிட்ஜுக்குத் தெரிவிக்கிறது. */15contract L2StandardBridge is IL2ERC20Bridge, CrossDomainEnabled {16 /* *******************************17 * வெளிப்புற ஒப்பந்த குறிப்புகள் *18 ******************************* */1920 address public l1TokenBridge;அனைத்தையும் காட்டுL1 பாலத்தின் முகவரியைக் கண்காணிக்கவும். L1 இணையானதற்கு மாறாக, இங்கே நமக்கு இந்த மாறி தேவை என்பதை நினைவில் கொள்ளவும். L1 பாலத்தின் முகவரி முன்கூட்டியே தெரியாது.
12 /* **************3 * கன்ஸ்ட்ரக்டர் *4 ************** */56 /* *7 * @param _l2CrossDomainMessenger இந்த ஒப்பந்தத்தால் பயன்படுத்தப்படும் கிராஸ்-டொமைன் மெசஞ்சர்.8 * @param _l1TokenBridge பிரதான செயினில் (main chain) பயன்படுத்தப்பட்ட L1 பிரிட்ஜின் முகவரி. */9 constructor(address _l2CrossDomainMessenger, address _l1TokenBridge)10 CrossDomainEnabled(_l2CrossDomainMessenger)11 {12 l1TokenBridge = _l1TokenBridge;13 }1415 /* **************16 * திரும்பப் பெறுதல் *17 ************** */1819 /* *20 * @inheritdoc IL2ERC20Bridge */21 function withdraw(22 address _l2Token,23 uint256 _amount,24 uint32 _l1Gas,25 bytes calldata _data26 ) external virtual {27 _initiateWithdrawal(_l2Token, msg.sender, msg.sender, _amount, _l1Gas, _data);28 }2930 /* *31 * @inheritdoc IL2ERC20Bridge */32 function withdrawTo(33 address _l2Token,34 address _to,35 uint256 _amount,36 uint32 _l1Gas,37 bytes calldata _data38 ) external virtual {39 _initiateWithdrawal(_l2Token, msg.sender, _to, _amount, _l1Gas, _data);40 }அனைத்தையும் காட்டுஇந்த இரண்டு செயல்பாடுகளும் திரும்பப் பெறுதல்களைத் தொடங்குகின்றன. L1 டோக்கன் முகவரியைக் குறிப்பிடத் தேவையில்லை என்பதை நினைவில் கொள்ளவும். L2 டோக்கன்கள் L1 இணையான முகவரியை நமக்குச் சொல்லும் என்று எதிர்பார்க்கப்படுகிறது.
12 /* *3 * @dev டோக்கனை அழிப்பதன் மூலமும், திரும்பப் பெறுதல் பற்றி L1 டோக்கன் கேட்வேக்குத் தெரிவிப்பதன் மூலமும்4 * திரும்பப் பெறுதல்களுக்கான தர்க்கத்தைச் செய்கிறது.5 * @param _l2Token திரும்பப் பெறுதல் தொடங்கப்பட்ட L2 டோக்கனின் முகவரி.6 * @param _from L2-இல் திரும்பப் பெறுதலைப் பெற வேண்டிய கணக்கு.7 * @param _to L1-இல் திரும்பப் பெறுதலை வழங்க வேண்டிய கணக்கு.8 * @param _amount திரும்பப் பெற வேண்டிய டோக்கனின் அளவு.9 * @param _l1Gas பயன்படுத்தப்படவில்லை, ஆனால் சாத்தியமான முன்னோக்கு இணக்கத்தன்மை (forward compatibility) பரிசீலனைகளுக்காக சேர்க்கப்பட்டுள்ளது.10 * @param _data L1-க்கு அனுப்ப வேண்டிய விருப்பத் தரவு. இந்தத் தரவு வெளிப்புற ஒப்பந்தங்களின் வசதிக்காக மட்டுமே வழங்கப்படுகிறது. அதிகபட்ச நீளத்தை செயல்படுத்துவதைத் தவிர, இந்த ஒப்பந்தங்கள் அதன் உள்ளடக்கத்தைப் பற்றி எந்த உத்தரவாதத்தையும் வழங்காது. */11 function _initiateWithdrawal(12 address _l2Token,13 address _from,14 address _to,15 uint256 _amount,16 uint32 _l1Gas,17 bytes calldata _data18 ) internal {19 // திரும்பப் பெறுதல் தொடங்கப்படும்போது, அடுத்தடுத்த L220 // பயன்பாட்டைத் தடுக்க திரும்பப் பெறுபவரின் நிதியை நாங்கள் அழிக்கிறோம் (burn)21 // slither-disable-next-line reentrancy-events22 IL2StandardERC20(_l2Token).burn(msg.sender, _amount);அனைத்தையும் காட்டுநாங்கள் _from அளவுருவை நம்பியிருக்கவில்லை, மாறாக msg.sender-ஐ நம்பியிருக்கிறோம் என்பதைக் கவனியுங்கள், இது போலியாக உருவாக்குவது மிகவும் கடினம் (எனக்குத் தெரிந்தவரை சாத்தியமற்றது).
12 // l1TokenBridge.finalizeERC20Withdrawal(_to, _amount) க்கான calldata-வை உருவாக்குகிறது3 // slither-disable-next-line reentrancy-events4 address l1Token = IL2StandardERC20(_l2Token).l1Token();5 bytes memory message;67 if (_l2Token == Lib_PredeployAddresses.OVM_ETH) {L1-ல் ETH மற்றும் ERC-20-ஐ வேறுபடுத்துவது அவசியமாகும்.
1 message = abi.encodeWithSelector(2 IL1StandardBridge.finalizeETHWithdrawal.selector,3 _from,4 _to,5 _amount,6 _data7 );8 } else {9 message = abi.encodeWithSelector(10 IL1ERC20Bridge.finalizeERC20Withdrawal.selector,11 l1Token,12 _l2Token,13 _from,14 _to,15 _amount,16 _data17 );18 }1920 // L1 பிரிட்ஜுக்கு செய்தியை அனுப்புகிறது21 // slither-disable-next-line reentrancy-events22 sendCrossDomainMessage(l1TokenBridge, _l1Gas, message);2324 // slither-disable-next-line reentrancy-events25 emit WithdrawalInitiated(l1Token, _l2Token, msg.sender, _to, _amount, _data);26 }2728 /* ***********************************29 * கிராஸ்-செயின் செயல்பாடு: டெபாசிட் செய்தல் *30 *********************************** */3132 /* *33 * @inheritdoc IL2ERC20Bridge */34 function finalizeDeposit(35 address _l1Token,36 address _l2Token,37 address _from,38 address _to,39 uint256 _amount,40 bytes calldata _dataஅனைத்தையும் காட்டுஇந்தச் செயல்பாடு L1StandardBridge-ஆல் அழைக்கப்படுகிறது.
1 ) external virtual onlyFromCrossDomainAccount(l1TokenBridge) {செய்தியின் ஆதாரம் சட்டபூர்வமானது என்பதை உறுதிப்படுத்தவும்.
இது முக்கியமானது, ஏனெனில் இந்தச் செயல்பாடு _mint-ஐ அழைக்கிறது மற்றும் L1-ல் பாலம் வைத்திருக்கும் டோக்கன்களால் ஈடுசெய்யப்படாத டோக்கன்களை வழங்கப் பயன்படுத்தப்படலாம்.
1 // இலக்கு டோக்கன் இணக்கமாக உள்ளதா என்பதைச் சரிபார்த்து,2 // L1-இல் டெபாசிட் செய்யப்பட்ட டோக்கன் இங்குள்ள L2 டெபாசிட் செய்யப்பட்ட டோக்கன் பிரதிநிதித்துவத்துடன் பொருந்துகிறதா என்பதைச் சரிபார்க்கவும்3 if (4 // slither-disable-next-line reentrancy-events5 ERC165Checker.supportsInterface(_l2Token, 0x1d1d8b63) &&6 _l1Token == IL2StandardERC20(_l2Token).l1Token()பகுத்தறிவுச் சோதனைகள் (Sanity checks):
- சரியான இடைமுகம் ஆதரிக்கப்படுகிறது
- L2 ERC-20 ஒப்பந்தத்தின் L1 முகவரி டோக்கன்களின் L1 ஆதாரத்துடன் பொருந்துகிறது
1 ) {2 // ஒரு டெபாசிட் இறுதி செய்யப்படும்போது, L2-இல் உள்ள கணக்கில் அதே அளவு3 // டோக்கன்களை வரவு வைக்கிறோம்.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);பகுத்தறிவுச் சோதனைகள் தேர்ச்சி பெற்றால், டெபாசிட்டை முடிக்கவும்:
- டோக்கன்களை உருவாக்கவும் (Mint)
- பொருத்தமான நிகழ்வை வெளியிடவும்
1 } else {2 // டெபாசிட் செய்யப்படும் L2 டோக்கன் அதன் L1 டோக்கனின் சரியான முகவரியைப் பற்றி முரண்படுகிறது3 // அல்லது சரியான இடைமுகத்தை ஆதரிக்கவில்லை.4 // ஒரு தீங்கிழைக்கும் L2 டோக்கன் இருந்தால் அல்லது ஒரு பயனர் எப்படியாவது5 // டெபாசிட் செய்ய தவறான L2 டோக்கன் முகவரியைக் குறிப்பிட்டால் மட்டுமே இது நிகழ வேண்டும்.6 // எந்தவொரு சந்தர்ப்பத்திலும், நாங்கள் செயல்முறையை இங்கு நிறுத்தி, ஒரு திரும்பப் பெறுதல்7 // செய்தியை உருவாக்குகிறோம், இதனால் பயனர்கள் சில சந்தர்ப்பங்களில் தங்கள் நிதியை வெளியே எடுக்க முடியும்.8 // தீங்கிழைக்கும் டோக்கன் ஒப்பந்தங்களை முற்றிலுமாகத் தடுக்க எந்த வழியும் இல்லை, ஆனால் இது9 // பயனர் பிழையைக் கட்டுப்படுத்துகிறது மற்றும் சில வகையான தீங்கிழைக்கும் ஒப்பந்த நடத்தைகளைத் தணிக்கிறது.அனைத்தையும் காட்டுதவறான L2 டோக்கன் முகவரியைப் பயன்படுத்தி பயனர் கண்டறியக்கூடிய பிழையைச் செய்திருந்தால், நாங்கள் டெபாசிட்டை ரத்து செய்து L1-ல் டோக்கன்களைத் திருப்பித் தர விரும்புகிறோம். L2-லிருந்து இதைச் செய்வதற்கான ஒரே வழி, தவறு சவால் காலத்திற்குக் காத்திருக்க வேண்டிய ஒரு செய்தியை அனுப்புவதாகும், ஆனால் டோக்கன்களை நிரந்தரமாக இழப்பதை விட இது பயனருக்கு மிகவும் சிறந்தது.
1 bytes memory message = abi.encodeWithSelector(2 IL1ERC20Bridge.finalizeERC20Withdrawal.selector,3 _l1Token,4 _l2Token,5 _to, // டெபாசிட்டை அனுப்புநருக்கே திருப்பி அனுப்ப இங்கு _to மற்றும் _from மாற்றப்பட்டுள்ளது6 _from,7 _amount,8 _data9 );1011 // L1 பிரிட்ஜுக்கு செய்தியை அனுப்புகிறது12 // slither-disable-next-line reentrancy-events13 sendCrossDomainMessage(l1TokenBridge, 0, message);14 // slither-disable-next-line reentrancy-events15 emit DepositFailed(_l1Token, _l2Token, _from, _to, _amount, _data);16 }17 }18}அனைத்தையும் காட்டுமுடிவுரை
நிலையான பாலம் என்பது சொத்துப் பரிமாற்றங்களுக்கான மிகவும் நெகிழ்வான பொறிமுறையாகும். இருப்பினும், இது மிகவும் பொதுவானது என்பதால், இது எப்போதும் பயன்படுத்த எளிதான பொறிமுறையாக இருக்காது. குறிப்பாகத் திரும்பப் பெறுதல்களுக்கு, பெரும்பாலான பயனர்கள் சவால் காலத்திற்குக் காத்திருக்காத மற்றும் திரும்பப் பெறுதலை முடிக்க Merkle சான்று தேவைப்படாத மூன்றாம் தரப்பு பாலங்களைப் (third party bridges) (opens in a new tab) பயன்படுத்த விரும்புகிறார்கள்.
இந்தப் பாலங்கள் பொதுவாக L1-ல் சொத்துகளை வைத்திருப்பதன் மூலம் செயல்படுகின்றன, அவை ஒரு சிறிய கட்டணத்தில் உடனடியாக வழங்குகின்றன (பெரும்பாலும் நிலையான பாலத்தைத் திரும்பப் பெறுவதற்கான கேஸ் செலவை விடக் குறைவு). பாலம் (அல்லது அதை இயக்குபவர்கள்) L1 சொத்துகளில் பற்றாக்குறை ஏற்படும் என்று எதிர்பார்க்கும் போது, அது L2-லிருந்து போதுமான சொத்துகளை மாற்றுகிறது. இவை மிகப் பெரிய திரும்பப் பெறுதல்கள் என்பதால், திரும்பப் பெறும் செலவு ஒரு பெரிய தொகையில் ஈடுசெய்யப்படுகிறது மற்றும் இது மிகச் சிறிய சதவீதமாகும்.
அடுக்கு 2 எவ்வாறு செயல்படுகிறது மற்றும் தெளிவான மற்றும் பாதுகாப்பான Solidity குறியீட்டை எவ்வாறு எழுதுவது என்பதைப் பற்றி மேலும் புரிந்துகொள்ள இந்தக் கட்டுரை உங்களுக்கு உதவியிருக்கும் என்று நம்புகிறோம்.
எனது மேலும் பல படைப்புகளுக்கு இங்கே பார்க்கவும் (opens in a new tab).
பக்கம் கடைசியாகப் புதுப்பிக்கப்பட்டது: 3 மார்ச், 2026