ஆப்டிமிசம் நிலையான பாலம் ஒப்பந்தத்தின் வழிகாட்டி
ஆப்டிமிசம் (opens in a new tab) என்பது ஒரு ஆப்டிமிஸ்டிக் ரோல்அப் ஆகும். ஆப்டிமிஸ்டிக் ரோலப்கள் எத்தேரியம் முதன்மை வலைப்பின்னலை (அடுக்கு 1 (l1) என்றும் அழைக்கப்படுகிறது) விட மிகக் குறைந்த விலையில் பரிவர்த்தனைகளைச் செயல்படுத்த முடியும், ஏனெனில் பிணையத்தில் உள்ள ஒவ்வொரு கணுவிற்கும் பதிலாக சில கணுக்களால் மட்டுமே பரிவர்த்தனைகள் செயல்படுத்தப்படுகின்றன. அதே நேரத்தில், தரவுகள் அனைத்தும் L1 இல் எழுதப்படுவதால், முதன்மை வலைப்பின்னலின் அனைத்து ஒருமைப்பாடு மற்றும் கிடைக்கும் தன்மை உத்தரவாதங்களுடன் அனைத்தையும் நிரூபிக்கவும் மறுகட்டமைக்கவும் முடியும்.
ஆப்டிமிசம் (அல்லது வேறு ஏதேனும் L2) இல் L1 சொத்துகளைப் பயன்படுத்த, சொத்துகள் பாலம் செய்யப்பட வேண்டும். இதை அடைவதற்கான ஒரு வழி, பயனர்கள் L1 இல் சொத்துகளை (ETH மற்றும் ERC-20 வில்லைகள் மிகவும் பொதுவானவை) பூட்டி, L2 இல் பயன்படுத்த சமமான சொத்துகளைப் பெறுவதாகும். இறுதியில், அவற்றை வைத்திருப்பவர்கள் அவற்றை மீண்டும் L1 க்கு பாலம் செய்ய விரும்பலாம். இதைச் செய்யும்போது, சொத்துகள் L2 இல் எரிக்கப்பட்டு, பின்னர் L1 இல் பயனருக்கு மீண்டும் வெளியிடப்படும்.
ஆப்டிமிசம் நிலையான பாலம் (opens in a new tab) செயல்படும் விதம் இதுதான். இந்தக் கட்டுரையில், அந்தப் பாலம் எவ்வாறு செயல்படுகிறது என்பதைப் பார்க்க அதன் மூலக் குறியீட்டைப் பார்ப்போம், மேலும் அதை நன்கு எழுதப்பட்ட Solidity குறியீட்டிற்கு உதாரணமாகப் படிப்போம்.
கட்டுப்பாட்டு ஓட்டங்கள்
பாலம் இரண்டு முக்கிய ஓட்டங்களைக் கொண்டுள்ளது:
- வைப்பு (L1 இலிருந்து L2 க்கு)
- திரும்பப் பெறுதல் (L2 இலிருந்து L1 க்கு)
வைப்பு ஓட்டம்
அடுக்கு 1
- ERC-20 ஐ வைப்புச் செய்தால், வைப்புச் செய்பவர் வைப்புச் செய்யப்படும் தொகையைச் செலவிட பாலத்திற்கு ஒரு அனுமதித்தொகையை வழங்குகிறார்
- வைப்புச் செய்பவர் L1 பாலத்தை அழைக்கிறார் (
depositERC20,depositERC20To,depositETH, அல்லதுdepositETHTo) - L1 பாலம் பாலம் செய்யப்பட்ட சொத்தை தன் வசம் எடுத்துக்கொள்கிறது
- ETH: அழைப்பின் ஒரு பகுதியாக வைப்புச் செய்பவரால் சொத்து பரிமாற்றம் செய்யப்படுகிறது
- ERC-20: வைப்புச் செய்பவர் வழங்கிய அனுமதித்தொகையைப் பயன்படுத்தி பாலம் தனக்குத்தானே சொத்தைப் பரிமாற்றம் செய்கிறது
- L1 பாலம் L2 பாலத்தில்
finalizeDepositஐ அழைக்க குறுக்கு-கள செய்தி பொறிமுறையைப் பயன்படுத்துகிறது
அடுக்கு 2
- L2 பாலம்
finalizeDepositக்கான அழைப்பு சட்டபூர்வமானதா என்பதைச் சரிபார்க்கிறது:- குறுக்கு கள செய்தி ஒப்பந்தத்திலிருந்து வந்ததா
- முதலில் L1 இல் உள்ள பாலத்திலிருந்து வந்ததா
- L2 இல் உள்ள ERC-20 வில்லை ஒப்பந்தம் சரியானதா என்பதை L2 பாலம் சரிபார்க்கிறது:
- L2 ஒப்பந்தம் அதன் L1 இணையானது L1 இல் வில்லைகள் வந்த அதே ஒப்பந்தம் என்று தெரிவிக்கிறது
- L2 ஒப்பந்தம் சரியான இடைமுகத்தை ஆதரிப்பதாகத் தெரிவிக்கிறது (ERC-165 ஐப் பயன்படுத்தி (opens in a new tab)).
- L2 ஒப்பந்தம் சரியானதாக இருந்தால், பொருத்தமான முகவரிக்கு பொருத்தமான எண்ணிக்கையிலான வில்லைகளை அச்சிட அதை அழைக்கவும். இல்லையெனில், L1 இல் வில்லைகளை உரிமைக்கோர பயனரை அனுமதிக்க திரும்பப் பெறுதல் செயல்முறையைத் தொடங்கவும்.
திரும்பப் பெறுதல் ஓட்டம்
அடுக்கு 2
- திரும்பப் பெறுபவர் L2 பாலத்தை அழைக்கிறார் (
withdrawஅல்லதுwithdrawTo) - L2 பாலம்
msg.senderக்கு சொந்தமான பொருத்தமான எண்ணிக்கையிலான வில்லைகளை எரிக்கிறது - L2 பாலம் L1 பாலத்தில்
finalizeETHWithdrawalஅல்லதுfinalizeERC20Withdrawalஐ அழைக்க குறுக்கு-கள செய்தி பொறிமுறையைப் பயன்படுத்துகிறது
அடுக்கு 1
- L1 பாலம்
finalizeETHWithdrawalஅல்லதுfinalizeERC20Withdrawalக்கான அழைப்பு சட்டபூர்வமானதா என்பதைச் சரிபார்க்கிறது:- குறுக்கு கள செய்தி பொறிமுறையிலிருந்து வந்ததா
- முதலில் L2 இல் உள்ள பாலத்திலிருந்து வந்ததா
- L1 பாலம் பொருத்தமான சொத்தை (ETH அல்லது ERC-20) பொருத்தமான முகவரிக்கு பரிமாற்றம் செய்கிறது
அடுக்கு 1 குறியீடு
இது L1, எத்தேரியம் முதன்மை வலைப்பின்னலில் இயங்கும் குறியீடு.
IL1ERC20Bridge
இந்த இடைமுகம் இங்கே வரையறுக்கப்பட்டுள்ளது (opens in a new tab). இது ERC-20 வில்லைகளைப் பாலம் செய்வதற்குத் தேவையான செயல்பாடுகள் மற்றும் வரையறைகளை உள்ளடக்கியது.
// SPDX-License-Identifier: MIT
ஆப்டிமிசத்தின் பெரும்பாலான குறியீடுகள் MIT உரிமத்தின் கீழ் வெளியிடப்படுகின்றன (opens in a new tab).
pragma solidity >0.5.0 <0.9.0;
இதை எழுதும் போது Solidity இன் சமீபத்திய பதிப்பு 0.8.12 ஆகும். பதிப்பு 0.9.0 வெளியிடப்படும் வரை, இந்தக் குறியீடு அதனுடன் இணக்கமாக உள்ளதா இல்லையா என்பது எங்களுக்குத் தெரியாது.
/**
* @title IL1ERC20Bridge
*/
interface IL1ERC20Bridge {
/**********
* நிகழ்வுகள் *
**********/
event ERC20DepositInitiated(
ஆப்டிமிசம் பாலம் சொற்களஞ்சியத்தில் வைப்பு என்பது L1 இலிருந்து L2 க்கு பரிமாற்றம் செய்வதைக் குறிக்கிறது, மேலும் திரும்பப் பெறுதல் என்பது L2 இலிருந்து L1 க்கு பரிமாற்றம் செய்வதைக் குறிக்கிறது.
address indexed _l1Token,
address indexed _l2Token,
பெரும்பாலான சந்தர்ப்பங்களில் L1 இல் உள்ள ERC-20 இன் முகவரி L2 இல் உள்ள சமமான ERC-20 இன் முகவரியைப் போன்றது அல்ல.
வில்லை முகவரிகளின் பட்டியலை நீங்கள் இங்கே பார்க்கலாம் (opens in a new tab).
chainId 1 ஐக் கொண்ட முகவரி L1 (முதன்மை வலைப்பின்னல்) இல் உள்ளது மற்றும் chainId 10 ஐக் கொண்ட முகவரி L2 (ஆப்டிமிசம்) இல் உள்ளது.
மற்ற இரண்டு chainId மதிப்புகள் Kovan சோதனைப் பிணையம் (42) மற்றும் Optimistic Kovan சோதனைப் பிணையம் (69) ஆகியவற்றுக்கானவை.
address indexed _from,
address _to,
uint256 _amount,
bytes _data
);
பரிமாற்றங்களில் குறிப்புகளைச் சேர்க்க முடியும், அவ்வாறான நிலையில் அவை அவற்றைப் புகாரளிக்கும் நிகழ்வுகளில் சேர்க்கப்படும்.
event ERC20WithdrawalFinalized(
address indexed _l1Token,
address indexed _l2Token,
address indexed _from,
address _to,
uint256 _amount,
bytes _data
);
அதே பாலம் ஒப்பந்தம் இரு திசைகளிலும் பரிமாற்றங்களைக் கையாள்கிறது. L1 பாலத்தைப் பொறுத்தவரை, இது வைப்புகளின் துவக்கம் மற்றும் திரும்பப் பெறுதல்களின் இறுதிப்படுத்தல் ஆகியவற்றைக் குறிக்கிறது.
/********************
* பொதுச் செயல்பாடுகள் *
********************/
/**
* @dev தொடர்புடைய அடுக்கு 2 (l2) பாலம் ஒப்பந்தத்தின் முகவரியைப் பெறவும்.
* @return தொடர்புடைய அடுக்கு 2 (l2) பாலம் ஒப்பந்தத்தின் முகவரி.
*/
function l2TokenBridge() external returns (address);
இந்தச் செயல்பாடு உண்மையில் தேவையில்லை, ஏனெனில் L2 இல் இது முன்பே நிலைநிறுத்தப்பட்ட ஒப்பந்தமாகும், எனவே இது எப்போதும் 0x4200000000000000000000000000000000000010 முகவரியில் இருக்கும்.
L2 பாலத்துடனான சமச்சீர்மைக்காக இது இங்கே உள்ளது, ஏனெனில் L1 பாலத்தின் முகவரியை அறிவது எளிதானது அல்ல.
/**
* @dev அடுக்கு 2 (l2) இல் அழைப்பாளரின் இருப்பில் ஒரு குறிப்பிட்ட அளவு ERC-20 ஐ வைப்பீடு செய்யவும்.
* @param _l1Token நாம் வைப்பீடு செய்யும் அடுக்கு 1 (l1) ERC-20 இன் முகவரி
* @param _l2Token அடுக்கு 1 (l1) க்கு தொடர்புடைய அடுக்கு 2 (l2) ERC-20 இன் முகவரி
* @param _amount வைப்பீடு செய்ய வேண்டிய ERC-20 இன் அளவு
* @param _l2Gas அடுக்கு 2 (l2) இல் வைப்பீட்டை முடிக்கத் தேவையான எரிவாயு வரம்பு.
* @param _data அடுக்கு 2 (l2) க்கு அனுப்ப வேண்டிய விருப்பத் தரவு. இந்தத் தரவு வெளிப்புற ஒப்பந்தங்களுக்கான வசதிக்காக மட்டுமே வழங்கப்படுகிறது. அதிகபட்ச நீளத்தை செயல்படுத்துவதைத் தவிர, இந்த ஒப்பந்தங்கள் அதன் உள்ளடக்கத்தைப் பற்றி எந்த உத்தரவாதத்தையும் வழங்காது.
*/
function depositERC20(
address _l1Token,
address _l2Token,
uint256 _amount,
uint32 _l2Gas,
bytes calldata _data
) external;
_l2Gas அளவுரு என்பது பரிவர்த்தனை செலவிட அனுமதிக்கப்படும் L2 எரிவாயுவின் அளவாகும்.
ஒரு குறிப்பிட்ட (உயர்) வரம்பு வரை, இது இலவசம் (opens in a new tab), எனவே ERC-20 ஒப்பந்தம் அச்சிடும்போது மிகவும் விசித்திரமான ஒன்றைச் செய்யாவிட்டால், இது ஒரு சிக்கலாக இருக்கக்கூடாது.
ஒரு பயனர் வேறு தொகுதிச்சங்கிலியில் உள்ள அதே முகவரிக்கு சொத்துகளைப் பாலம் செய்யும் பொதுவான காட்சியை இந்தச் செயல்பாடு கவனித்துக்கொள்கிறது.
/**
* @dev அடுக்கு 2 (l2) இல் பெறுநரின் இருப்பில் ஒரு குறிப்பிட்ட அளவு ERC-20 ஐ வைப்பீடு செய்யவும்.
* @param _l1Token நாம் வைப்பீடு செய்யும் அடுக்கு 1 (l1) ERC-20 இன் முகவரி
* @param _l2Token அடுக்கு 1 (l1) க்கு தொடர்புடைய அடுக்கு 2 (l2) ERC-20 இன் முகவரி
* @param _to திரும்பப் பெறுதலை வரவு வைக்க வேண்டிய அடுக்கு 2 (l2) முகவரி.
* @param _amount வைப்பீடு செய்ய வேண்டிய ERC-20 இன் அளவு.
* @param _l2Gas அடுக்கு 2 (l2) இல் வைப்பீட்டை முடிக்கத் தேவையான எரிவாயு வரம்பு.
* @param _data அடுக்கு 2 (l2) க்கு அனுப்ப வேண்டிய விருப்பத் தரவு. இந்தத் தரவு வெளிப்புற ஒப்பந்தங்களுக்கான வசதிக்காக மட்டுமே வழங்கப்படுகிறது. அதிகபட்ச நீளத்தை செயல்படுத்துவதைத் தவிர, இந்த ஒப்பந்தங்கள் அதன் உள்ளடக்கத்தைப் பற்றி எந்த உத்தரவாதத்தையும் வழங்காது.
*/
function depositERC20To(
address _l1Token,
address _l2Token,
address _to,
uint256 _amount,
uint32 _l2Gas,
bytes calldata _data
) external;
இந்தச் செயல்பாடு கிட்டத்தட்ட depositERC20 ஐப் போன்றது, ஆனால் இது ERC-20 ஐ வேறு முகவரிக்கு அனுப்ப உங்களை அனுமதிக்கிறது.
/*************************
* குறுக்கு-சங்கிலி செயல்பாடுகள் *
*************************/
/**
* @dev அடுக்கு 2 (l2) இலிருந்து அடுக்கு 1 (l1) க்கு திரும்பப் பெறுதலை முடித்து, பெறுநரின் அடுக்கு 1 (l1) ERC-20 வில்லை இருப்பில் நிதியை வரவு வைக்கவும்.
* அடுக்கு 2 (l2) இலிருந்து தொடங்கப்பட்ட திரும்பப் பெறுதல் இறுதி செய்யப்படாவிட்டால் இந்த அழைப்பு தோல்வியடையும்.
*
* @param _l1Token திரும்பப் பெறுதலை இறுதி செய்வதற்கான (finalizeWithdrawal) அடுக்கு 1 (l1) வில்லையின் முகவரி.
* @param _l2Token திரும்பப் பெறுதல் தொடங்கப்பட்ட அடுக்கு 2 (l2) வில்லையின் முகவரி.
* @param _from பரிமாற்றத்தைத் தொடங்கும் அடுக்கு 2 (l2) முகவரி.
* @param _to திரும்பப் பெறுதலை வரவு வைக்க வேண்டிய அடுக்கு 1 (l1) முகவரி.
* @param _amount வைப்பீடு செய்ய வேண்டிய ERC-20 இன் அளவு.
* @param _data அடுக்கு 2 (l2) இல் அனுப்புநரால் வழங்கப்பட்ட தரவு. இந்தத் தரவு வெளிப்புற ஒப்பந்தங்களுக்கான வசதிக்காக மட்டுமே வழங்கப்படுகிறது. அதிகபட்ச நீளத்தை செயல்படுத்துவதைத் தவிர, இந்த ஒப்பந்தங்கள் அதன் உள்ளடக்கத்தைப் பற்றி எந்த உத்தரவாதத்தையும் வழங்காது.
*/
function finalizeERC20Withdrawal(
address _l1Token,
address _l2Token,
address _from,
address _to,
uint256 _amount,
bytes calldata _data
) external;
}
ஆப்டிமிசத்தில் திரும்பப் பெறுதல்கள் (மற்றும் L2 இலிருந்து L1 க்கான பிற செய்திகள்) இரண்டு படி செயல்முறையாகும்:
- L2 இல் ஒரு தொடக்கப் பரிவர்த்தனை.
- L1 இல் ஒரு இறுதி அல்லது உரிமைக்கோரல் பரிவர்த்தனை. L2 பரிவர்த்தனைக்கான பிழை சவால் காலம் (opens in a new tab) முடிவடைந்த பிறகு இந்தப் பரிவர்த்தனை நடக்க வேண்டும்.
IL1StandardBridge
இந்த இடைமுகம் இங்கே வரையறுக்கப்பட்டுள்ளது (opens in a new tab).
இந்தக் கோப்பு ETH க்கான நிகழ்வு மற்றும் செயல்பாட்டு வரையறைகளைக் கொண்டுள்ளது.
இந்த வரையறைகள் ERC-20 க்காக மேலே IL1ERC20Bridge இல் வரையறுக்கப்பட்டவற்றுக்கு மிகவும் ஒத்தவை.
சில ERC-20 வில்லைகளுக்கு தனிப்பயன் செயலாக்கம் தேவைப்படுவதாலும், நிலையான பாலத்தால் கையாள முடியாததாலும் பாலம் இடைமுகம் இரண்டு கோப்புகளாகப் பிரிக்கப்பட்டுள்ளது.
இந்த வழியில் அத்தகைய வில்லையைக் கையாளும் தனிப்பயன் பாலம் IL1ERC20Bridge ஐச் செயல்படுத்த முடியும், மேலும் ETH ஐயும் பாலம் செய்ய வேண்டியதில்லை.
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.9.0;
import "./IL1ERC20Bridge.sol";
/**
* @title IL1StandardBridge
*/
interface IL1StandardBridge is IL1ERC20Bridge {
/**********
* நிகழ்வுகள் *
**********/
event ETHDepositInitiated(
address indexed _from,
address indexed _to,
uint256 _amount,
bytes _data
);
L1 மற்றும் L2 வில்லை முகவரிகள் இல்லாமல் இருப்பதைத் தவிர, இந்த நிகழ்வு ERC-20 பதிப்பிற்கு (ERC20DepositInitiated) கிட்டத்தட்ட ஒத்ததாக இருக்கும்.
மற்ற நிகழ்வுகள் மற்றும் செயல்பாடுகளுக்கும் இது பொருந்தும்.
event ETHWithdrawalFinalized(
.
.
.
);
/********************
* பொதுச் செயல்பாடுகள் *
********************/
/**
* @dev அடுக்கு 2 (l2) இல் அழைப்பாளரின் இருப்பில் ஒரு குறிப்பிட்ட அளவு ETH ஐ வைப்பீடு செய்யவும்.
.
.
.
*/
function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;
/**
* @dev அடுக்கு 2 (l2) இல் பெறுநரின் இருப்பில் ஒரு குறிப்பிட்ட அளவு ETH ஐ வைப்பீடு செய்யவும்.
.
.
.
*/
function depositETHTo(
address _to,
uint32 _l2Gas,
bytes calldata _data
) external payable;
/*************************
* குறுக்கு-சங்கிலி செயல்பாடுகள் *
*************************/
/**
* @dev அடுக்கு 2 (l2) இலிருந்து அடுக்கு 1 (l1) க்கு திரும்பப் பெறுதலை முடித்து, பெறுநரின் அடுக்கு 1 (l1) ETH வில்லை இருப்பில் நிதியை வரவு வைக்கவும். xDomainMessenger மட்டுமே இந்தச் செயல்பாட்டை அழைக்க முடியும் என்பதால், திரும்பப் பெறுதல் இறுதி செய்யப்படுவதற்கு முன்பு இது ஒருபோதும் அழைக்கப்படாது.
.
.
.
*/
function finalizeETHWithdrawal(
address _from,
address _to,
uint256 _amount,
bytes calldata _data
) external;
}
CrossDomainEnabled
மற்ற அடுக்குக்கு செய்திகளை அனுப்ப இந்த ஒப்பந்தம் (opens in a new tab) இரு பாலங்களாலும் (L1 மற்றும் L2) மரபுரிமையாகப் பெறப்படுகிறது.
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.9.0;
/* இடைமுக இறக்குமதிகள் */
import { ICrossDomainMessenger } from "./ICrossDomainMessenger.sol";
குறுக்கு கள தூதரைப் பயன்படுத்தி மற்ற அடுக்குக்கு செய்திகளை எவ்வாறு அனுப்புவது என்பதை இந்த இடைமுகம் (opens in a new tab) ஒப்பந்தத்திற்குச் சொல்கிறது. இந்தக் குறுக்கு கள தூதர் முற்றிலும் வேறுபட்ட அமைப்பாகும், மேலும் இது தனக்கென ஒரு கட்டுரைக்குத் தகுதியானது, அதை நான் எதிர்காலத்தில் எழுதுவேன் என்று நம்புகிறேன்.
/**
* @title CrossDomainEnabled
* @dev குறுக்கு-களத் தொடர்புகளைச் செய்யும் ஒப்பந்தங்களுக்கான உதவி ஒப்பந்தம்
*
* பயன்படுத்தப்படும் தொகுப்பான்: மரபுரிமையாகப் பெறும் ஒப்பந்தத்தால் வரையறுக்கப்படுகிறது
*/
contract CrossDomainEnabled {
/*************
* மாறிகள் *
*************/
// மற்றொரு களத்திலிருந்து செய்திகளை அனுப்பவும் பெறவும் பயன்படுத்தப்படும் தூதுவர் ஒப்பந்தம்.
address public messenger;
/***************
* ஆக்கி *
***************/
/**
* @param _messenger தற்போதைய அடுக்கில் உள்ள CrossDomainMessenger இன் முகவரி.
*/
constructor(address _messenger) {
messenger = _messenger;
}
ஒப்பந்தம் தெரிந்து கொள்ள வேண்டிய ஒரு அளவுரு, இந்த அடுக்கில் உள்ள குறுக்கு கள தூதரின் முகவரி. இந்த அளவுரு ஆக்கியில் ஒருமுறை அமைக்கப்படுகிறது, மேலும் ஒருபோதும் மாறாது.
/**********************
* செயல்பாட்டு மாற்றிகள் *
**********************/
/**
* மாற்றியமைக்கப்பட்ட செயல்பாட்டை ஒரு குறிப்பிட்ட குறுக்கு-களக் கணக்கால் மட்டுமே அழைக்க முடியும் என்பதைச் செயல்படுத்துகிறது.
* @param _sourceDomainAccount இந்தச் செயல்பாட்டை அழைக்க அங்கீகரிக்கப்பட்ட தொடக்கக் களத்தில் உள்ள ஒரே கணக்கு.
*/
modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {
குறுக்கு கள செய்தியிடலை அது இயங்கும் தொகுதிச்சங்கிலியில் உள்ள எந்தவொரு ஒப்பந்தத்தாலும் அணுக முடியும் (எத்தேரியம் முதன்மை வலைப்பின்னல் அல்லது ஆப்டிமிசம்). ஆனால் ஒவ்வொரு பக்கத்திலும் உள்ள பாலம் மறுபக்கத்திலுள்ள பாலத்திலிருந்து வரும் குறிப்பிட்ட செய்திகளை மட்டுமே நம்ப வேண்டும்.
require(
msg.sender == address(getCrossDomainMessenger()),
"OVM_XCHAIN: messenger contract unauthenticated"
);
பொருத்தமான குறுக்கு கள தூதரிடமிருந்து (messenger, நீங்கள் கீழே பார்ப்பது போல்) வரும் செய்திகளை மட்டுமே நம்ப முடியும்.
require(
getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,
"OVM_XCHAIN: wrong sender of cross-domain message"
);
குறுக்கு கள தூதர் மற்ற அடுக்குடன் ஒரு செய்தியை அனுப்பிய முகவரியை வழங்கும் விதம் .xDomainMessageSender() செயல்பாடு (opens in a new tab) ஆகும்.
செய்தியால் தொடங்கப்பட்ட பரிவர்த்தனையில் இது அழைக்கப்படும் வரை இந்தத் தகவலை வழங்க முடியும்.
நாம் பெற்ற செய்தி மற்ற பாலத்திலிருந்து வந்ததா என்பதை உறுதிப்படுத்த வேண்டும்.
_;
}
/**********************
* உள் செயல்பாடுகள் *
**********************/
/**
* பொதுவாக சேமிப்பகத்திலிருந்து தூதுவரைப் பெறுகிறது. ஒரு துணை ஒப்பந்தம் மேலெழுத (override) தேவைப்பட்டால் இந்தச் செயல்பாடு வெளிப்படுத்தப்படுகிறது.
* @return பயன்படுத்தப்பட வேண்டிய குறுக்கு-களத் தூதுவர் ஒப்பந்தத்தின் முகவரி.
*/
function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {
return ICrossDomainMessenger(messenger);
}
இந்தச் செயல்பாடு குறுக்கு கள தூதரை வழங்குகிறது.
எந்தக் குறுக்கு கள தூதரைப் பயன்படுத்த வேண்டும் என்பதைக் குறிப்பிட ஒரு வழிமுறையைப் பயன்படுத்த இதிலிருந்து மரபுரிமையாகப் பெறும் ஒப்பந்தங்களை அனுமதிக்க, messenger மாறிக்கு பதிலாக ஒரு செயல்பாட்டைப் பயன்படுத்துகிறோம்.
/**
* மற்றொரு களத்தில் உள்ள கணக்கிற்கு ஒரு செய்தியை அனுப்புகிறது
* @param _crossDomainTarget இலக்குக் களத்தில் உத்தேசிக்கப்பட்ட பெறுநர்
* @param _message இலக்கிற்கு அனுப்ப வேண்டிய தரவு (பொதுவாக `onlyFromCrossDomainAccount()` உள்ள செயல்பாட்டிற்கான அழைப்புத் தரவு)
* @param _gasLimit இலக்குக் களத்தில் செய்தியைப் பெறுவதற்கான எரிவாயு வரம்பு (gasLimit).
*/
function sendCrossDomainMessage(
address _crossDomainTarget,
uint32 _gasLimit,
bytes memory _message
இறுதியாக, மற்ற அடுக்குக்கு செய்தியை அனுப்பும் செயல்பாடு.
) internal {
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-நிகழ்வுகள், மறுநுழைவு-benign
ஸ்லித்தர் (opens in a new tab) என்பது பாதிப்புகள் மற்றும் பிற சாத்தியமான சிக்கல்களைத் தேட ஒவ்வொரு ஒப்பந்தத்திலும் ஆப்டிமிசம் இயக்கும் ஒரு நிலையான பகுப்பாய்வி ஆகும். இந்த நிலையில், பின்வரும் வரி இரண்டு பாதிப்புகளைத் தூண்டுகிறது:
getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);
}
}
இந்த நிலையில் மறுநுழைவு பற்றி நாங்கள் கவலைப்படவில்லை, ஸ்லித்தருக்கு அதை அறிய வழி இல்லாவிட்டாலும், getCrossDomainMessenger() நம்பகமான முகவரியை வழங்குகிறது என்பதை நாங்கள் அறிவோம்.
L1 பாலம் ஒப்பந்தம்
இந்த ஒப்பந்தத்திற்கான மூலக் குறியீடு இங்கே உள்ளது (opens in a new tab).
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
இடைமுகங்கள் பிற ஒப்பந்தங்களின் ஒரு பகுதியாக இருக்கலாம், எனவே அவை பரந்த அளவிலான Solidity பதிப்புகளை ஆதரிக்க வேண்டும். ஆனால் பாலம் என்பது நமது ஒப்பந்தமாகும், மேலும் அது எந்த Solidity பதிப்பைப் பயன்படுத்துகிறது என்பதில் நாம் கண்டிப்பாக இருக்க முடியும்.
/* இடைமுக இறக்குமதிகள் */
import { IL1StandardBridge } from "./IL1StandardBridge.sol";
import { IL1ERC20Bridge } from "./IL1ERC20Bridge.sol";
IL1ERC20Bridge மற்றும் IL1StandardBridge ஆகியவை மேலே விளக்கப்பட்டுள்ளன.
import { IL2ERC20Bridge } from "../../L2/messaging/IL2ERC20Bridge.sol";
L2 இல் நிலையான பாலத்தைக் கட்டுப்படுத்த செய்திகளை உருவாக்க இந்த இடைமுகம் (opens in a new tab) நம்மை அனுமதிக்கிறது.
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
இந்த இடைமுகம் (opens in a new tab) ERC-20 ஒப்பந்தங்களைக் கட்டுப்படுத்த நம்மை அனுமதிக்கிறது. இதைப் பற்றி நீங்கள் இங்கே மேலும் படிக்கலாம்.
/* நூலக இறக்குமதிகள் */
import { CrossDomainEnabled } from "../../libraries/bridge/CrossDomainEnabled.sol";
மேலே விளக்கியபடி, இந்த ஒப்பந்தம் அடுக்கக செய்தியிடலுக்குப் பயன்படுத்தப்படுகிறது.
import { Lib_PredeployAddresses } from "../../libraries/constants/Lib_PredeployAddresses.sol";
Lib_PredeployAddresses (opens in a new tab) எப்போதும் ஒரே முகவரியைக் கொண்ட L2 ஒப்பந்தங்களுக்கான முகவரிகளைக் கொண்டுள்ளது. இது L2 இல் உள்ள நிலையான பாலத்தையும் உள்ளடக்கியது.
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
ஓப்பன்செப்பெலினின் முகவரி பயன்பாடுகள் (opens in a new tab). இது ஒப்பந்த முகவரிகள் மற்றும் வெளிப்புறமாகச் சொந்தமான கணக்குகளுக்கு (EOA) சொந்தமானவற்றை வேறுபடுத்தப் பயன்படுகிறது.
இது ஒரு சரியான தீர்வு அல்ல என்பதை நினைவில் கொள்ளவும், ஏனெனில் நேரடி அழைப்புகள் மற்றும் ஒப்பந்தத்தின் ஆக்கியிலிருந்து செய்யப்படும் அழைப்புகளை வேறுபடுத்த எந்த வழியும் இல்லை, ஆனால் குறைந்தபட்சம் இது சில பொதுவான பயனர் பிழைகளை அடையாளம் காணவும் தடுக்கவும் அனுமதிக்கிறது.
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
ERC-20 தரநிலை (opens in a new tab) ஒரு ஒப்பந்தம் தோல்வியைப் புகாரளிக்க இரண்டு வழிகளை ஆதரிக்கிறது:
- மீளமை
falseஐ வழங்கு
இரண்டு நிகழ்வுகளையும் கையாள்வது நமது குறியீட்டை மிகவும் சிக்கலாக்கும், எனவே அதற்குப் பதிலாக ஓப்பன்செப்பெலினின் SafeERC20 (opens in a new tab) ஐப் பயன்படுத்துகிறோம், இது அனைத்து தோல்விகளும் மீளமைக்கப்படுவதை (opens in a new tab) உறுதி செய்கிறது.
/**
* @title L1StandardBridge
* @dev அடுக்கு 1 (l1) ETH மற்றும் ERC-20 பாலம் என்பது வைப்பீடு செய்யப்பட்ட அடுக்கு 1 (l1) நிதிகள் மற்றும் அடுக்கு 2 (l2) இல் பயன்பாட்டில் உள்ள நிலையான வில்லைகளைச் சேமிக்கும் ஒரு ஒப்பந்தம் ஆகும். இது தொடர்புடைய அடுக்கு 2 (l2) பாலத்தை ஒத்திசைக்கிறது, வைப்பீடுகள் குறித்து அதற்குத் தெரிவிக்கிறது மற்றும் புதிதாக இறுதி செய்யப்பட்ட திரும்பப் பெறுதல்களுக்காக அதைக் கவனிக்கிறது.
*
*/
contract L1StandardBridge is IL1StandardBridge, CrossDomainEnabled {
using SafeERC20 for IERC20;
ஒவ்வொரு முறையும் IERC20 இடைமுகத்தைப் பயன்படுத்தும் போது SafeERC20 ரேப்பரைப் பயன்படுத்த வேண்டும் என்பதை இந்த வரியில்தான் குறிப்பிடுகிறோம்.
/********************************
* வெளிப்புற ஒப்பந்தக் குறிப்புகள் *
********************************/
address public l2TokenBridge;
L2StandardBridge இன் முகவரி.
// வைப்பீடு செய்யப்பட்ட அடுக்கு 1 (l1) வில்லையின் இருப்பிற்கு அடுக்கு 1 (l1) வில்லையை அடுக்கு 2 (l2) வில்லையுடன் வரைபடமாக்குகிறது (Maps)
mapping(address => mapping(address => uint256)) public deposits;
இது போன்ற இரட்டை மேப்பிங் (opens in a new tab) என்பது இரு பரிமாண ஸ்பார்ஸ் வரிசையை (opens in a new tab) நீங்கள் வரையறுக்கும் வழியாகும்.
இந்தத் தரவுக் கட்டமைப்பில் உள்ள மதிப்புகள் deposit[L1 token addr][L2 token addr] என அடையாளம் காணப்படுகின்றன.
இயல்புநிலை மதிப்பு பூஜ்ஜியமாகும்.
வெவ்வேறு மதிப்பிற்கு அமைக்கப்பட்ட கலங்கள் மட்டுமே சேமிப்பகத்தில் எழுதப்படும்.
/***************
* ஆக்கி *
***************/
// இந்த ஒப்பந்தம் ஒரு பதிலாள் (proxy) பின்னால் உள்ளது, எனவே ஆக்கி அளவுருக்கள் பயன்படுத்தப்படாது.
constructor() CrossDomainEnabled(address(0)) {}
சேமிப்பகத்தில் உள்ள அனைத்து மாறிகளையும் நகலெடுக்காமல் இந்த ஒப்பந்தத்தை மேம்படுத்த விரும்புகிறோம்.
அதைச் செய்ய, பதிலி ஒப்பந்தத்தால் சேமிக்கப்பட்ட முகவரியைக் கொண்ட தனி ஒப்பந்தத்திற்கு அழைப்புகளைப் பரிமாற்றம் செய்ய delegatecall (opens in a new tab) ஐப் பயன்படுத்துகிறோம் (நீங்கள் மேம்படுத்தும்போது அந்த முகவரியை மாற்ற பதிலியிடம் கூறுகிறீர்கள்).
நீங்கள் delegatecall ஐப் பயன்படுத்தும்போது, சேமிப்பகம் அழைக்கும் ஒப்பந்தத்தின் சேமிப்பகமாகவே இருக்கும், எனவே அனைத்து ஒப்பந்த நிலை மாறிகளின் மதிப்புகளும் பாதிக்கப்படாது.
இந்த முறையின் ஒரு விளைவு என்னவென்றால், delegatecall இன் அழைக்கப்பட்ட ஒப்பந்தத்தின் சேமிப்பகம் பயன்படுத்தப்படுவதில்லை, எனவே அதற்கு அனுப்பப்பட்ட ஆக்கி மதிப்புகள் ஒரு பொருட்டல்ல.
இதன் காரணமாகவே CrossDomainEnabled ஆக்கிக்கு நாம் ஒரு அர்த்தமற்ற மதிப்பை வழங்க முடியும்.
கீழே உள்ள துவக்கம் ஆக்கியிலிருந்து தனித்தனியாக இருப்பதற்கும் இதுவே காரணம்.
/******************
* துவக்கம் *
******************/
/**
* @param _l1messenger குறுக்கு-சங்கிலித் தொடர்புகளுக்குப் பயன்படுத்தப்படும் அடுக்கு 1 (l1) தூதுவர் முகவரி.
* @param _l2TokenBridge அடுக்கு 2 (l2) நிலையான பாலம் முகவரி.
*/
// ஸ்லித்தர்-disable-next-line external-function
இந்த ஸ்லித்தர் சோதனை (opens in a new tab) ஒப்பந்தக் குறியீட்டிலிருந்து அழைக்கப்படாத செயல்பாடுகளை அடையாளம் காட்டுகிறது, எனவே public க்குப் பதிலாக external என அறிவிக்கப்படலாம்.
external செயல்பாடுகளின் எரிவாயு செலவு குறைவாக இருக்கலாம், ஏனெனில் அவை அழைப்புத் தரவில் அளவுருக்களுடன் வழங்கப்படலாம்.
public என அறிவிக்கப்பட்ட செயல்பாடுகளை ஒப்பந்தத்திற்குள்ளிருந்து அணுக முடியும்.
ஒப்பந்தங்கள் அவற்றின் சொந்த அழைப்புத் தரவை மாற்ற முடியாது, எனவே அளவுருக்கள் நினைவகத்தில் இருக்க வேண்டும்.
அத்தகைய செயல்பாடு வெளிப்புறமாக அழைக்கப்படும்போது, அழைப்புத் தரவை நினைவகத்திற்கு நகலெடுப்பது அவசியமாகும், இதற்கு எரிவாயு செலவாகும்.
இந்த நிலையில் செயல்பாடு ஒரு முறை மட்டுமே அழைக்கப்படுகிறது, எனவே திறமையின்மை எங்களுக்கு ஒரு பொருட்டல்ல.
function initialize(address _l1messenger, address _l2TokenBridge) public {
require(messenger == address(0), "Contract has already been initialized.");
initialize செயல்பாடு ஒரு முறை மட்டுமே அழைக்கப்பட வேண்டும்.
L1 குறுக்கு கள தூதர் அல்லது L2 வில்லை பாலத்தின் முகவரி மாறினால், நாங்கள் ஒரு புதிய பதிலியையும் அதை அழைக்கும் புதிய பாலத்தையும் உருவாக்குகிறோம்.
முழு அமைப்பும் மேம்படுத்தப்படும்போது தவிர இது நடக்க வாய்ப்பில்லை, இது மிகவும் அரிதான நிகழ்வாகும்.
இந்தச் செயல்பாட்டை யார் அழைக்கலாம் என்பதைக் கட்டுப்படுத்தும் எந்தப் பொறிமுறையும் இதில் இல்லை என்பதை நினைவில் கொள்ளவும்.
இதன் பொருள், கோட்பாட்டளவில் ஒரு தாக்குபவர் நாங்கள் பதிலியையும் பாலத்தின் முதல் பதிப்பையும் நிலைநிறுத்தும் வரை காத்திருக்கலாம், பின்னர் சட்டபூர்வமான பயனர் செய்வதற்கு முன்பு initialize செயல்பாட்டைப் பெற முந்திச் செயல்படலாம் (opens in a new tab). ஆனால் இதைத் தடுக்க இரண்டு முறைகள் உள்ளன:
- ஒப்பந்தங்கள் நேரடியாக EOA ஆல் நிலைநிறுத்தப்படாமல், அவற்றை உருவாக்கும் மற்றொரு ஒப்பந்தத்தைக் கொண்ட பரிவர்த்தனையில் (opens in a new tab) நிலைநிறுத்தப்பட்டால், முழு செயல்முறையும் அணுவாக இருக்கலாம், மேலும் வேறு எந்தப் பரிவர்த்தனையும் செயல்படுத்தப்படுவதற்கு முன்பு முடிவடையும்.
initializeக்கான சட்டபூர்வமான அழைப்பு தோல்வியுற்றால், புதிதாக உருவாக்கப்பட்ட பதிலி மற்றும் பாலத்தைப் புறக்கணித்து புதியவற்றை உருவாக்குவது எப்போதும் சாத்தியமாகும்.
messenger = _l1messenger;
l2TokenBridge = _l2TokenBridge;
}
பாலம் தெரிந்து கொள்ள வேண்டிய இரண்டு அளவுருக்கள் இவை.
/**************
* வைப்பீடு செய்தல் *
**************/
/** @dev அனுப்புநர் EOA ஆக இருக்கத் தேவைப்படும் மாற்றி. இந்தச் சரிபார்ப்பை initcode மூலம் ஒரு தீங்கிழைக்கும் ஒப்பந்தம் தவிர்க்கலாம், ஆனால் நாம் தவிர்க்க விரும்பும் பயனர் பிழையை இது கவனித்துக்கொள்கிறது.
*/
modifier onlyEOA() {
// ஒப்பந்தங்களிலிருந்து வைப்பீடுகளை நிறுத்தப் பயன்படுகிறது (தவறுதலாக இழக்கப்படும் வில்லைகளைத் தவிர்க்க)
require(!Address.isContract(msg.sender), "Account not EOA");
_;
}
ஓப்பன்செப்பெலினின் Address பயன்பாடுகள் நமக்குத் தேவைப்பட்டதற்குக் காரணம் இதுதான்.
/**
* @dev அடுக்கு 2 (l2) இல் அழைப்பாளரின் இருப்பில் ஒரு குறிப்பிட்ட அளவு ETH ஐ வைப்பீடு செய்ய
* எந்தத் தரவும் இல்லாமல் இந்தச் செயல்பாட்டை அழைக்கலாம்.
* பெறுதல் (receive) செயல்பாடு தரவை எடுக்காது என்பதால், ஒரு பழமைவாத
* இயல்புநிலை அளவு அடுக்கு 2 (l2) க்கு அனுப்பப்படுகிறது.
*/
receive() external payable onlyEOA {
_initiateETHDeposit(msg.sender, msg.sender, 200_000, bytes(""));
}
இந்தச் செயல்பாடு சோதனை நோக்கங்களுக்காக உள்ளது. இது இடைமுக வரையறைகளில் தோன்றவில்லை என்பதைக் கவனியுங்கள் - இது சாதாரண பயன்பாட்டிற்கானது அல்ல.
/**
* @inheritdoc IL1StandardBridge
*/
function depositETH(uint32 _l2Gas, bytes calldata _data) external payable onlyEOA {
_initiateETHDeposit(msg.sender, msg.sender, _l2Gas, _data);
}
/**
* @inheritdoc IL1StandardBridge
*/
function depositETHTo(
address _to,
uint32 _l2Gas,
bytes calldata _data
) external payable {
_initiateETHDeposit(msg.sender, _to, _l2Gas, _data);
}
இந்த இரண்டு செயல்பாடுகளும் உண்மையான ETH வைப்பைக் கையாளும் செயல்பாடான _initiateETHDeposit ஐச் சுற்றியுள்ள ரேப்பர்கள் ஆகும்.
/**
* @dev ETH ஐச் சேமித்து, வைப்பீடு குறித்து அடுக்கு 2 (l2) ETH நுழைவாயிலுக்குத் தெரிவிப்பதன் மூலம் வைப்பீடுகளுக்கான தர்க்கத்தைச் செய்கிறது.
* @param _from அடுக்கு 1 (l1) இல் வைப்பீட்டை எடுக்க வேண்டிய கணக்கு.
* @param _to அடுக்கு 2 (l2) இல் வைப்பீட்டை வழங்க வேண்டிய கணக்கு.
* @param _l2Gas அடுக்கு 2 (l2) இல் வைப்பீட்டை முடிக்கத் தேவையான எரிவாயு வரம்பு.
* @param _data அடுக்கு 2 (l2) க்கு அனுப்ப வேண்டிய விருப்பத் தரவு. இந்தத் தரவு வெளிப்புற ஒப்பந்தங்களுக்கான வசதிக்காக மட்டுமே வழங்கப்படுகிறது. அதிகபட்ச நீளத்தை செயல்படுத்துவதைத் தவிர, இந்த ஒப்பந்தங்கள் அதன் உள்ளடக்கத்தைப் பற்றி எந்த உத்தரவாதத்தையும் வழங்காது.
*/
function _initiateETHDeposit(
address _from,
address _to,
uint32 _l2Gas,
bytes memory _data
) internal {
// finalizeDeposit அழைப்பிற்கான அழைப்புத் தரவை உருவாக்கவும்
bytes memory message = abi.encodeWithSelector(
குறுக்கு கள செய்திகள் செயல்படும் விதம் என்னவென்றால், இலக்கு ஒப்பந்தம் செய்தியை அதன் அழைப்புத் தரவாகக் கொண்டு அழைக்கப்படுகிறது.
Solidity ஒப்பந்தங்கள் எப்போதும் அவற்றின் அழைப்புத் தரவை ABI விவரக்குறிப்புகளுக்கு (opens in a new tab) ஏற்ப விளக்குகின்றன.
Solidity செயல்பாடு abi.encodeWithSelector (opens in a new tab) அந்த அழைப்புத் தரவை உருவாக்குகிறது.
IL2ERC20Bridge.finalizeDeposit.selector,
address(0),
Lib_PredeployAddresses.OVM_ETH,
_from,
_to,
msg.value,
_data
);
இந்த அளவுருக்களுடன் finalizeDeposit செயல்பாட்டை (opens in a new tab) அழைப்பதே இங்குள்ள செய்தியாகும்:
| அளவுரு | மதிப்பு | பொருள் |
|---|---|---|
| _l1Token | address(0) | L1 இல் ETH (இது ERC-20 வில்லை அல்ல) ஐக் குறிக்கும் சிறப்பு மதிப்பு |
| _l2Token | Lib_PredeployAddresses.OVM_ETH | ஆப்டிமிசத்தில் ETH ஐ நிர்வகிக்கும் L2 ஒப்பந்தம், 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000 (இந்த ஒப்பந்தம் உள் ஆப்டிமிசம் பயன்பாட்டிற்கு மட்டுமே) |
| _from | _from | ETH ஐ அனுப்பும் L1 இல் உள்ள முகவரி |
| _to | _to | ETH ஐப் பெறும் L2 இல் உள்ள முகவரி |
| amount | msg.value | அனுப்பப்பட்ட Wei அளவு (இது ஏற்கனவே பாலத்திற்கு அனுப்பப்பட்டுள்ளது) |
| _data | _data | வைப்புடன் இணைக்க வேண்டிய கூடுதல் தரவு |
// அழைப்புத் தரவை அடுக்கு 2 (l2) க்குள் அனுப்பவும்
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-நிகழ்வுகள்
sendCrossDomainMessage(l2TokenBridge, _l2Gas, message);
குறுக்கு கள தூதர் மூலம் செய்தியை அனுப்பவும்.
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-நிகழ்வுகள்
emit ETHDepositInitiated(_from, _to, msg.value, _data);
}
இந்தப் பரிமாற்றத்தைக் கேட்கும் எந்தவொரு பரவலாக்கப்பட்ட செயலிக்கும் (dapp) தெரிவிக்க ஒரு நிகழ்வை வெளியிடவும்.
/**
* @inheritdoc IL1ERC20Bridge
*/
function depositERC20(
.
.
.
) external virtual onlyEOA {
_initiateERC20Deposit(_l1Token, _l2Token, msg.sender, msg.sender, _amount, _l2Gas, _data);
}
/**
* @inheritdoc IL1ERC20Bridge
*/
function depositERC20To(
.
.
.
) external virtual {
_initiateERC20Deposit(_l1Token, _l2Token, msg.sender, _to, _amount, _l2Gas, _data);
}
இந்த இரண்டு செயல்பாடுகளும் உண்மையான ERC-20 வைப்பைக் கையாளும் செயல்பாடான _initiateERC20Deposit ஐச் சுற்றியுள்ள ரேப்பர்கள் ஆகும்.
/**
* @dev வைப்பீடு குறித்து அடுக்கு 2 (l2) வைப்பீடு செய்யப்பட்ட வில்லை
* ஒப்பந்தத்திற்குத் தெரிவிப்பதன் மூலமும், அடுக்கு 1 (l1) நிதிகளைப் பூட்ட ஒரு கையாளுநரை அழைப்பதன் மூலமும் (எ.கா., transferFrom) வைப்பீடுகளுக்கான தர்க்கத்தைச் செய்கிறது.
*
* @param _l1Token நாம் வைப்பீடு செய்யும் அடுக்கு 1 (l1) ERC-20 இன் முகவரி
* @param _l2Token அடுக்கு 1 (l1) க்கு தொடர்புடைய அடுக்கு 2 (l2) ERC-20 இன் முகவரி
* @param _from அடுக்கு 1 (l1) இல் வைப்பீட்டை எடுக்க வேண்டிய கணக்கு
* @param _to அடுக்கு 2 (l2) இல் வைப்பீட்டை வழங்க வேண்டிய கணக்கு
* @param _amount வைப்பீடு செய்ய வேண்டிய ERC-20 இன் அளவு.
* @param _l2Gas அடுக்கு 2 (l2) இல் வைப்பீட்டை முடிக்கத் தேவையான எரிவாயு வரம்பு.
* @param _data அடுக்கு 2 (l2) க்கு அனுப்ப வேண்டிய விருப்பத் தரவு. இந்தத் தரவு வெளிப்புற ஒப்பந்தங்களுக்கான வசதிக்காக மட்டுமே வழங்கப்படுகிறது. அதிகபட்ச நீளத்தை செயல்படுத்துவதைத் தவிர, இந்த ஒப்பந்தங்கள் அதன் உள்ளடக்கத்தைப் பற்றி எந்த உத்தரவாதத்தையும் வழங்காது.
*/
function _initiateERC20Deposit(
address _l1Token,
address _l2Token,
address _from,
address _to,
uint256 _amount,
uint32 _l2Gas,
bytes calldata _data
) internal {
இந்தச் செயல்பாடு சில முக்கியமான வேறுபாடுகளுடன் மேலே உள்ள _initiateETHDeposit ஐப் போன்றது.
முதல் வித்தியாசம் என்னவென்றால், இந்தச் செயல்பாடு வில்லை முகவரிகள் மற்றும் பரிமாற்றம் செய்ய வேண்டிய தொகையை அளவுருக்களாகப் பெறுகிறது.
ETH ஐப் பொறுத்தவரை, பாலத்திற்கான அழைப்பு ஏற்கனவே பாலம் கணக்கிற்கு சொத்தைப் பரிமாற்றம் செய்வதை உள்ளடக்கியது (msg.value).
// அடுக்கு 1 (l1) இல் வைப்பீடு தொடங்கப்படும்போது, அடுக்கு 1 (l1) பாலம் எதிர்கால
// திரும்பப் பெறுதல்களுக்காக நிதியைத் தனக்கே பரிமாற்றம் செய்கிறது. safeTransferFrom ஒப்பந்தத்தில் குறியீடு உள்ளதா என்பதையும் சரிபார்க்கிறது, எனவே இது தோல்வியடையும்
// _from ஒரு EOA அல்லது முகவரி(0) ஆக இருந்தால்.
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-நிகழ்வுகள், மறுநுழைவு-benign
IERC20(_l1Token).safeTransferFrom(_from, address(this), _amount);
ERC-20 வில்லைப் பரிமாற்றங்கள் ETH இலிருந்து வேறுபட்ட செயல்முறையைப் பின்பற்றுகின்றன:
- பயனர் (
_from) பொருத்தமான வில்லைகளைப் பரிமாற்றம் செய்ய பாலத்திற்கு ஒரு அனுமதித்தொகையை வழங்குகிறார். - பயனர் வில்லை ஒப்பந்தத்தின் முகவரி, தொகை போன்றவற்றுடன் பாலத்தை அழைக்கிறார்.
- வைப்புச் செயல்முறையின் ஒரு பகுதியாக பாலம் வில்லைகளை (தனக்குத்தானே) பரிமாற்றம் செய்கிறது.
முதல் படி கடைசி இரண்டிலிருந்து தனிப் பரிவர்த்தனையில் நடக்கலாம்.
இருப்பினும், முந்திச் செயல்படுதல் ஒரு சிக்கல் அல்ல, ஏனெனில் _initiateERC20Deposit ஐ அழைக்கும் இரண்டு செயல்பாடுகளும் (depositERC20 மற்றும் depositERC20To) msg.sender ஐ _from அளவுருவாகக் கொண்டு மட்டுமே இந்தச் செயல்பாட்டை அழைக்கின்றன.
// _l2Token.finalizeDeposit(_to, _amount) க்கான அழைப்புத் தரவை உருவாக்கவும்
bytes memory message = abi.encodeWithSelector(
IL2ERC20Bridge.finalizeDeposit.selector,
_l1Token,
_l2Token,
_from,
_to,
_amount,
_data
);
// அழைப்புத் தரவை அடுக்கு 2 (l2) க்குள் அனுப்பவும்
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-நிகழ்வுகள், மறுநுழைவு-benign
sendCrossDomainMessage(l2TokenBridge, _l2Gas, message);
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-benign
deposits[_l1Token][_l2Token] = deposits[_l1Token][_l2Token] + _amount;
வைப்புச் செய்யப்பட்ட வில்லைகளின் அளவை deposits தரவுக் கட்டமைப்பில் சேர்க்கவும்.
அதே L1 ERC-20 வில்லைக்கு ஒத்த பல முகவரிகள் L2 இல் இருக்கலாம், எனவே வைப்புகளைக் கண்காணிக்க L1 ERC-20 வில்லையின் பாலத்தின் இருப்பைப் பயன்படுத்துவது போதாது.
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-நிகழ்வுகள்
emit ERC20DepositInitiated(_l1Token, _l2Token, _from, _to, _amount, _data);
}
/*************************
* குறுக்கு-சங்கிலி செயல்பாடுகள் *
*************************/
/**
* @inheritdoc IL1StandardBridge
*/
function finalizeETHWithdrawal(
address _from,
address _to,
uint256 _amount,
bytes calldata _data
L2 பாலம் L2 குறுக்கு கள தூதருக்கு ஒரு செய்தியை அனுப்புகிறது, இது L1 குறுக்கு கள தூதரை இந்தச் செயல்பாட்டை அழைக்கச் செய்கிறது (நிச்சயமாக, செய்தியை இறுதி செய்யும் பரிவர்த்தனை (opens in a new tab) L1 இல் சமர்ப்பிக்கப்பட்டவுடன்).
) external onlyFromCrossDomainAccount(l2TokenBridge) {
இது குறுக்கு கள தூதரிடமிருந்து வரும் மற்றும் L2 வில்லை பாலத்திலிருந்து உருவாகும் ஒரு சட்டபூர்வமான செய்தி என்பதை உறுதிப்படுத்தவும். இந்தச் செயல்பாடு பாலத்திலிருந்து ETH ஐத் திரும்பப் பெறப் பயன்படுகிறது, எனவே இது அங்கீகரிக்கப்பட்ட அழைப்பாளரால் மட்டுமே அழைக்கப்படுகிறது என்பதை நாம் உறுதிப்படுத்த வேண்டும்.
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-நிகழ்வுகள்
(bool success, ) = _to.call{ value: _amount }(new bytes(0));
ETH ஐப் பரிமாற்றம் செய்வதற்கான வழி, msg.value இல் உள்ள Wei அளவுடன் பெறுநரை அழைப்பதாகும்.
require(success, "TransferHelper::safeTransferETH: ETH transfer failed");
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-நிகழ்வுகள்
emit ETHWithdrawalFinalized(_from, _to, _amount, _data);
திரும்பப் பெறுதல் பற்றிய ஒரு நிகழ்வை வெளியிடவும்.
}
/**
* @inheritdoc IL1ERC20Bridge
*/
function finalizeERC20Withdrawal(
address _l1Token,
address _l2Token,
address _from,
address _to,
uint256 _amount,
bytes calldata _data
) external onlyFromCrossDomainAccount(l2TokenBridge) {
இந்தச் செயல்பாடு ERC-20 வில்லைகளுக்கான தேவையான மாற்றங்களுடன் மேலே உள்ள finalizeETHWithdrawal ஐப் போன்றது.
deposits[_l1Token][_l2Token] = deposits[_l1Token][_l2Token] - _amount;
deposits தரவுக் கட்டமைப்பைப் புதுப்பிக்கவும்.
// அடுக்கு 1 (l1) இல் திரும்பப் பெறுதல் இறுதி செய்யப்படும்போது, அடுக்கு 1 (l1) பாலம் நிதியைத் திரும்பப் பெறுபவருக்குப் பரிமாற்றம் செய்கிறது
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-நிகழ்வுகள்
IERC20(_l1Token).safeTransfer(_to, _amount);
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-நிகழ்வுகள்
emit ERC20WithdrawalFinalized(_l1Token, _l2Token, _from, _to, _amount, _data);
}
/*****************************
* தற்காலிகமானது - ETH ஐ இடம்பெயர்த்தல் *
*****************************/
/**
* @dev கணக்கில் ETH இருப்பைச் சேர்க்கிறது. இது பழைய நுழைவாயிலிலிருந்து புதிய நுழைவாயிலுக்கு ETH ஐ
* இடம்பெயர்க்க அனுமதிக்கும் நோக்கம் கொண்டது.
* குறிப்பு: பழைய ஒப்பந்தத்திலிருந்து இடம்பெயர்ந்த ETH ஐப் பெற முடியும் என்பதற்காக இது ஒரு மேம்படுத்தலுக்கு மட்டுமே விடப்பட்டுள்ளது
*/
function donateETH() external payable {}
}
பாலத்தின் முந்தைய செயலாக்கம் இருந்தது.
அந்தச் செயலாக்கத்திலிருந்து இதற்கு மாறியபோது, நாங்கள் அனைத்து சொத்துகளையும் நகர்த்த வேண்டியிருந்தது.
ERC-20 வில்லைகளை அப்படியே நகர்த்தலாம்.
இருப்பினும், ஒரு ஒப்பந்தத்திற்கு ETH ஐப் பரிமாற்றம் செய்ய உங்களுக்கு அந்த ஒப்பந்தத்தின் ஒப்புதல் தேவை, அதைத்தான் donateETH நமக்கு வழங்குகிறது.
L2 இல் ERC-20 வில்லைகள்
ஒரு ERC-20 வில்லை நிலையான பாலத்தில் பொருந்துவதற்கு, அது நிலையான பாலத்தை, மற்றும் நிலையான பாலத்தை மட்டுமே வில்லைகளை அச்சிட அனுமதிக்க வேண்டும். ஆப்டிமிசத்தில் புழக்கத்தில் உள்ள வில்லைகளின் எண்ணிக்கை L1 பாலம் ஒப்பந்தத்திற்குள் பூட்டப்பட்டுள்ள வில்லைகளின் எண்ணிக்கைக்கு சமமாக இருப்பதை பாலங்கள் உறுதி செய்ய வேண்டியிருப்பதால் இது அவசியமாகும். L2 இல் அதிக வில்லைகள் இருந்தால், சில பயனர்களால் தங்கள் சொத்துகளை மீண்டும் L1 க்கு பாலம் செய்ய முடியாது. நம்பகமான பாலத்திற்குப் பதிலாக, நாங்கள் அடிப்படையில் பின்ன இருப்பு வங்கியியலை (opens in a new tab) மீண்டும் உருவாக்குவோம். L1 இல் அதிக வில்லைகள் இருந்தால், அந்த வில்லைகளில் சில பாலம் ஒப்பந்தத்திற்குள் என்றென்றும் பூட்டப்பட்டிருக்கும், ஏனெனில் L2 வில்லைகளை எரிக்காமல் அவற்றை வெளியிட வழி இல்லை.
IL2StandardERC20
நிலையான பாலத்தைப் பயன்படுத்தும் L2 இல் உள்ள ஒவ்வொரு ERC-20 வில்லையும் இந்த இடைமுகத்தை (opens in a new tab) வழங்க வேண்டும், இது நிலையான பாலத்திற்குத் தேவையான செயல்பாடுகள் மற்றும் நிகழ்வுகளைக் கொண்டுள்ளது.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
நிலையான ERC-20 இடைமுகம் (opens in a new tab) mint மற்றும் burn செயல்பாடுகளை உள்ளடக்கவில்லை.
அந்த முறைகள் ERC-20 தரநிலையால் (opens in a new tab) கோரப்படவில்லை, இது வில்லைகளை உருவாக்குவதற்கும் அழிப்பதற்குமான வழிமுறைகளைக் குறிப்பிடாமல் விட்டுவிடுகிறது.
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
ஒரு ஒப்பந்தம் என்ன செயல்பாடுகளை வழங்குகிறது என்பதைக் குறிப்பிட ERC-165 இடைமுகம் (opens in a new tab) பயன்படுத்தப்படுகிறது. நீங்கள் தரநிலையை இங்கே படிக்கலாம் (opens in a new tab).
interface IL2StandardERC20 is IERC20, IERC165 {
function l1Token() external returns (address);
இந்தச் செயல்பாடு இந்த ஒப்பந்தத்திற்குப் பாலம் செய்யப்பட்ட L1 வில்லையின் முகவரியை வழங்குகிறது. எதிர் திசையில் இதேபோன்ற செயல்பாடு எங்களிடம் இல்லை என்பதை நினைவில் கொள்க. L2 ஆதரவு செயல்படுத்தப்பட்டபோது திட்டமிடப்பட்டதா இல்லையா என்பதைப் பொருட்படுத்தாமல், எந்தவொரு L1 வில்லையையும் பாலம் செய்ய நாம் முடியும்.
function mint(address _to, uint256 _amount) external;
function burn(address _from, uint256 _amount) external;
event Mint(address indexed _account, uint256 _amount);
event Burn(address indexed _account, uint256 _amount);
}
வில்லைகளை அச்சிட (உருவாக்க) மற்றும் எரிக்க (அழிக்க) செயல்பாடுகள் மற்றும் நிகழ்வுகள். வில்லைகளின் எண்ணிக்கை சரியாக இருப்பதை (L1 இல் பூட்டப்பட்டுள்ள வில்லைகளின் எண்ணிக்கைக்கு சமம்) உறுதி செய்ய இந்தச் செயல்பாடுகளை இயக்கக்கூடிய ஒரே நிறுவனமாக பாலம் இருக்க வேண்டும்.
L2StandardERC20
இது IL2StandardERC20 இடைமுகத்தின் எங்கள் செயலாக்கமாகும் (opens in a new tab).
உங்களுக்கு ஏதேனும் தனிப்பயன் தர்க்கம் தேவைப்படாவிட்டால், நீங்கள் இதைப் பயன்படுத்த வேண்டும்.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
ஓப்பன்செப்பெலின் ERC-20 ஒப்பந்தம் (opens in a new tab). ஆப்டிமிசம் சக்கரத்தை மீண்டும் கண்டுபிடிப்பதில் நம்பிக்கை கொள்ளவில்லை, குறிப்பாக சக்கரம் நன்கு தணிக்கை செய்யப்பட்டு சொத்துகளை வைத்திருக்க போதுமான நம்பகத்தன்மையுடன் இருக்க வேண்டியிருக்கும் போது.
import "./IL2StandardERC20.sol";
contract L2StandardERC20 is IL2StandardERC20, ERC20 {
address public l1Token;
address public l2Bridge;
இவை நமக்குத் தேவையான இரண்டு கூடுதல் உள்ளமைவு அளவுருக்கள் ஆகும், மேலும் ERC-20 பொதுவாக இவற்றைக் கோருவதில்லை.
/**
* @param _l2Bridge அடுக்கு 2 (l2) நிலையான பாலத்தின் முகவரி.
* @param _l1Token தொடர்புடைய அடுக்கு 1 (l1) வில்லையின் முகவரி.
* @param _name ERC-20 பெயர்.
* @param _symbol ERC-20 குறியீடு.
*/
constructor(
address _l2Bridge,
address _l1Token,
string memory _name,
string memory _symbol
) ERC20(_name, _symbol) {
l1Token = _l1Token;
l2Bridge = _l2Bridge;
}
முதலில் நாம் மரபுரிமையாகப் பெறும் ஒப்பந்தத்திற்கான ஆக்கியை அழைக்கவும் (ERC20(_name, _symbol)) பின்னர் நமது சொந்த மாறிகளை அமைக்கவும்.
modifier onlyL2Bridge() {
require(msg.sender == l2Bridge, "Only L2 Bridge can mint and burn");
_;
}
// ஸ்லித்தர்-disable-next-line external-function
function supportsInterface(bytes4 _interfaceId) public pure returns (bool) {
bytes4 firstSupportedInterface = bytes4(keccak256("supportsInterface(bytes4)")); // ERC165
bytes4 secondSupportedInterface = IL2StandardERC20.l1Token.selector ^
IL2StandardERC20.mint.selector ^
IL2StandardERC20.burn.selector;
return _interfaceId == firstSupportedInterface || _interfaceId == secondSupportedInterface;
}
ERC-165 (opens in a new tab) செயல்படும் விதம் இதுதான். ஒவ்வொரு இடைமுகமும் ஆதரிக்கப்படும் செயல்பாடுகளின் எண்ணிக்கையாகும், மேலும் அந்தச் செயல்பாடுகளின் ABI செயல்பாட்டுத் தேர்வாளர்களின் (opens in a new tab) பிரத்தியேக அல்லது (exclusive or) (opens in a new tab) என அடையாளம் காணப்படுகிறது.
L2 பாலம் அது சொத்துகளை அனுப்பும் ERC-20 ஒப்பந்தம் ஒரு IL2StandardERC20 என்பதை உறுதிப்படுத்த ERC-165 ஐ ஒரு பகுத்தறிவுச் சரிபார்ப்பாகப் பயன்படுத்துகிறது.
குறிப்பு: முரட்டு ஒப்பந்தம் supportsInterface க்கு தவறான பதில்களை வழங்குவதைத் தடுக்க எதுவும் இல்லை, எனவே இது ஒரு பகுத்தறிவுச் சரிபார்ப்பு பொறிமுறையாகும், பாதுகாப்பு பொறிமுறை அல்ல.
// ஸ்லித்தர்-disable-next-line external-function
function mint(address _to, uint256 _amount) public virtual onlyL2Bridge {
_mint(_to, _amount);
emit Mint(_to, _amount);
}
// ஸ்லித்தர்-disable-next-line external-function
function burn(address _from, uint256 _amount) public virtual onlyL2Bridge {
_burn(_from, _amount);
emit Burn(_from, _amount);
}
}
L2 பாலம் மட்டுமே சொத்துகளை அச்சிடவும் எரிக்கவும் அனுமதிக்கப்படுகிறது.
_mint மற்றும் _burn ஆகியவை உண்மையில் ஓப்பன்செப்பெலின் ERC-20 ஒப்பந்தத்தில் வரையறுக்கப்பட்டுள்ளன.
அந்த ஒப்பந்தம் அவற்றை வெளிப்புறமாக வெளிப்படுத்தாது, ஏனெனில் வில்லைகளை அச்சிடுவதற்கும் எரிப்பதற்குமான நிபந்தனைகள் ERC-20 ஐப் பயன்படுத்துவதற்கான வழிகளின் எண்ணிக்கையைப் போலவே வேறுபட்டவை.
L2 பாலம் குறியீடு
இது ஆப்டிமிசத்தில் பாலத்தை இயக்கும் குறியீடு. இந்த ஒப்பந்தத்திற்கான ஆதாரம் இங்கே உள்ளது (opens in a new tab).
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/* இடைமுக இறக்குமதிகள் */
import { IL1StandardBridge } from "../../L1/messaging/IL1StandardBridge.sol";
import { IL1ERC20Bridge } from "../../L1/messaging/IL1ERC20Bridge.sol";
import { IL2ERC20Bridge } from "./IL2ERC20Bridge.sol";
IL2ERC20Bridge (opens in a new tab) இடைமுகம் நாம் மேலே பார்த்த L1 இணையானதற்கு மிகவும் ஒத்திருக்கிறது. இரண்டு குறிப்பிடத்தக்க வேறுபாடுகள் உள்ளன:
- L1 இல் நீங்கள் வைப்புகளைத் தொடங்கி திரும்பப் பெறுதல்களை இறுதி செய்கிறீர்கள். இங்கே நீங்கள் திரும்பப் பெறுதல்களைத் தொடங்கி வைப்புகளை இறுதி செய்கிறீர்கள்.
- L1 இல் ETH மற்றும் ERC-20 வில்லைகளை வேறுபடுத்துவது அவசியம். L2 இல் நாம் இரண்டிற்கும் ஒரே செயல்பாடுகளைப் பயன்படுத்தலாம், ஏனெனில் உள்நாட்டில் ஆப்டிமிசத்தில் உள்ள ETH இருப்புகள் 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000 (opens in a new tab) முகவரியுடன் ERC-20 வில்லையாகக் கையாளப்படுகின்றன.
/* நூலக இறக்குமதிகள் */
import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import { CrossDomainEnabled } from "../../libraries/bridge/CrossDomainEnabled.sol";
import { Lib_PredeployAddresses } from "../../libraries/constants/Lib_PredeployAddresses.sol";
/* ஒப்பந்த இறக்குமதிகள் */
import { IL2StandardERC20 } from "../../standards/IL2StandardERC20.sol";
/**
* @title L2StandardBridge
* @dev அடுக்கு 2 (l2) நிலையான பாலம் என்பது அடுக்கு 1 (l1) மற்றும் அடுக்கு 2 (l2) க்கு இடையில் ETH மற்றும் ERC-20 மாற்றங்களைச் செயல்படுத்த
* அடுக்கு 1 (l1) நிலையான பாலத்துடன் இணைந்து செயல்படும் ஒரு ஒப்பந்தம் ஆகும்.
* அடுக்கு 1 (l1) நிலையான பாலத்தில் வைப்பீடுகள் குறித்துக் கேட்கும்போது, இந்த ஒப்பந்தம் புதிய வில்லைகளுக்கான அச்சிடுபவராக (minter) செயல்படுகிறது.
* திரும்பப் பெறுவதற்காக உத்தேசிக்கப்பட்ட வில்லைகளை எரிப்பவராகவும் (burner) இந்த ஒப்பந்தம் செயல்படுகிறது, அடுக்கு 1 (l1) நிதிகளை வெளியிடுமாறு அடுக்கு 1 (l1)
* பாலத்திற்குத் தெரிவிக்கிறது.
*/
contract L2StandardBridge is IL2ERC20Bridge, CrossDomainEnabled {
/********************************
* வெளிப்புற ஒப்பந்தக் குறிப்புகள் *
********************************/
address public l1TokenBridge;
L1 பாலத்தின் முகவரியைக் கண்காணிக்கவும். L1 இணையானதற்கு மாறாக, இங்கே நமக்கு இந்த மாறி தேவை என்பதை நினைவில் கொள்க. L1 பாலத்தின் முகவரி முன்கூட்டியே தெரியாது.
/***************
* ஆக்கி *
***************/
/**
* @param _l2CrossDomainMessenger இந்த ஒப்பந்தத்தால் பயன்படுத்தப்படும் குறுக்கு-களத் தூதுவர்.
* @param _l1TokenBridge முதன்மைச் சங்கிலியில் பயன்படுத்தப்பட்ட அடுக்கு 1 (l1) பாலத்தின் முகவரி.
*/
constructor(address _l2CrossDomainMessenger, address _l1TokenBridge)
CrossDomainEnabled(_l2CrossDomainMessenger)
{
l1TokenBridge = _l1TokenBridge;
}
/***************
* திரும்பப் பெறுதல் *
***************/
/**
* @inheritdoc IL2ERC20Bridge
*/
function withdraw(
address _l2Token,
uint256 _amount,
uint32 _l1Gas,
bytes calldata _data
) external virtual {
_initiateWithdrawal(_l2Token, msg.sender, msg.sender, _amount, _l1Gas, _data);
}
/**
* @inheritdoc IL2ERC20Bridge
*/
function withdrawTo(
address _l2Token,
address _to,
uint256 _amount,
uint32 _l1Gas,
bytes calldata _data
) external virtual {
_initiateWithdrawal(_l2Token, msg.sender, _to, _amount, _l1Gas, _data);
}
இந்த இரண்டு செயல்பாடுகளும் திரும்பப் பெறுதல்களைத் தொடங்குகின்றன. L1 வில்லை முகவரியைக் குறிப்பிடத் தேவையில்லை என்பதை நினைவில் கொள்க. L2 வில்லைகள் L1 இணையான முகவரியை நமக்குச் சொல்லும் என்று எதிர்பார்க்கப்படுகிறது.
/**
* @dev வில்லையை எரிப்பதன் மூலமும், திரும்பப் பெறுதல் குறித்து அடுக்கு 1 (l1) வில்லை நுழைவாயிலுக்குத்
* தெரிவிப்பதன் மூலமும் திரும்பப் பெறுதல்களுக்கான தர்க்கத்தைச் செய்கிறது.
* @param _l2Token திரும்பப் பெறுதல் தொடங்கப்பட்ட அடுக்கு 2 (l2) வில்லையின் முகவரி.
* @param _from அடுக்கு 2 (l2) இல் திரும்பப் பெறுதலை எடுக்க வேண்டிய கணக்கு.
* @param _to அடுக்கு 1 (l1) இல் திரும்பப் பெறுதலை வழங்க வேண்டிய கணக்கு.
* @param _amount திரும்பப் பெற வேண்டிய வில்லையின் அளவு.
* @param _l1Gas பயன்படுத்தப்படவில்லை, ஆனால் சாத்தியமான முன்னோக்கிய பொருந்தக்கூடிய பரிசீலனைகளுக்காகச் சேர்க்கப்பட்டுள்ளது.
* @param _data அடுக்கு 1 (l1) க்கு அனுப்ப வேண்டிய விருப்பத் தரவு. இந்தத் தரவு வெளிப்புற ஒப்பந்தங்களுக்கான வசதிக்காக மட்டுமே வழங்கப்படுகிறது. அதிகபட்ச நீளத்தை செயல்படுத்துவதைத் தவிர, இந்த ஒப்பந்தங்கள் அதன் உள்ளடக்கத்தைப் பற்றி எந்த உத்தரவாதத்தையும் வழங்காது.
*/
function _initiateWithdrawal(
address _l2Token,
address _from,
address _to,
uint256 _amount,
uint32 _l1Gas,
bytes calldata _data
) internal {
// திரும்பப் பெறுதல் தொடங்கப்படும்போது, அடுத்தடுத்த அடுக்கு 2 (l2) பயன்பாட்டைத் தடுக்க, திரும்பப் பெறுபவரின் நிதியை நாங்கள் எரிக்கிறோம்
// பயன்பாடு
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-நிகழ்வுகள்
IL2StandardERC20(_l2Token).burn(msg.sender, _amount);
நாங்கள் _from அளவுருவை நம்பி இல்லை என்பதைக் கவனியுங்கள், ஆனால் msg.sender ஐ நம்பியுள்ளோம், இது போலியாக உருவாக்குவது மிகவும் கடினம் (எனக்குத் தெரிந்தவரை சாத்தியமற்றது).
// l1TokenBridge.finalizeERC20Withdrawal(_to, _amount) க்கான அழைப்புத் தரவை உருவாக்கவும்
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-நிகழ்வுகள்
address l1Token = IL2StandardERC20(_l2Token).l1Token();
bytes memory message;
if (_l2Token == Lib_PredeployAddresses.OVM_ETH) {
L1 இல் ETH மற்றும் ERC-20 ஐ வேறுபடுத்துவது அவசியம்.
message = abi.encodeWithSelector(
IL1StandardBridge.finalizeETHWithdrawal.selector,
_from,
_to,
_amount,
_data
);
} else {
message = abi.encodeWithSelector(
IL1ERC20Bridge.finalizeERC20Withdrawal.selector,
l1Token,
_l2Token,
_from,
_to,
_amount,
_data
);
}
// அடுக்கு 1 (l1) பாலத்திற்குச் செய்தியை அனுப்பவும்
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-நிகழ்வுகள்
sendCrossDomainMessage(l1TokenBridge, _l1Gas, message);
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-நிகழ்வுகள்
emit WithdrawalInitiated(l1Token, _l2Token, msg.sender, _to, _amount, _data);
}
/************************************
* குறுக்கு-சங்கிலி செயல்பாடு: வைப்பீடு செய்தல் *
************************************/
/**
* @inheritdoc IL2ERC20Bridge
*/
function finalizeDeposit(
address _l1Token,
address _l2Token,
address _from,
address _to,
uint256 _amount,
bytes calldata _data
இந்தச் செயல்பாடு L1StandardBridge ஆல் அழைக்கப்படுகிறது.
) external virtual onlyFromCrossDomainAccount(l1TokenBridge) {
செய்தியின் ஆதாரம் சட்டபூர்வமானதா என்பதை உறுதிப்படுத்தவும்.
இது முக்கியமானது, ஏனெனில் இந்தச் செயல்பாடு _mint ஐ அழைக்கிறது மற்றும் L1 இல் பாலம் வைத்திருக்கும் வில்லைகளால் ஈடுசெய்யப்படாத வில்லைகளை வழங்கப் பயன்படுத்தப்படலாம்.
// இலக்கு வில்லை இணக்கமாக உள்ளதா என்பதைச் சரிபார்த்து,
// அடுக்கு 1 (l1) இல் வைப்பீடு செய்யப்பட்ட வில்லை இங்குள்ள அடுக்கு 2 (l2) வைப்பீடு செய்யப்பட்ட வில்லைப் பிரதிநிதித்துவத்துடன் பொருந்துகிறதா என்பதைச் சரிபார்க்கவும்
if (
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-நிகழ்வுகள்
ERC165Checker.supportsInterface(_l2Token, 0x1d1d8b63) &&
_l1Token == IL2StandardERC20(_l2Token).l1Token()
பகுத்தறிவுச் சரிபார்ப்புகள்:
- சரியான இடைமுகம் ஆதரிக்கப்படுகிறது
- L2 ERC-20 ஒப்பந்தத்தின் L1 முகவரி வில்லைகளின் L1 ஆதாரத்துடன் பொருந்துகிறது
) {
// வைப்பீடு இறுதி செய்யப்படும்போது, அடுக்கு 2 (l2) இல் உள்ள கணக்கில் அதே அளவிலான
// வில்லைகளை நாங்கள் வரவு வைக்கிறோம்.
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-நிகழ்வுகள்
IL2StandardERC20(_l2Token).mint(_to, _amount);
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-நிகழ்வுகள்
emit DepositFinalized(_l1Token, _l2Token, _from, _to, _amount, _data);
பகுத்தறிவுச் சரிபார்ப்புகள் தேர்ச்சி பெற்றால், வைப்பை இறுதி செய்யவும்:
- வில்லைகளை அச்சிடு
- பொருத்தமான நிகழ்வை வெளியிடு
} else {
// வைப்பீடு செய்யப்படும் அடுக்கு 2 (l2) வில்லை சரியான முகவரி குறித்து முரண்படுகிறது
// அதன் அடுக்கு 1 (l1) வில்லையின், அல்லது சரியான இடைமுகத்தை ஆதரிக்கவில்லை.
// ஒரு தீங்கிழைக்கும் அடுக்கு 2 (l2) வில்லை இருந்தால், அல்லது ஒரு பயனர் எப்படியாவது
// வைப்பீடு செய்யத் தவறான அடுக்கு 2 (l2) வில்லை முகவரியைக் குறிப்பிட்டால் மட்டுமே இது நிகழ வேண்டும்.
// எந்தவொரு சந்தர்ப்பத்திலும், நாங்கள் செயல்முறையை இங்கு நிறுத்தி, ஒரு திரும்பப் பெறுதல்
// செய்தியை உருவாக்குகிறோம், இதனால் பயனர்கள் சில சந்தர்ப்பங்களில் தங்கள் நிதியை வெளியே எடுக்க முடியும்.
// தீங்கிழைக்கும் வில்லை ஒப்பந்தங்களை முற்றிலுமாகத் தடுக்க எந்த வழியும் இல்லை, ஆனால் இது
// பயனர் பிழையைக் கட்டுப்படுத்துகிறது மற்றும் சில வகையான தீங்கிழைக்கும் ஒப்பந்த நடத்தைகளைத் தணிக்கிறது.
தவறான L2 வில்லை முகவரியைப் பயன்படுத்துவதன் மூலம் பயனர் கண்டறியக்கூடிய பிழையைச் செய்தால், நாங்கள் வைப்பை ரத்துசெய்து L1 இல் வில்லைகளைத் திருப்பித் தர விரும்புகிறோம். L2 இலிருந்து இதைச் செய்வதற்கான ஒரே வழி, பிழை சவால் காலத்திற்குக் காத்திருக்க வேண்டிய ஒரு செய்தியை அனுப்புவதாகும், ஆனால் வில்லைகளை நிரந்தரமாக இழப்பதை விட இது பயனருக்கு மிகவும் சிறந்தது.
bytes memory message = abi.encodeWithSelector(
IL1ERC20Bridge.finalizeERC20Withdrawal.selector,
_l1Token,
_l2Token,
_to, // வைப்பீட்டை அனுப்புநருக்கே திருப்பி அனுப்ப _to மற்றும் _from ஆகியவற்றை இங்கு மாற்றினோம்
_from,
_amount,
_data
);
// அடுக்கு 1 (l1) பாலத்திற்குச் செய்தியை அனுப்பவும்
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-நிகழ்வுகள்
sendCrossDomainMessage(l1TokenBridge, 0, message);
// ஸ்லித்தர்-disable-next-line மறுநுழைவு-நிகழ்வுகள்
emit DepositFailed(_l1Token, _l2Token, _from, _to, _amount, _data);
}
}
}
முடிவுரை
நிலையான பாலம் என்பது சொத்துப் பரிமாற்றங்களுக்கான மிகவும் நெகிழ்வான பொறிமுறையாகும். இருப்பினும், இது மிகவும் பொதுவானது என்பதால் இது எப்போதும் பயன்படுத்த எளிதான பொறிமுறையாக இருக்காது. குறிப்பாகத் திரும்பப் பெறுதல்களுக்கு, பெரும்பாலான பயனர்கள் சவால் காலத்திற்குக் காத்திருக்காத மற்றும் திரும்பப் பெறுதலை இறுதி செய்ய மெர்கல் சான்று தேவைப்படாத மூன்றாம் தரப்பு பாலங்களைப் (opens in a new tab) பயன்படுத்த விரும்புகிறார்கள்.
இந்தப் பாலங்கள் பொதுவாக L1 இல் சொத்துகளை வைத்திருப்பதன் மூலம் செயல்படுகின்றன, அவை ஒரு சிறிய கட்டணத்தில் உடனடியாக வழங்குகின்றன (பெரும்பாலும் நிலையான பாலம் திரும்பப் பெறுவதற்கான எரிவாயு செலவை விடக் குறைவு). பாலம் (அல்லது அதை இயக்குபவர்கள்) L1 சொத்துகளில் பற்றாக்குறை ஏற்படும் என்று எதிர்பார்க்கும்போது, அது L2 இலிருந்து போதுமான சொத்துகளைப் பரிமாற்றம் செய்கிறது. இவை மிகப் பெரிய திரும்பப் பெறுதல்கள் என்பதால், திரும்பப் பெறும் செலவு ஒரு பெரிய தொகையில் கடனடைக்கப்படுகிறது மற்றும் இது மிகச் சிறிய சதவீதமாகும்.
அடுக்கு 2 எவ்வாறு செயல்படுகிறது மற்றும் தெளிவான மற்றும் பாதுகாப்பான Solidity குறியீட்டை எவ்வாறு எழுதுவது என்பதைப் பற்றி மேலும் புரிந்துகொள்ள இந்தக் கட்டுரை உங்களுக்கு உதவியிருக்கும் என்று நம்புகிறோம்.
எனது மேலும் பல பணிகளுக்கு இங்கே பார்க்கவும் (opens in a new tab).