ஸ்கேம் டோக்கன்களால் பயன்படுத்தப்படும் சில தந்திரங்கள் மற்றும் அவற்றை எவ்வாறு கண்டறிவது
இந்த டுடோரியலில், மோசடிக்காரர்கள் பயன்படுத்தும் சில தந்திரங்களையும் அவர்கள் அவற்றை எவ்வாறு செயல்படுத்துகிறார்கள் என்பதையும் பார்க்க ஒரு ஸ்கேம் டோக்கனைopens in a new tab பிரித்தறிகிறோம். டுடோரியலின் முடிவில், நீங்கள் ERC-20 டோக்கன் கான்ட்ராக்ட்கள், அவற்றின் திறன்கள் மற்றும் சந்தேகம் ஏன் அவசியம் என்பது பற்றிய விரிவான பார்வையைப் பெறுவீர்கள். பிறகு, அந்த ஸ்கேம் டோக்கன் மூலம் வெளியிடப்படும் நிகழ்வுகளைப் பார்த்து, அது முறையானது அல்ல என்பதைத் தானாகவே எவ்வாறு அடையாளம் காணலாம் என்று பார்ப்போம்.
ஸ்கேம் டோக்கன்கள் - அவை என்ன, மக்கள் ஏன் அவற்றைச் செய்கிறார்கள், மற்றும் அவற்றை எவ்வாறு தவிர்ப்பது
எதீரியத்தைப் பயன்படுத்துவதற்கான பொதுவான பயன்பாடுகளில் ஒன்றாக, ஒரு குழு தங்கள் சொந்த நாணயமாக ஒரு பரிமாற்றக்கூடிய டோக்கனை உருவாக்குவது உள்ளது. எனினும், எங்கு நியாயமான பயன்பாடுகள் மதிப்பை உருவாக்குகின்றனவோ, அங்கு இந்த மதிப்பைத் திருட முயற்சிக்கும் குற்றவாளிகளும் உள்ளனர்.
ஒரு பயனர் கண்ணோட்டத்தில் இந்த பொருள் பற்றி ethereum.org-இல் மற்றோரிடத்தில் நீங்கள் மேலும் படிக்கலாம். இந்த டுடோரியல் ஒரு ஸ்கேம் டோக்கனை அது எப்படி செய்யப்படுகிறது மற்றும் எப்படி கண்டறியப்படலாம் என்பதைப் பார்ப்பதற்காகப் பிரித்தறிவதில் கவனம் செலுத்துகிறது.
wARB ஒரு மோசடி என்று எனக்கு எப்படித் தெரியும்?
நாம் பிரித்தறியும் டோக்கன் wARBopens in a new tab ஆகும், இது முறையான ARB டோக்கனுக்குopens in a new tab சமமானதாகப் பாசாங்கு செய்கிறது.
எது முறையான டோக்கன் என்பதைத் தெரிந்து கொள்வதற்கான எளிதான வழி, அதன் தொடக்க நிறுவனமான, Arbitrumopens in a new tab-ஐப் பார்ப்பதுதான். முறையான முகவரிகள் அவர்களின் ஆவணப்படுத்தலில்opens in a new tab குறிப்பிடப்பட்டுள்ளன.
மூலக் குறியீடு ஏன் கிடைக்கிறது?
பொதுவாக மற்றவர்களை மோசடி செய்ய முயற்சிக்கும் நபர்கள் ரகசியமாக இருப்பார்கள் என்று நாம் எதிர்பார்ப்போம், மேலும் உண்மையில் பல ஸ்கேம் டோக்கன்களுக்கு அவற்றின் குறியீடு கிடைக்காது (எடுத்துக்காட்டாக, இதுopens in a new tab மற்றும் இதுopens in a new tab).
இருப்பினும், முறையான டோக்கன்கள் பொதுவாக அவற்றின் மூலக் குறியீட்டை வெளியிடுகின்றன, எனவே முறையானதாகத் தோன்றுவதற்காக ஸ்கேம் டோக்கன்களின் ஆசிரியர்களும் சில சமயங்களில் அதையே செய்கிறார்கள். wARBopens in a new tab என்பது மூலக் குறியீடு கிடைக்கும் டோக்கன்களில் ஒன்றாகும், இது அதைப் புரிந்துகொள்வதை எளிதாக்குகிறது.
கான்ட்ராக்ட் வரிசைப்படுத்துநர்கள் மூலக் குறியீட்டை வெளியிடுவதா இல்லையா என்பதைத் தேர்வுசெய்ய முடியும் என்றாலும், அவர்களால் தவறான மூலக் குறியீட்டை வெளியிட முடியாது. பிளாக் எக்ஸ்புளோரர் வழங்கப்பட்ட மூலக் குறியீட்டை சுயாதீனமாகத் தொகுக்கிறது, மேலும் சரியான அதே பைட் குறியீடு கிடைக்கவில்லை என்றால், அது அந்த மூலக் குறியீட்டை நிராகரிக்கிறது. Etherscan தளத்தில் இதுபற்றி மேலும் படிக்கலாம்opens in a new tab.
முறையான ERC-20 டோக்கன்களுடன் ஒப்பீடு
இந்த டோக்கனை முறையான ERC-20 டோக்கன்களுடன் ஒப்பிடப் போகிறோம். முறையான ERC-20 டோக்கன்கள் பொதுவாக எவ்வாறு எழுதப்படுகின்றன என்பது உங்களுக்குத் தெரியாவிட்டால், இந்த டுடோரியலைப் பார்க்கவும்.
சிறப்புரிமை பெற்ற முகவரிகளுக்கான மாறிலிகள்
கான்ட்ராக்ட்களுக்கு சில நேரங்களில் சிறப்புரிமை பெற்ற முகவரிகள் தேவைப்படும். நீண்ட காலப் பயன்பாட்டிற்காக வடிவமைக்கப்பட்ட கான்ட்ராக்ட்கள் சில சிறப்புரிமை பெற்ற முகவரிகளை அந்த முகவரிகளை மாற்ற அனுமதிக்கின்றன, எடுத்துக்காட்டாக, ஒரு புதிய மல்டிசிக் கான்ட்ராக்டின் பயன்பாட்டை இயக்க. இதைச் செய்ய பல வழிகள் உள்ளன.
HOP டோக்கன் கான்ட்ராக்ட்opens in a new tab Ownableopens in a new tab முறையைப் பயன்படுத்துகிறது. சிறப்புரிமை பெற்ற முகவரி ஸ்டோரேஜில், _owner எனப்படும் ஒரு ஃபீல்டில் வைக்கப்பட்டுள்ளது (மூன்றாவது கோப்பான, Ownable.sol ஐப் பார்க்கவும்).
1abstract contract Ownable is Context {2 address private _owner;3 .4 .5 .6}ARB டோக்கன் கான்ட்ராக்ட்டில்opens in a new tab நேரடியாக ஒரு சிறப்புரிமை பெற்ற முகவரி இல்லை. இருப்பினும், அதற்கு ஒன்று தேவையில்லை. அது முகவரி 0xb50721bcf8d664c30412cfbc6cf7a15145234ad1opens in a new tab-இல் ஒரு proxyopens in a new tab-இன் பின்னால் அமர்ந்திருக்கிறது. அந்த கான்ட்ராக்ட்டிற்கு ஒரு சிறப்புரிமை பெற்ற முகவரி உள்ளது (நான்காவது கோப்பான, ERC1967Upgrade.sol ஐப் பார்க்கவும்) அதை மேம்படுத்தல்களுக்குப் பயன்படுத்தலாம்.
1 /**2 * @dev EIP1967 நிர்வாக ஸ்லாட்டில் ஒரு புதிய முகவரியைச் சேமிக்கிறது.3 */4 function _setAdmin(address newAdmin) private {5 require(newAdmin != address(0), "ERC1967: new admin is the zero address");6 StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;7 }இதற்கு மாறாக, wARB கான்ட்ராக்ட்டில் கடினக் குறியீடு செய்யப்பட்ட contract_owner உள்ளது.
1contract WrappedArbitrum is Context, IERC20 {2 .3 .4 .5 address deployer = 0xB50721BCf8d664c30412Cfbc6cf7a15145234ad1;6 address public contract_owner = 0xb40dE7b1beE84Ff2dc22B70a049A07A13a411A33;7 .8 .9 .10}அனைத்தையும் காட்டுஇந்த கான்ட்ராக்ட் உரிமையாளர்opens in a new tab என்பது வெவ்வேறு நேரங்களில் வெவ்வேறு கணக்குகளால் கட்டுப்படுத்தக்கூடிய ஒரு கான்ட்ராக்ட் அல்ல, மாறாக ஒரு வெளிப்புறமாகச் சொந்தமான கணக்கு. இதன் பொருள், இது ஒருவேளை ஒரு தனிநபரால் குறுகிய காலப் பயன்பாட்டிற்காக வடிவமைக்கப்பட்டிருக்கலாம், மாறாக மதிப்புமிக்கதாக இருக்கும் ஒரு ERC-20-ஐக் கட்டுப்படுத்துவதற்கான நீண்ட காலத் தீர்வாக அல்ல.
உண்மையில், Etherscan-இல் பார்த்தால், மோசடிக்காரர் இந்த கான்ட்ராக்ட்டை மே 19, 2023 அன்று 12 மணிநேரம் மட்டுமே பயன்படுத்தியிருப்பதைக் காணலாம் (முதல் பரிவர்த்தனைopens in a new tab முதல் கடைசி பரிவர்த்தனைopens in a new tab வரை).
போலியான _transfer செயல்பாடு
ஒரு உள் _transfer செயல்பாட்டைப் பயன்படுத்தி உண்மையான பரிமாற்றங்கள் நடப்பது வழக்கம்.
wARB-இல் இந்த செயல்பாடு கிட்டத்தட்ட முறையானதாகத் தெரிகிறது:
1 function _transfer(address sender, address recipient, uint256 amount) internal virtual{2 require(sender != address(0), "ERC20: transfer from the zero address");3 require(recipient != address(0), "ERC20: transfer to the zero address");45 _beforeTokenTransfer(sender, recipient, amount);67 _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");8 _balances[recipient] = _balances[recipient].add(amount);9 if (sender == contract_owner){10 sender = deployer;11 }12 emit Transfer(sender, recipient, amount);13 }அனைத்தையும் காட்டுசந்தேகத்திற்குரிய பகுதி:
1 if (sender == contract_owner){2 sender = deployer;3 }4 emit Transfer(sender, recipient, amount);கான்ட்ராக்ட் உரிமையாளர் டோக்கன்களை அனுப்பினால், Transfer நிகழ்வு அவை deployer இடமிருந்து வருவதாக ஏன் காட்டுகிறது?
இருப்பினும், ஒரு முக்கியமான சிக்கல் உள்ளது. இந்த _transfer செயல்பாட்டை யார் அழைக்கிறார்கள்? அதை வெளியிலிருந்து அழைக்க முடியாது, அது internal எனக் குறிக்கப்பட்டுள்ளது. மேலும் நம்மிடம் உள்ள குறியீட்டில் _transfer-க்கு எந்த அழைப்புகளும் இல்லை. தெளிவாக, இது ஒரு ஏமாற்று வேலையாக இங்கே உள்ளது.
1 function transfer(address recipient, uint256 amount) public virtual override returns (bool) {2 _f_(_msgSender(), recipient, amount);3 return true;4 }56 function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {7 _f_(sender, recipient, amount);8 _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));9 return true;10 }அனைத்தையும் காட்டுடோக்கன்களைப் பரிமாற்ற அழைக்கப்படும் transfer மற்றும் transferFrom ஆகிய செயல்பாடுகளைப் பார்க்கும்போது, அவை முற்றிலும் வேறுபட்ட ஒரு செயல்பாடான, _f_-ஐ அழைப்பதை நாம் காண்கிறோம்.
உண்மையான _f_ செயல்பாடு
1 function _f_(address sender, address recipient, uint256 amount) internal _mod_(sender,recipient,amount) virtual {2 require(sender != address(0), "ERC20: transfer from the zero address");3 require(recipient != address(0), "ERC20: transfer to the zero address");45 _beforeTokenTransfer(sender, recipient, amount);67 _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");8 _balances[recipient] = _balances[recipient].add(amount);9 if (sender == contract_owner){1011 sender = deployer;12 }13 emit Transfer(sender, recipient, amount);14 }அனைத்தையும் காட்டுஇந்தச் செயல்பாட்டில் இரண்டு சாத்தியமான அபாய எச்சரிக்கைகள் உள்ளன.
-
செயல்பாட்டு மாற்றிopens in a new tab
_mod_-இன் பயன்பாடு. இருப்பினும், மூலக் குறியீட்டைப் பார்க்கும்போது,_mod_உண்மையில் பாதிப்பில்லாதது என்பதைக் காண்கிறோம்.1modifier _mod_(address sender, address recipient, uint256 amount){2 _;3} -
_transferஇல் நாம் பார்த்த அதே சிக்கல், அதாவதுcontract_ownerடோக்கன்களை அனுப்பும்போது அவைdeployerஇடமிருந்து வருவது போல் தோன்றுவது.
போலியான நிகழ்வுகள் செயல்பாடு dropNewTokens
இப்போது நாம் ஒரு உண்மையான மோசடி போல் தோன்றும் ஒன்றிற்கு வருகிறோம். நான் வாசிப்புத்திறனுக்காக செயல்பாட்டை சற்று திருத்தியுள்ளேன், ஆனால் அது செயல்பாட்டு ரீதியாகச் சமமானது.
1function dropNewTokens(address uPool,2 address[] memory eReceiver,3 uint256[] memory eAmounts) public auth()இந்த செயல்பாட்டிற்கு auth() மாற்றி உள்ளது, அதாவது இது கான்ட்ராக்ட் உரிமையாளரால் மட்டுமே அழைக்கப்பட முடியும்.
1modifier auth() {2 require(msg.sender == contract_owner, "Not allowed to interact");3 _;4}இந்தக் கட்டுப்பாடு மிகவும் சரியானது, ஏனென்றால் தோராயமான கணக்குகள் டோக்கன்களை விநியோகிப்பதை நாம் விரும்ப மாட்டோம். இருப்பினும், செயல்பாட்டின் மீதமுள்ள பகுதி சந்தேகத்திற்குரியது.
1{2 for (uint256 i = 0; i < eReceiver.length; i++) {3 emit Transfer(uPool, eReceiver[i], eAmounts[i]);4 }5}ஒரு பூல் கணக்கிலிருந்து பெறுநர்களின் ஒரு வரிசைக்கு தொகைகளின் ஒரு வரிசையைப் பரிமாற்றுவதற்கான ஒரு செயல்பாடு மிகவும் சரியானது. ஊதியப் பட்டியல், ஏர்டிராப்கள் போன்ற பல பயன்பாட்டு நிகழ்வுகளில், நீங்கள் ஒரு மூலத்திலிருந்து பல இடங்களுக்கு டோக்கன்களை விநியோகிக்க விரும்புவீர்கள். பல பரிவர்த்தனைகளை வெளியிடுவதற்குப் பதிலாக ஒற்றைப் பரிவர்த்தனையில் செய்வது (கேஸ் அளவில்) மலிவானது, அல்லது ஒரே பரிவர்த்தனையின் பகுதியாக வேறுபட்ட கான்ட்ராக்ட்டிலிருந்து ERC-20-ஐ பலமுறை அழைப்பதைக் காட்டிலும்.
இருப்பினும், dropNewTokens அதைச் செய்யாது. அது Transfer நிகழ்வுகளைopens in a new tab வெளியிடுகிறது, ஆனால் உண்மையில் எந்த டோக்கன்களையும் பரிமாற்றுவதில்லை. உண்மையில் நடக்காத ஒரு பரிமாற்றத்தைப் பற்றி ஆஃப்செயின் பயன்பாடுகளிடம் கூறி அவற்றை குழப்புவதற்கு முறையான காரணம் எதுவும் இல்லை.
எரிக்கும் Approve செயல்பாடு
ERC-20 கான்ட்ராக்ட்கள் அனுமதிகளுக்காக ஒரு approve செயல்பாட்டைக் கொண்டிருக்க வேண்டும், மேலும் உண்மையில் நமது ஸ்கேம் டோக்கனுக்கு அத்தகைய செயல்பாடு உள்ளது, மேலும் அது சரியாகவும் இருக்கிறது. இருப்பினும், Solidity சி-யிலிருந்து வந்ததால், அது கேஸ் முக்கியத்துவம் வாய்ந்தது. "Approve" மற்றும் "approve" ஆகியவை வெவ்வேறு ஸ்டிரிங்குகள் ஆகும்.
மேலும், இந்தச் செயல்பாடு approve-உடன் தொடர்புடையது அல்ல.
1 function Approve(2 address[] memory holders)டோக்கன் வைத்திருப்பவர்களுக்கான முகவரிகளின் ஒரு வரிசையுடன் இந்தச் செயல்பாடு அழைக்கப்படுகிறது.
1 public approver() {approver() மாற்றி contract_owner மட்டுமே இந்தச் செயல்பாட்டை அழைக்க அனுமதிக்கப்படுவதை உறுதிசெய்கிறது (கீழே பார்க்கவும்).
1 for (uint256 i = 0; i < holders.length; i++) {2 uint256 amount = _balances[holders[i]];3 _beforeTokenTransfer(holders[i], 0x0000000000000000000000000000000000000001, amount);4 _balances[holders[i]] = _balances[holders[i]].sub(amount,5 "ERC20: burn amount exceeds balance");6 _balances[0x0000000000000000000000000000000000000001] =7 _balances[0x0000000000000000000000000000000000000001].add(amount);8 }9 }10அனைத்தையும் காட்டுஒவ்வொரு வைத்திருப்பாளர் முகவரிக்கும் இந்தச் செயல்பாடு வைத்திருப்பவரின் முழு இருப்புத்தொகையையும் 0x00...01 என்ற முகவரிக்கு நகர்த்துகிறது, செயல்திறனுடன் அதை எரிக்கிறது (தரநிலையின் உண்மையான burn மொத்த விநியோகத்தையும் மாற்றுகிறது, மேலும் டோக்கன்களை 0x00...00-க்கு பரிமாற்றுகிறது). அதாவது contract_owner எந்தவொரு பயனரின் சொத்துக்களையும் அகற்ற முடியும். அது ஒரு ஆளுகை டோக்கனில் நீங்கள் விரும்பும் ஒரு அம்சமாகத் தெரியவில்லை.
குறியீட்டுத் தர சிக்கல்கள்
இந்தக் குறியீட்டுத் தரச் சிக்கல்கள் இந்தக் குறியீடு ஒரு மோசடி என்று நிரூபிக்கவில்லை, ஆனால் அவை அதைச் சந்தேகத்திற்குரியதாகத் தோற்றுவிக்கின்றன. Arbitrum போன்ற ஒழுங்கமைக்கப்பட்ட நிறுவனங்கள் பொதுவாக இவ்வளவு மோசமான குறியீட்டை வெளியிடுவதில்லை.
mount செயல்பாடு
தரநிலைகளில்opens in a new tab இது குறிப்பிடப்படவில்லை என்றாலும், பொதுவாகப் புதிய டோக்கன்களை உருவாக்கும் செயல்பாடு mint என்று அழைக்கப்படுகிறது.
wARB கன்ஸ்ட்ரக்டரைப் பார்த்தால், மிண்ட் செயல்பாடு ஏதோ காரணத்திற்காக mount எனப் பெயர் மாற்றப்பட்டிருப்பதைக் காணலாம், மேலும் செயல்திறனுக்காக முழுத் தொகைக்கும் ஒரே முறை அழைப்பதற்குப் பதிலாக ஆரம்ப விநியோகத்தில் ஐந்தில் ஒரு பங்குடன் ஐந்து முறை அழைக்கப்படுகிறது.
1 constructor () public {23 _name = "Wrapped Arbitrum";4 _symbol = "wARB";5 _decimals = 18;6 uint256 initialSupply = 1000000000000;78 mount(deployer, initialSupply*(10**18)/5);9 mount(deployer, initialSupply*(10**18)/5);10 mount(deployer, initialSupply*(10**18)/5);11 mount(deployer, initialSupply*(10**18)/5);12 mount(deployer, initialSupply*(10**18)/5);13 }அனைத்தையும் காட்டுmount செயல்பாடுமே சந்தேகத்திற்குரியதுதான்.
1 function mount(address account, uint256 amount) public {2 require(msg.sender == contract_owner, "ERC20: mint to the zero address");requireஐப் பார்க்கும்போது, கான்ட்ராக்ட் உரிமையாளருக்கு மட்டுமே மிண்ட் செய்ய அனுமதிக்கப்படுகிறது என்பதைக் காண்கிறோம். அது முறையானது. ஆனால் பிழைச் செய்தி உரிமையாளருக்கு மட்டுமே மிண்ட் செய்ய அனுமதி அல்லது அதுபோன்ற ஏதேனும் ஒன்றாக இருக்க வேண்டும். அதற்குப் பதிலாக, அது தொடர்பில்லாத ERC20: பூஜ்ஜிய முகவரிக்கு மிண்ட் என்று உள்ளது. பூஜ்ஜிய முகவரிக்கு மிண்ட் செய்வதற்கான சரியான சோதனை require(account != address(0), "<error message>") ஆகும், அதை இந்த கான்ட்ராக்ட் ஒருபோதும் சரிபார்க்கக் கவலைப்படவில்லை.
1 _totalSupply = _totalSupply.add(amount);2 _balances[contract_owner] = _balances[contract_owner].add(amount);3 emit Transfer(address(0), account, amount);4 }மிண்டிங் உடன் நேரடியாகத் தொடர்புடைய மேலும் இரண்டு சந்தேகத்திற்கிடமான உண்மைகள் உள்ளன:
-
ஒரு
accountபாராமீட்டர் உள்ளது, இது அநேகமாக மிண்ட் செய்யப்பட்ட தொகையைப் பெற வேண்டிய கணக்காக இருக்கலாம். ஆனால் உண்மையில் அதிகரிக்கும் இருப்புcontract_owner-இன் உடையது. -
அதிகரித்த இருப்பு
contract_owner-க்கு சொந்தமானது என்றாலும், வெளியிடப்பட்ட நிகழ்வுaccount-க்கு ஒரு பரிமாற்றத்தைக் காட்டுகிறது.
ஏன் auth மற்றும் approver இரண்டும்? எதுவும் செய்யாத mod ஏன்?
இந்த கான்ட்ராக்ட்டில் மூன்று மாற்றிகள் உள்ளன: _mod_, auth, மற்றும் approver.
1 modifier _mod_(address sender, address recipient, uint256 amount){2 _;3 }_mod_ மூன்று பாராமீட்டர்களை எடுத்துக்கொள்கிறது மற்றும் அவற்றுடன் எதையும் செய்வதில்லை. ஏன் இது இருக்கிறது?
1 modifier auth() {2 require(msg.sender == contract_owner, "Not allowed to interact");3 _;4 }56 modifier approver() {7 require(msg.sender == contract_owner, "Not allowed to interact");8 _;9 }அனைத்தையும் காட்டுauth மற்றும் approver அதிகப் பொருள் தருகின்றன, ஏனெனில் அவை கான்ட்ராக்ட் contract_owner ஆல் அழைக்கப்பட்டதா என்பதைச் சரிபார்க்கின்றன. மிண்டிங் போன்ற சில சிறப்புரிமை பெற்ற செயல்கள் அந்தக் கணக்கிற்கு மட்டுமே கட்டுப்படுத்தப்பட்டிருக்க வேண்டும் என்று நாங்கள் எதிர்பார்ப்போம். இருப்பினும், துல்லியமாக ஒரே காரியத்தைச் செய்யும் இரண்டு தனித்தனி செயல்பாடுகளைக் கொண்டிருப்பதில் என்ன பயன்?
நாம் தானாக என்ன கண்டறிய முடியும்?
Etherscan ஐப் பார்ப்பதன் மூலம் wARB ஒரு ஸ்கேம் டோக்கன் என்பதைக் காணலாம். இருப்பினும், அது ஒரு மையப்படுத்தப்பட்ட தீர்வு. கோட்பாட்டளவில், Etherscan ஐத் திசைதிருப்பலாம் அல்லது ஹேக் செய்யலாம். ஒரு டோக்கன் முறையானதா இல்லையா என்பதை சுயாதீனமாக கண்டுபிடிக்க முடிவது நல்லது.
ஒரு ERC-20 டோக்கன் சந்தேகத்திற்கிடமானதா (ஒரு மோசடி அல்லது மிக மோசமாக எழுதப்பட்டது) என்பதை அடையாளம் காண, அவை வெளியிடும் நிகழ்வுகளைப் பார்ப்பதன் மூலம் சில தந்திரங்களைப் பயன்படுத்தலாம்.
சந்தேகத்திற்கிடமான Approval நிகழ்வுகள்
Approval நிகழ்வுகள்opens in a new tab ஒரு நேரடி கோரிக்கையுடன் மட்டுமே நடக்க வேண்டும் (Transfer நிகழ்வுகள்opens in a new tab போலல்லாமல் அவை ஒரு அனுமதியின் விளைவாக நடக்கலாம்). இந்த சிக்கல் மற்றும் கோரிக்கைகள் ஒரு ஒப்பந்தத்தால் மத்தியஸ்தம் செய்யப்படுவதற்குப் பதிலாக ஏன் நேரடியாக இருக்க வேண்டும் என்பதற்கான விரிவான விளக்கத்திற்கு Solidity ஆவணங்களைப் பார்க்கவும்opens in a new tab.
இதன் பொருள், ஒரு வெளிப்புறமாகச் சொந்தமான கணக்கிலிருந்து செலவழிப்பதை அங்கீகரிக்கும் Approval நிகழ்வுகள் அந்தக் கணக்கில் இருந்து உருவாகும் மற்றும் அதன் இலக்கு ERC-20 ஒப்பந்தமாக இருக்கும் பரிவர்த்தனைகளிலிருந்து வர வேண்டும். வெளிப்புறமாக சொந்தமான கணக்கிலிருந்து வேறு எந்த வகையான அங்கீகாரமும் சந்தேகத்திற்குரியது.
viemopens in a new tab மற்றும் TypeScriptopens in a new tab ஐப் பயன்படுத்தி இந்த வகையான நிகழ்வை அடையாளம் காணும் ஒரு புரோகிராம் இதோopens in a new tab, இது டைப் பாதுகாப்புடன் கூடிய JavaScript மாறுபாடு ஆகும். அதை இயக்க:
.env.example-ஐ.env-க்கு நகலெடுக்கவும்.- ஒரு Ethereum மெயின்நெட் முனைக்கான URL-ஐ வழங்க
.envஐத் திருத்தவும். - தேவையான தொகுப்புகளை நிறுவ
pnpm installஐ இயக்கவும். - சந்தேகத்திற்கிடமான அங்கீகாரங்களைத் தேட
pnpm susApprovalஐ இயக்கவும்.
இதோ வரிக்கு வரி விளக்கம்:
1import {2 Address,3 TransactionReceipt,4 createPublicClient,5 http,6 parseAbiItem,7} from "viem"8import { mainnet } from "viem/chains"viem-இலிருந்து வகை வரையறைகள், செயல்பாடுகள் மற்றும் சங்கிலி வரையறையை இறக்குமதி செய்யவும்.
1import { config } from "dotenv"2config()URL ஐப் பெற .env-ஐப் படிக்கவும்.
1const client = createPublicClient({2 chain: mainnet,3 transport: http(process.env.URL),4})ஒரு Viem வாடிக்கையாளரை உருவாக்கவும். பிளாக்செயினில் இருந்து நாம் படிக்க மட்டுமே வேண்டும், எனவே இந்த வாடிக்கையாளருக்கு ஒரு தனிப்பட்ட விசை தேவையில்லை.
1const testedAddress = "0xb047c8032b99841713b8e3872f06cf32beb27b82"2const fromBlock = 16859812n3const toBlock = 16873372nசந்தேகத்திற்கிடமான ERC-20 ஒப்பந்தத்தின் முகவரி, மற்றும் நாம் நிகழ்வுகளைத் தேடும் தொகுதிகள். முனை வழங்குநர்கள் பொதுவாக நிகழ்வுகளைப் படிக்கும் நமது திறனைக் கட்டுப்படுத்துகிறார்கள், ஏனெனில் அலைவரிசை விலை உயர்ந்ததாக இருக்கலாம். அதிர்ஷ்டவசமாக wARB பதினெட்டு மணி நேரத்திற்கு பயன்பாட்டில் இல்லை, எனவே நாம் அனைத்து நிகழ்வுகளையும் தேடலாம் (மொத்தம் 13 மட்டுமே இருந்தன).
1const approvalEvents = await client.getLogs({2 address: testedAddress,3 fromBlock,4 toBlock,5 event: parseAbiItem(6 "event Approval(address indexed _owner, address indexed _spender, uint256 _value)"7 ),8})Viem-இடம் நிகழ்வு தகவல்களைக் கேட்க இதுவே வழி. ஃபீல்டு பெயர்கள் உட்பட சரியான நிகழ்வு கையொப்பத்தை நாம் வழங்கும்போது, அது நமக்காக நிகழ்வைப் பிரித்தெடுக்கிறது.
1const isContract = async (addr: Address): boolean =>2 await client.getBytecode({ address: addr })நமது வழிமுறை வெளிப்புறமாக சொந்தமான கணக்குகளுக்கு மட்டுமே பொருந்தும். client.getBytecode மூலம் ஏதேனும் பைட் குறியீடு திருப்பியளிக்கப்பட்டால், இது ஒரு ஒப்பந்தம் என்று பொருள், நாம் அதைத் தவிர்க்க வேண்டும்.
நீங்கள் இதற்கு முன் TypeScript ஐப் பயன்படுத்தவில்லை என்றால், செயல்பாட்டு வரையறை சற்று விசித்திரமாகத் தோன்றலாம். முதல் (மற்றும் ஒரே) பாராமீட்டருக்கு addr என்று பெயர் என்று மட்டும் நாம் கூறவில்லை, அது Address வகையைச் சேர்ந்தது என்றும் கூறுகிறோம். இதேபோல், : boolean பகுதி செயல்பாட்டின் திருப்பியளிக்கும் மதிப்பு ஒரு பூலியன் என்று TypeScript-இடம் கூறுகிறது.
1const getEventTxn = async (ev: Event): TransactionReceipt =>2 await client.getTransactionReceipt({ hash: ev.transactionHash })இந்தச் செயல்பாடு ஒரு நிகழ்விலிருந்து பரிவர்த்தனை ரசீதைப் பெறுகிறது. பரிவர்த்தனையின் இலக்கு என்ன என்பதை நாம் அறிவதை உறுதிசெய்ய ரசீது தேவை.
1const suspiciousApprovalEvent = async (ev : Event) : (Event | null) => {இது மிக முக்கியமான செயல்பாடு, ஒரு நிகழ்வு சந்தேகத்திற்கிடமானதா இல்லையா என்பதை உண்மையில் தீர்மானிப்பது இதுதான். திருப்பியளிக்கும் வகை, (Event | null), இந்தச் செயல்பாடு Event அல்லது null ஐத் திருப்பியளிக்கலாம் என்று TypeScript-இடம் கூறுகிறது. நிகழ்வு சந்தேகத்திற்கிடமானதாக இல்லாவிட்டால் நாம் null ஐத் திருப்புகிறோம்.
1const owner = ev.args._ownerViem இடம் ஃபீல்டு பெயர்கள் உள்ளன, எனவே அது நமக்காக நிகழ்வைப் பிரித்தெடுத்தது. _owner என்பது செலவழிக்கப்பட வேண்டிய டோக்கன்களின் உரிமையாளர்.
1// ஒப்பந்தங்களால் செய்யப்படும் அங்கீகாரங்கள் சந்தேகத்திற்கிடமானவை அல்ல2if (await isContract(owner)) return nullஉரிமையாளர் ஒரு ஒப்பந்தமாக இருந்தால், இந்த அங்கீகாரம் சந்தேகத்திற்குரியது அல்ல என்று ধরেக்கொள்ளவும். ஒரு ஒப்பந்தத்தின் அங்கீகாரம் சந்தேகத்திற்கிடமானதா இல்லையா என்பதைச் சரிபார்க்க, பரிவர்த்தனையின் முழுமையான செயல்பாட்டையும் நாம் கண்டறிய வேண்டும், அது உரிமையாளர் ஒப்பந்தத்திற்குச் சென்றதா, அந்த ஒப்பந்தம் ERC-20 ஒப்பந்தத்தை நேரடியாக அழைத்ததா என்பதைப் பார்க்க. அது நாம் செய்ய விரும்புவதை விட அதிக வளம் செலவாகும்.
1const txn = await getEventTxn(ev)அங்கீகாரம் வெளிப்புறமாக சொந்தமான கணக்கிலிருந்து வந்தால், அதை ஏற்படுத்திய பரிவர்த்தனையைப் பெறவும்.
1// பரிவர்த்தனையின் `from` அல்லாத ஒரு EOA உரிமையாளரிடமிருந்து வந்தால் அங்கீகாரம் சந்தேகத்திற்கிடமானது2if (owner.toLowerCase() != txn.from.toLowerCase()) return evமுகவரிகள் ஹெக்ஸாடெசிமல் என்பதால் நாம் ஸ்டிரிங் சமத்துவத்தைச் சரிபார்க்க முடியாது, எனவே அவை எழுத்துக்களைக் கொண்டிருக்கின்றன. சில நேரங்களில், உதாரணமாக txn.from இல், அந்த எழுத்துக்கள் அனைத்தும் சிறிய எழுத்துக்களாக இருக்கும். மற்ற சந்தர்ப்பங்களில், ev.args._owner போன்ற, முகவரி பிழை அடையாளத்திற்காக கலந்த-கேஸில்opens in a new tab உள்ளது.
ஆனால் பரிவர்த்தனை உரிமையாளரிடமிருந்து வரவில்லை என்றால், அந்த உரிமையாளர் வெளிப்புறமாகச் சொந்தமானவராக இருந்தால், நமக்கு ஒரு சந்தேகத்திற்கிடமான பரிவர்த்தனை உள்ளது.
1// பரிவர்த்தனையின் இலக்கு நாம்2// விசாரிக்கும் ERC-20 ஒப்பந்தமாக இல்லாவிட்டால் அதுவும் சந்தேகத்திற்கிடமானது3if (txn.to.toLowerCase() != testedAddress) return evஇதேபோல், பரிவர்த்தனையின் to முகவரி, முதலில் அழைக்கப்பட்ட ஒப்பந்தம், விசாரணையில் உள்ள ERC-20 ஒப்பந்தமாக இல்லாவிட்டால் அது சந்தேகத்திற்கிடமானது.
1 // சந்தேகப்பட எந்த காரணமும் இல்லையென்றால், null ஐத் திருப்பியளிக்கவும்.2 return null3}எந்த நிபந்தனையும் உண்மையாக இல்லையென்றால், Approval நிகழ்வு சந்தேகத்திற்கிடமானதல்ல.
1const testPromises = approvalEvents.map((ev) => suspiciousApprovalEvent(ev))2const testResults = (await Promise.all(testPromises)).filter((x) => x != null)34console.log(testResults)ஒரு async செயல்பாடுopens in a new tab ஒரு Promise பொருளைத் திருப்பி அனுப்புகிறது. பொதுவான தொடரியல், await x() உடன், நாம் செயலாக்கத்தைத் தொடர்வதற்கு முன் அந்த Promise நிறைவேற்றப்படும் வரை காத்திருக்கிறோம். இது புரோகிராம் செய்யவும் பின்பற்றவும் எளிமையானது, ஆனால் இது திறனற்றதும் கூட. ஒரு குறிப்பிட்ட நிகழ்விற்கான Promise நிறைவேற்றப்படும் வரை நாம் காத்திருக்கும்போது, நாம் ஏற்கனவே அடுத்த நிகழ்வில் வேலை செய்யத் தொடங்கலாம்.
இங்கே நாம் Promise பொருட்களின் ஒரு வரிசையை உருவாக்க mapopens in a new tab ஐப் பயன்படுத்துகிறோம். பிறகு நாம் அந்த அனைத்து வாக்குறுதிகளும் தீர்க்கப்படும் வரை காத்திருக்க Promise.allopens in a new tab ஐப் பயன்படுத்துகிறோம். சந்தேகத்திற்கிடமில்லாத நிகழ்வுகளை நீக்க அந்த முடிவுகளை நாம் filteropens in a new tab செய்கிறோம்.
சந்தேகத்திற்கிடமான Transfer நிகழ்வுகள்
மோசடி டோக்கன்களை அடையாளம் காண மற்றொரு சாத்தியமான வழி, அவை ஏதேனும் சந்தேகத்திற்கிடமான பரிமாற்றங்களைக் கொண்டிருக்கின்றனவா என்பதைப் பார்ப்பது. உதாரணமாக, அவ்வளவு டோக்கன்கள் இல்லாத கணக்குகளிலிருந்து பரிமாற்றங்கள். இந்தச் சோதனையை எவ்வாறு செயல்படுத்துவது என்பதை நீங்கள் காணலாம்opens in a new tab, ஆனால் wARB-க்கு இந்தப் பிரச்சினை இல்லை.
முடிவுரை
ERC-20 மோசடிகளின் தானியங்கு கண்டறிதல் தவறான எதிர்மறைகளால்opens in a new tab பாதிக்கப்படுகிறது, ஏனெனில் ஒரு மோசடி ஒரு முற்றிலும் சாதாரண ERC-20 டோக்கன் ஒப்பந்தத்தைப் பயன்படுத்தலாம், அது உண்மையான எதையும் பிரதிநிதித்துவப்படுத்தாது. எனவே நீங்கள் எப்போதும் நம்பகமான மூலத்திலிருந்து டோக்கன் முகவரியைப் பெற முயற்சிக்க வேண்டும்.
தானியங்கு கண்டறிதல் DeFi பகுதிகள் போன்ற சில சந்தர்ப்பங்களில் உதவ முடியும், அங்கு பல டோக்கன்கள் உள்ளன மற்றும் அவை தானாகவே கையாளப்பட வேண்டும். ஆனால் எப்போதும் போல் கேவியட் எம்ப்டர்opens in a new tab, உங்கள் சொந்த ஆராய்ச்சியைச் செய்யுங்கள், உங்கள் பயனர்களையும் அவ்வாறே செய்ய ஊக்குவிக்கவும்.
எனது மேலும் பணிகளை இங்கே பார்க்கவும்opens in a new tab.
பக்கத்தின் கடைசி புதுப்பிப்பு: 25 பிப்ரவரி, 2026