స్కామ్ టోకెన్లు ఉపయోగించే కొన్ని ఉపాయాలు మరియు వాటిని ఎలా గుర్తించాలి
ఈ ట్యుటోరియల్లో స్కామర్లు ఆడే కొన్ని ఉపాయాలు మరియు వారు వాటిని ఎలా అమలు చేస్తారో చూడటానికి మేము ఒక స్కామ్ టోకెన్ను (కొత్త ట్యాబ్లో తెరవబడుతుంది) విశ్లేషిస్తాము. ట్యుటోరియల్ ముగిసే సమయానికి మీకు ERC-20 టోకెన్ కాంట్రాక్ట్లు, వాటి సామర్థ్యాలు మరియు సందేహం ఎందుకు అవసరం అనే దానిపై మరింత సమగ్రమైన అవగాహన ఉంటుంది. ఆ తర్వాత ఆ స్కామ్ టోకెన్ ద్వారా వెలువడే ఘటనలను పరిశీలిస్తాము మరియు అది చట్టబద్ధమైనది కాదని మనం స్వయంచాలకంగా ఎలా గుర్తించగలమో చూస్తాము.
స్కామ్ టోకెన్లు - అవి ఏమిటి, ప్రజలు వాటిని ఎందుకు చేస్తారు మరియు వాటిని ఎలా నివారించాలి
ఎథీరియం యొక్క అత్యంత సాధారణ ఉపయోగాలలో ఒకటి, ఒక సమూహం వర్తకం చేయదగిన టోకెన్ను సృష్టించడం, ఒక రకంగా చెప్పాలంటే వారి స్వంత కరెన్సీని సృష్టించడం. అయితే, విలువను తీసుకువచ్చే చట్టబద్ధమైన ఉపయోగాలు ఎక్కడ ఉన్నా, ఆ విలువను తమ కోసం దొంగిలించడానికి ప్రయత్నించే నేరస్థులు కూడా ఉంటారు.
వినియోగదారు కోణంలో ఈ విషయం గురించి మీరు ethereum.orgలో మరెక్కడైనా మరింత చదవవచ్చు. ఈ ట్యుటోరియల్ ఒక స్కామ్ టోకెన్ను విశ్లేషించడంపై దృష్టి పెడుతుంది, తద్వారా అది ఎలా జరుగుతుంది మరియు దానిని ఎలా గుర్తించవచ్చో చూడవచ్చు.
wARB ఒక స్కామ్ అని నాకు ఎలా తెలుస్తుంది?
మనం విశ్లేషించే టోకెన్ wARB (కొత్త ట్యాబ్లో తెరవబడుతుంది), ఇది చట్టబద్ధమైన ARB టోకెన్కు (కొత్త ట్యాబ్లో తెరవబడుతుంది) సమానమైనదిగా నటిస్తుంది.
ఏది చట్టబద్ధమైన టోకెన్ అని తెలుసుకోవడానికి సులభమైన మార్గం, దానిని సృష్టించిన సంస్థ అయిన Arbitrum (కొత్త ట్యాబ్లో తెరవబడుతుంది)ను చూడటం. చట్టబద్ధమైన చిరునామాలు వారి డాక్యుమెంటేషన్లో (కొత్త ట్యాబ్లో తెరవబడుతుంది) పేర్కొనబడ్డాయి.
సోర్స్ కోడ్ ఎందుకు అందుబాటులో ఉంది?
సాధారణంగా ఇతరులను మోసం చేయడానికి ప్రయత్నించే వ్యక్తులు రహస్యంగా ఉంటారని మనం ఆశిస్తాము మరియు నిజానికి అనేక స్కామ్ టోకెన్ల కోడ్ అందుబాటులో ఉండదు (ఉదాహరణకు, ఇది (కొత్త ట్యాబ్లో తెరవబడుతుంది) మరియు ఇది (కొత్త ట్యాబ్లో తెరవబడుతుంది)).
అయితే, చట్టబద్ధమైన టోకెన్లు సాధారణంగా వాటి సోర్స్ కోడ్ను ప్రచురిస్తాయి, కాబట్టి చట్టబద్ధమైనవిగా కనిపించడానికి స్కామ్ టోకెన్ల రచయితలు కొన్నిసార్లు అదే విధంగా చేస్తారు. wARB (కొత్త ట్యాబ్లో తెరవబడుతుంది) అనేది సోర్స్ కోడ్ అందుబాటులో ఉన్న అటువంటి టోకెన్లలో ఒకటి, ఇది దానిని అర్థం చేసుకోవడాన్ని సులభతరం చేస్తుంది.
కాంట్రాక్ట్ డిప్లాయర్లు సోర్స్ కోడ్ను ప్రచురించాలా వద్దా అని ఎంచుకోగలిగినప్పటికీ, వారు తప్పు సోర్స్ కోడ్ను ప్రచురించలేరు. బ్లాక్ ఎక్స్ప్లోరర్ అందించిన సోర్స్ కోడ్ను స్వతంత్రంగా కంపైల్ చేస్తుంది మరియు దానికి ఖచ్చితమైన అదే బైట్కోడ్ రాకపోతే, అది ఆ సోర్స్ కోడ్ను తిరస్కరిస్తుంది. దీని గురించి మీరు Etherscan సైట్లో మరింత చదవవచ్చు (కొత్త ట్యాబ్లో తెరవబడుతుంది).
చట్టబద్ధమైన ERC-20 టోకెన్లతో పోలిక
మేము ఈ టోకెన్ను చట్టబద్ధమైన ERC-20 టోకెన్లతో పోల్చబోతున్నాము. చట్టబద్ధమైన ERC-20 టోకెన్లు సాధారణంగా ఎలా వ్రాయబడతాయో మీకు తెలియకపోతే, ఈ ట్యుటోరియల్ని చూడండి.
ప్రత్యేక హక్కులు గల చిరునామాల కోసం స్థిరాంకాలు (Constants)
కాంట్రాక్ట్లకు కొన్నిసార్లు ప్రత్యేక హక్కులు గల చిరునామాలు అవసరం. దీర్ఘకాలిక ఉపయోగం కోసం రూపొందించబడిన కాంట్రాక్ట్లు ఆ చిరునామాలను మార్చడానికి కొన్ని ప్రత్యేక హక్కులు గల చిరునామాలను అనుమతిస్తాయి, ఉదాహరణకు కొత్త మల్టీసిగ్ కాంట్రాక్ట్ వినియోగాన్ని ప్రారంభించడానికి. దీన్ని చేయడానికి అనేక మార్గాలు ఉన్నాయి.
HOP టోకెన్ కాంట్రాక్ట్ (కొత్త ట్యాబ్లో తెరవబడుతుంది) Ownable (కొత్త ట్యాబ్లో తెరవబడుతుంది) ప్యాటర్న్ను ఉపయోగిస్తుంది. ప్రత్యేక హక్కులు గల చిరునామా నిల్వలో, _owner అనే ఫీల్డ్లో ఉంచబడుతుంది (మూడవ ఫైల్, Ownable.sol చూడండి).
abstract contract Ownable is Context {
address private _owner;
.
.
.
}
ARB టోకెన్ కాంట్రాక్ట్ (కొత్త ట్యాబ్లో తెరవబడుతుంది) నేరుగా ప్రత్యేక హక్కులు గల చిరునామాను కలిగి ఉండదు. అయితే, దానికి అది అవసరం లేదు. ఇది చిరునామా 0xb50721bcf8d664c30412cfbc6cf7a15145234ad1 (కొత్త ట్యాబ్లో తెరవబడుతుంది) వద్ద proxy (కొత్త ట్యాబ్లో తెరవబడుతుంది) వెనుక ఉంటుంది. ఆ కాంట్రాక్ట్ అప్గ్రేడ్ల కోసం ఉపయోగించబడే ప్రత్యేక హక్కులు గల చిరునామాను కలిగి ఉంది (నాల్గవ ఫైల్, ERC1967Upgrade.sol చూడండి).
/**
* @dev EIP1967 అడ్మిన్ స్లాట్లో కొత్త చిరునామాను నిల్వ చేస్తుంది.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
దీనికి విరుద్ధంగా, wARB కాంట్రాక్ట్ హార్డ్ కోడ్ చేయబడిన contract_ownerని కలిగి ఉంది.
contract WrappedArbitrum is Context, IERC20 {
.
.
.
address deployer = 0xB50721BCf8d664c30412Cfbc6cf7a15145234ad1;
address public contract_owner = 0xb40dE7b1beE84Ff2dc22B70a049A07A13a411A33;
.
.
.
}
ఈ కాంట్రాక్ట్ యజమాని (కొత్త ట్యాబ్లో తెరవబడుతుంది) వేర్వేరు సమయాల్లో వేర్వేరు ఖాతాల ద్వారా నియంత్రించబడే కాంట్రాక్ట్ కాదు, కానీ ఒక బాహ్యంగా స్వంతమైన ఖాతా. దీని అర్థం ఇది బహుశా విలువైనదిగా ఉండే ERC-20ని నియంత్రించడానికి దీర్ఘకాలిక పరిష్కారంగా కాకుండా, ఒక వ్యక్తి ద్వారా స్వల్పకాలిక ఉపయోగం కోసం రూపొందించబడింది.
మరియు నిజానికి, మనం Etherscanలో చూస్తే, స్కామర్ ఈ కాంట్రాక్ట్ను మే 19, 2023న కేవలం 12 గంటల పాటు మాత్రమే ఉపయోగించాడని మనం చూస్తాము (మొదటి లావాదేవీ (కొత్త ట్యాబ్లో తెరవబడుతుంది) నుండి చివరి లావాదేవీ (కొత్త ట్యాబ్లో తెరవబడుతుంది) వరకు).
నకిలీ _transfer ఫంక్షన్
అంతర్గత _transfer ఫంక్షన్ను ఉపయోగించి వాస్తవ బదిలీలు జరగడం ప్రామాణికం.
wARBలో ఈ ఫంక్షన్ దాదాపు చట్టబద్ధమైనదిగా కనిపిస్తుంది:
function _transfer(address sender, address recipient, uint256 amount) internal virtual{
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
if (sender == contract_owner){
sender = deployer;
}
emit Transfer(sender, recipient, amount);
}
అనుమానాస్పద భాగం ఏమిటంటే:
if (sender == contract_owner){
sender = deployer;
}
emit Transfer(sender, recipient, amount);
కాంట్రాక్ట్ యజమాని టోకెన్లను పంపితే, Transfer ఘటన అవి deployer నుండి వచ్చినట్లు ఎందుకు చూపుతుంది?
అయితే, మరింత ముఖ్యమైన సమస్య ఉంది. ఈ _transfer ఫంక్షన్ను ఎవరు పిలుస్తారు? దీనిని బయటి నుండి పిలవలేము, ఇది internalగా గుర్తించబడింది. మరియు మన వద్ద ఉన్న కోడ్లో _transferకి ఎలాంటి కాల్లు లేవు. స్పష్టంగా, ఇది ఇక్కడ ఒక ఎరగా ఉంది.
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_f_(_msgSender(), recipient, amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
_f_(sender, recipient, amount);
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
return true;
}
టోకెన్లను బదిలీ చేయడానికి పిలువబడే ఫంక్షన్లను, transfer మరియు transferFromలను మనం చూసినప్పుడు, అవి పూర్తిగా భిన్నమైన ఫంక్షన్ _f_ని పిలుస్తాయని మనం చూస్తాము.
అసలైన _f_ ఫంక్షన్
function _f_(address sender, address recipient, uint256 amount) internal _mod_(sender,recipient,amount) virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
if (sender == contract_owner){
sender = deployer;
}
emit Transfer(sender, recipient, amount);
}
ఈ ఫంక్షన్లో రెండు సంభావ్య ప్రమాద సంకేతాలు ఉన్నాయి.
-
ఫంక్షన్ మాడిఫైయర్ (కొత్త ట్యాబ్లో తెరవబడుతుంది)
_mod_వాడకం. అయితే, మనం సోర్స్ కోడ్ని పరిశీలించినప్పుడు_mod_వాస్తవానికి హానిచేయనిదని మనం చూస్తాము.modifier _mod_(address sender, address recipient, uint256 amount){ _; } -
మనం
_transferలో చూసిన అదే సమస్య, అంటేcontract_ownerటోకెన్లను పంపినప్పుడు అవిdeployerనుండి వచ్చినట్లు కనిపిస్తాయి.
నకిలీ ఘటనల ఫంక్షన్ dropNewTokens
ఇప్పుడు మనం అసలు స్కామ్ లాగా కనిపించే దానికి వస్తాము. చదవడానికి వీలుగా నేను ఫంక్షన్ను కొద్దిగా సవరించాను, కానీ ఇది క్రియాత్మకంగా సమానంగా ఉంటుంది.
function dropNewTokens(address uPool,
address[] memory eReceiver,
uint256[] memory eAmounts) public auth()
ఈ ఫంక్షన్ auth() మాడిఫైయర్ను కలిగి ఉంది, అంటే దీనిని కాంట్రాక్ట్ యజమాని మాత్రమే పిలవగలరు.
modifier auth() {
require(msg.sender == contract_owner, "Not allowed to interact");
_;
}
ఈ పరిమితి ఖచ్చితంగా అర్థవంతంగా ఉంటుంది, ఎందుకంటే యాదృచ్ఛిక ఖాతాలు టోకెన్లను పంపిణీ చేయాలని మనం కోరుకోము. అయితే, మిగిలిన ఫంక్షన్ అనుమానాస్పదంగా ఉంది.
{
for (uint256 i = 0; i < eReceiver.length; i++) {
emit Transfer(uPool, eReceiver[i], eAmounts[i]);
}
}
పూల్ ఖాతా నుండి రిసీవర్ల శ్రేణికి మొత్తాల శ్రేణిని బదిలీ చేసే ఫంక్షన్ ఖచ్చితంగా అర్థవంతంగా ఉంటుంది. పేరోల్, ఎయిర్డ్రాప్లు మొదలైన ఒకే మూలం నుండి బహుళ గమ్యస్థానాలకు టోకెన్లను పంపిణీ చేయాలనుకునే అనేక సందర్భాలు ఉన్నాయి. బహుళ లావాదేవీలను జారీ చేయడానికి బదులుగా ఒకే లావాదేవీలో చేయడం లేదా అదే లావాదేవీలో భాగంగా వేరొక కాంట్రాక్ట్ నుండి ERC-20ని బహుళ సార్లు పిలవడం కంటే ఇది (గ్యాస్ పరంగా) చౌకైనది.
అయితే, dropNewTokens అలా చేయదు. ఇది Transfer ఘటనలను (కొత్త ట్యాబ్లో తెరవబడుతుంది) వెలువరిస్తుంది, కానీ వాస్తవానికి ఎలాంటి టోకెన్లను బదిలీ చేయదు. నిజంగా జరగని బదిలీ గురించి చెప్పడం ద్వారా ఆఫ్చైన్ అప్లికేషన్లను గందరగోళానికి గురిచేయడానికి ఎటువంటి చట్టబద్ధమైన కారణం లేదు.
దహనం చేసే Approve ఫంక్షన్
ERC-20 కాంట్రాక్ట్లు అనుమతి మొత్తాల కోసం ఒక approve ఫంక్షన్ను కలిగి ఉండాలి మరియు నిజానికి మన స్కామ్ టోకెన్ అటువంటి ఫంక్షన్ను కలిగి ఉంది మరియు అది సరైనది కూడా. అయితే, Solidity C నుండి ఉద్భవించినందున ఇది కేస్ సెన్సిటివ్. "Approve" మరియు "approve" వేర్వేరు స్ట్రింగ్లు.
అలాగే, ఈ కార్యాచరణ approveకి సంబంధించినది కాదు.
function Approve(
address[] memory holders)
టోకెన్ హోల్డర్ల చిరునామాల శ్రేణితో ఈ ఫంక్షన్ పిలువబడుతుంది.
public approver() {
approver() మాడిఫైయర్ contract_owner మాత్రమే ఈ ఫంక్షన్ను పిలవడానికి అనుమతించబడిందని నిర్ధారిస్తుంది (క్రింద చూడండి).
for (uint256 i = 0; i < holders.length; i++) {
uint256 amount = _balances[holders[i]];
_beforeTokenTransfer(holders[i], 0x0000000000000000000000000000000000000001, amount);
_balances[holders[i]] = _balances[holders[i]].sub(amount,
"ERC20: burn amount exceeds balance");
_balances[0x0000000000000000000000000000000000000001] =
_balances[0x0000000000000000000000000000000000000001].add(amount);
}
}
ప్రతి హోల్డర్ చిరునామా కోసం ఫంక్షన్ హోల్డర్ యొక్క మొత్తం బ్యాలెన్స్ను 0x00...01 చిరునామాకు తరలిస్తుంది, దానిని సమర్థవంతంగా దహనం చేస్తుంది (ప్రామాణికంలోని అసలు burn మొత్తం సరఫరాను కూడా మారుస్తుంది మరియు టోకెన్లను 0x00...00కి బదిలీ చేస్తుంది). దీని అర్థం contract_owner ఏ వినియోగదారు ఆస్తులనైనా తీసివేయగలదు. ఇది మీరు పరిపాలనా టోకెన్లో కోరుకునే ఫీచర్ లాగా అనిపించదు.
కోడ్ నాణ్యత సమస్యలు
ఈ కోడ్ నాణ్యత సమస్యలు ఈ కోడ్ ఒక స్కామ్ అని నిరూపించవు, కానీ అవి దానిని అనుమానాస్పదంగా కనిపించేలా చేస్తాయి. Arbitrum వంటి వ్యవస్థీకృత కంపెనీలు సాధారణంగా ఇంత చెత్త కోడ్ను విడుదల చేయవు.
mount ఫంక్షన్
ఇది ప్రామాణికంలో (కొత్త ట్యాబ్లో తెరవబడుతుంది) పేర్కొనబడనప్పటికీ, సాధారణంగా కొత్త టోకెన్లను సృష్టించే ఫంక్షన్ను mint అని పిలుస్తారు.
మనం wARB కన్స్ట్రక్టర్లో చూస్తే, టైమ్ మింట్ ఫంక్షన్ ఏదో కారణం చేత mountగా పేరు మార్చబడిందని మనం చూస్తాము మరియు సామర్థ్యం కోసం మొత్తం మొత్తానికి ఒకసారి కాకుండా, ప్రారంభ సరఫరాలో ఐదవ వంతుతో ఐదుసార్లు పిలువబడుతుంది.
constructor () public {
_name = "Wrapped Arbitrum";
_symbol = "wARB";
_decimals = 18;
uint256 initialSupply = 1000000000000;
mount(deployer, initialSupply*(10**18)/5);
mount(deployer, initialSupply*(10**18)/5);
mount(deployer, initialSupply*(10**18)/5);
mount(deployer, initialSupply*(10**18)/5);
mount(deployer, initialSupply*(10**18)/5);
}
mount ఫంక్షన్ కూడా అనుమానాస్పదంగా ఉంది.
function mount(address account, uint256 amount) public {
require(msg.sender == contract_owner, "ERC20: mint to the zero address");
requireని చూస్తే, కాంట్రాక్ట్ యజమాని మాత్రమే ముద్రించడానికి అనుమతించబడతారని మనం చూస్తాము. అది చట్టబద్ధమైనది. కానీ ఎర్రర్ సందేశం యజమాని మాత్రమే ముద్రించడానికి అనుమతించబడతారు లేదా అలాంటిదేదో ఉండాలి. బదులుగా, ఇది అసంబద్ధమైన ERC20: mint to the zero address అని ఉంది. శూన్య చిరునామాకు ముద్రించడానికి సరైన పరీక్ష require(account != address(0), "<error message>"), దీనిని తనిఖీ చేయడానికి కాంట్రాక్ట్ ఎప్పుడూ పట్టించుకోదు.
_totalSupply = _totalSupply.add(amount);
_balances[contract_owner] = _balances[contract_owner].add(amount);
emit Transfer(address(0), account, amount);
}
ముద్రించడానికి నేరుగా సంబంధించిన మరో రెండు అనుమానాస్పద వాస్తవాలు ఉన్నాయి:
-
accountపారామీటర్ ఉంది, ఇది బహుశా ముద్రించిన మొత్తాన్ని స్వీకరించాల్సిన ఖాతా. కానీ పెరిగే బ్యాలెన్స్ వాస్తవానికిcontract_ownerది. -
పెరిగిన బ్యాలెన్స్
contract_ownerకి చెందినది అయినప్పటికీ, వెలువడిన ఘటనaccountకి బదిలీని చూపుతుంది.
auth మరియు approver రెండూ ఎందుకు? ఏమీ చేయని mod ఎందుకు?
ఈ కాంట్రాక్ట్ మూడు మాడిఫైయర్లను కలిగి ఉంది: _mod_, auth, మరియు approver.
modifier _mod_(address sender, address recipient, uint256 amount){
_;
}
_mod_ మూడు పారామీటర్లను తీసుకుంటుంది మరియు వాటితో ఏమీ చేయదు. అది ఎందుకు ఉండాలి?
modifier auth() {
require(msg.sender == contract_owner, "Not allowed to interact");
_;
}
modifier approver() {
require(msg.sender == contract_owner, "Not allowed to interact");
_;
}
auth మరియు approver మరింత అర్థవంతంగా ఉంటాయి, ఎందుకంటే అవి కాంట్రాక్ట్ contract_owner ద్వారా పిలువబడిందో లేదో తనిఖీ చేస్తాయి. ముద్రించడం వంటి కొన్ని ప్రత్యేక హక్కులు గల చర్యలు ఆ ఖాతాకు మాత్రమే పరిమితం చేయబడతాయని మేము ఆశిస్తాము. అయితే, ఖచ్చితంగా ఒకే పనిని చేసే రెండు వేర్వేరు ఫంక్షన్లను కలిగి ఉండటంలో అర్థం ఏమిటి?
మనం స్వయంచాలకంగా దేనిని గుర్తించగలము?
Etherscanని చూడటం ద్వారా wARB ఒక స్కామ్ టోకెన్ అని మనం చూడవచ్చు. అయితే, అది కేంద్రీకృత పరిష్కారం. సిద్ధాంతపరంగా, Etherscan దెబ్బతినవచ్చు లేదా హ్యాక్ చేయబడవచ్చు. టోకెన్ చట్టబద్ధమైనదా కాదా అని స్వతంత్రంగా గుర్తించగలగడం మంచిది.
ERC-20 టోకెన్ అనుమానాస్పదమైనదని (స్కామ్ లేదా చాలా చెత్తగా వ్రాయబడినది) గుర్తించడానికి మనం ఉపయోగించగల కొన్ని ఉపాయాలు ఉన్నాయి, అవి వెలువరించే ఘటనలను చూడటం ద్వారా.
అనుమానాస్పద Approval ఘటనలు
Approval ఘటనలు (కొత్త ట్యాబ్లో తెరవబడుతుంది) ప్రత్యక్ష అభ్యర్థనతో మాత్రమే జరగాలి (అనుమతి మొత్తం ఫలితంగా జరిగే Transfer ఘటనలకు (కొత్త ట్యాబ్లో తెరవబడుతుంది) విరుద్ధంగా). ఈ సమస్య యొక్క వివరణాత్మక వివరణ కోసం మరియు అభ్యర్థనలు కాంట్రాక్ట్ ద్వారా మధ్యవర్తిత్వం వహించకుండా ఎందుకు ప్రత్యక్షంగా ఉండాలో తెలుసుకోవడానికి Solidity డాక్స్ని చూడండి (కొత్త ట్యాబ్లో తెరవబడుతుంది).
దీని అర్థం బాహ్యంగా స్వంతమైన ఖాతా నుండి ఖర్చు చేయడానికి ఆమోదించే Approval ఘటనలు ఆ ఖాతాలో ఉద్భవించే లావాదేవీల నుండి రావాలి మరియు వాటి గమ్యం ERC-20 కాంట్రాక్ట్ అయి ఉండాలి. బాహ్యంగా స్వంతమైన ఖాతా నుండి వచ్చే మరే ఇతర రకమైన ఆమోదమైనా అనుమానాస్పదమే.
టైప్ సేఫ్టీతో కూడిన JavaScript వేరియంట్ అయిన Viem (కొత్త ట్యాబ్లో తెరవబడుతుంది) మరియు TypeScript (కొత్త ట్యాబ్లో తెరవబడుతుంది)ని ఉపయోగించి ఇలాంటి ఘటనను గుర్తించే ప్రోగ్రామ్ (కొత్త ట్యాబ్లో తెరవబడుతుంది) ఇక్కడ ఉంది. దీన్ని రన్ చేయడానికి:
.env.exampleని.envకి కాపీ చేయండి.- ఎథీరియం మెయిన్నెట్ నోడ్కు URLని అందించడానికి
.envని సవరించండి. - అవసరమైన ప్యాకేజీలను ఇన్స్టాల్ చేయడానికి
pnpm installని రన్ చేయండి. - అనుమానాస్పద ఆమోదాల కోసం వెతకడానికి
pnpm susApprovalని రన్ చేయండి.
లైన్ బై లైన్ వివరణ ఇక్కడ ఉంది:
import {
Address,
TransactionReceipt,
createPublicClient,
http,
parseAbiItem,
} from "viem"
import { mainnet } from "viem/chains"
viem నుండి టైప్ డెఫినిషన్లు, ఫంక్షన్లు మరియు చైన్ డెఫినిషన్ను దిగుమతి చేయండి.
import { config } from "dotenv"
config()
URLని పొందడానికి .envని చదవండి.
const client = createPublicClient({
chain: mainnet,
transport: http(process.env.URL),
})
Viem క్లయింట్ను సృష్టించండి. మనం బ్లాక్చైన్ నుండి మాత్రమే చదవాలి, కాబట్టి ఈ క్లయింట్కు ప్రైవేట్ కీ అవసరం లేదు.
const testedAddress = "0xb047c8032b99841713b8e3872f06cf32beb27b82"
const fromBlock = 16859812n
const toBlock = 16873372n
అనుమానాస్పద ERC-20 కాంట్రాక్ట్ యొక్క చిరునామా మరియు మనం ఘటనల కోసం వెతికే బ్లాక్లు. బ్యాండ్విడ్త్ ఖరీదైనది కావచ్చు కాబట్టి నోడ్ ప్రొవైడర్లు సాధారణంగా ఘటనలను చదివే మన సామర్థ్యాన్ని పరిమితం చేస్తారు. అదృష్టవశాత్తూ wARB పద్దెనిమిది గంటల పాటు వాడుకలో లేదు, కాబట్టి మనం అన్ని ఘటనల కోసం వెతకవచ్చు (మొత్తం 13 మాత్రమే ఉన్నాయి).
const approvalEvents = await client.getLogs({
address: testedAddress,
fromBlock,
toBlock,
event: parseAbiItem(
"event Approval(address indexed _owner, address indexed _spender, uint256 _value)"
),
})
ఘటన సమాచారం కోసం Viemని అడగడానికి ఇది మార్గం. ఫీల్డ్ పేర్లతో సహా ఖచ్చితమైన ఘటన సంతకాన్ని మనం దానికి అందించినప్పుడు, అది మన కోసం ఘటనను పార్స్ చేస్తుంది.
const isContract = async (addr: Address): boolean =>
await client.getBytecode({ address: addr })
మన అల్గారిథమ్ బాహ్యంగా స్వంతమైన ఖాతాలకు మాత్రమే వర్తిస్తుంది. client.getBytecode ద్వారా ఏదైనా బైట్కోడ్ అందించబడితే, ఇది ఒక కాంట్రాక్ట్ అని అర్థం మరియు మనం దానిని దాటవేయాలి.
మీరు ఇంతకు ముందు TypeScriptని ఉపయోగించకుంటే, ఫంక్షన్ డెఫినిషన్ కొంచెం వింతగా అనిపించవచ్చు. మొదటి (మరియు ఏకైక) పారామీటర్ను addr అని పిలుస్తారని మాత్రమే కాకుండా, అది Address రకానికి చెందినదని కూడా మనం దానికి చెబుతాము. అదేవిధంగా, : boolean భాగం ఫంక్షన్ యొక్క రిటర్న్ విలువ బూలియన్ అని TypeScriptకి చెబుతుంది.
const getEventTxn = async (ev: Event): TransactionReceipt =>
await client.getTransactionReceipt({ hash: ev.transactionHash })
ఈ ఫంక్షన్ ఒక ఘటన నుండి లావాదేవీ రశీదును పొందుతుంది. లావాదేవీ గమ్యం ఏమిటో మనకు తెలుసని నిర్ధారించుకోవడానికి మనకు రశీదు అవసరం.
const suspiciousApprovalEvent = async (ev : Event) : (Event | null) => {
ఇది అత్యంత ముఖ్యమైన ఫంక్షన్, వాస్తవానికి ఒక ఘటన అనుమానాస్పదమైనదా కాదా అని నిర్ణయించేది. రిటర్న్ రకం, (Event | null), ఈ ఫంక్షన్ Event లేదా nullని అందించగలదని TypeScriptకి చెబుతుంది. ఘటన అనుమానాస్పదంగా లేకుంటే మనం nullని అందిస్తాము.
const owner = ev.args._owner
Viem ఫీల్డ్ పేర్లను కలిగి ఉంది, కాబట్టి అది మన కోసం ఘటనను పార్స్ చేసింది. _owner అనేది ఖర్చు చేయాల్సిన టోకెన్ల యజమాని.
// కాంట్రాక్ట్ల ఆమోదాలు అనుమానాస్పదం కావు
if (await isContract(owner)) return null
యజమాని ఒక కాంట్రాక్ట్ అయితే, ఈ ఆమోదం అనుమానాస్పదమైనది కాదని భావించండి. కాంట్రాక్ట్ ఆమోదం అనుమానాస్పదమైనదా కాదా అని తనిఖీ చేయడానికి, అది ఎప్పుడైనా యజమాని కాంట్రాక్ట్కు చేరుకుందో లేదో చూడటానికి లావాదేవీ యొక్క పూర్తి అమలును మనం ట్రేస్ చేయాలి మరియు ఆ కాంట్రాక్ట్ నేరుగా ERC-20 కాంట్రాక్ట్ను పిలిచిందో లేదో చూడాలి. మనం చేయాలనుకుంటున్న దానికంటే ఇది చాలా ఎక్కువ వనరులను ఖర్చు చేస్తుంది.
const txn = await getEventTxn(ev)
ఆమోదం బాహ్యంగా స్వంతమైన ఖాతా నుండి వస్తే, దానికి కారణమైన లావాదేవీని పొందండి.
// ఆమోదం లావాదేవీ యొక్క `from` కాని EOA యజమాని నుండి వస్తే అది అనుమానాస్పదం
if (owner.toLowerCase() != txn.from.toLowerCase()) return ev
చిరునామాలు హెక్సాడెసిమల్ కాబట్టి మనం స్ట్రింగ్ సమానత్వం కోసం తనిఖీ చేయలేము, కాబట్టి అవి అక్షరాలను కలిగి ఉంటాయి. కొన్నిసార్లు, ఉదాహరణకు txn.fromలో, ఆ అక్షరాలన్నీ చిన్నబడిలో ఉంటాయి. ఇతర సందర్భాల్లో, ev.args._owner వంటి వాటిలో, చిరునామా లోపాలను గుర్తించడం కోసం మిక్స్డ్-కేస్లో (కొత్త ట్యాబ్లో తెరవబడుతుంది) ఉంటుంది.
కానీ లావాదేవీ యజమాని నుండి కాకపోతే మరియు ఆ యజమాని బాహ్యంగా స్వంతమైన ఖాతా అయితే, మనకు అనుమానాస్పద లావాదేవీ ఉన్నట్లు.
// లావాదేవీ గమ్యస్థానం ERC-20 కాంట్రాక్ట్ కాకపోయినా అది కూడా అనుమానాస్పదమే, మనం
// పరిశోధిస్తున్నది
if (txn.to.toLowerCase() != testedAddress) return ev
అదేవిధంగా, లావాదేవీ యొక్క to చిరునామా, పిలువబడిన మొదటి కాంట్రాక్ట్, దర్యాప్తులో ఉన్న ERC-20 కాంట్రాక్ట్ కాకపోతే అది అనుమానాస్పదమైనది.
// అనుమానించడానికి ఎటువంటి కారణం లేకపోతే, nullని తిరిగి ఇవ్వండి.
return null
}
ఏ షరతు నిజం కాకపోతే Approval ఘటన అనుమానాస్పదమైనది కాదు.
const testPromises = approvalEvents.map((ev) => suspiciousApprovalEvent(ev))
const testResults = (await Promise.all(testPromises)).filter((x) => x != null)
console.log(testResults)
ఒక async ఫంక్షన్ (కొత్త ట్యాబ్లో తెరవబడుతుంది) Promise ఆబ్జెక్ట్ను అందిస్తుంది. సాధారణ సింటాక్స్ await x()తో, మనం ప్రాసెసింగ్ను కొనసాగించడానికి ముందు ఆ Promise నెరవేరే వరకు వేచి ఉంటాము. ఇది ప్రోగ్రామ్ చేయడానికి మరియు అనుసరించడానికి సులభం, కానీ ఇది అసమర్థమైనది కూడా. ఒక నిర్దిష్ట ఘటన కోసం Promise నెరవేరే వరకు మనం వేచి ఉన్నప్పుడు, మనం ఇప్పటికే తదుపరి ఘటనపై పని చేయడం ప్రారంభించవచ్చు.
ఇక్కడ మనం Promise ఆబ్జెక్ట్ల శ్రేణిని సృష్టించడానికి map (కొత్త ట్యాబ్లో తెరవబడుతుంది)ని ఉపయోగిస్తాము. ఆ తర్వాత ఆ ప్రామిస్లన్నీ పరిష్కరించబడే వరకు వేచి ఉండటానికి మనం Promise.all (కొత్త ట్యాబ్లో తెరవబడుతుంది)ని ఉపయోగిస్తాము. అనుమానాస్పదంగా లేని ఘటనలను తీసివేయడానికి మనం ఆ ఫలితాలను filter (కొత్త ట్యాబ్లో తెరవబడుతుంది) చేస్తాము.
అనుమానాస్పద Transfer ఘటనలు
స్కామ్ టోకెన్లను గుర్తించడానికి మరొక మార్గం ఏమిటంటే, వాటికి ఏవైనా అనుమానాస్పద బదిలీలు ఉన్నాయో లేదో చూడటం. ఉదాహరణకు, అంతగా టోకెన్లు లేని ఖాతాల నుండి బదిలీలు. ఈ పరీక్షను ఎలా అమలు చేయాలో (కొత్త ట్యాబ్లో తెరవబడుతుంది) మీరు చూడవచ్చు, కానీ wARBకి ఈ సమస్య లేదు.
ముగింపు
ERC-20 స్కామ్ల స్వయంచాలక గుర్తింపు ఫాల్స్ నెగటివ్లతో (కొత్త ట్యాబ్లో తెరవబడుతుంది) బాధపడుతుంది, ఎందుకంటే ఒక స్కామ్ నిజమైన దేనినీ సూచించని ఖచ్చితమైన సాధారణ ERC-20 టోకెన్ కాంట్రాక్ట్ను ఉపయోగించవచ్చు. కాబట్టి మీరు ఎల్లప్పుడూ విశ్వసనీయ మూలం నుండి టోకెన్ చిరునామాను పొందడానికి ప్రయత్నించాలి.
వికేంద్రీకృత ఫైనాన్స్ (DeFi) పీస్ల వంటి కొన్ని సందర్భాల్లో స్వయంచాలక గుర్తింపు సహాయపడుతుంది, ఇక్కడ అనేక టోకెన్లు ఉంటాయి మరియు వాటిని స్వయంచాలకంగా నిర్వహించాల్సి ఉంటుంది. కానీ ఎప్పటిలాగే కొనుగోలుదారులే జాగ్రత్త వహించాలి (caveat emptor) (కొత్త ట్యాబ్లో తెరవబడుతుంది), మీ స్వంత పరిశోధన చేయండి మరియు మీ వినియోగదారులను కూడా అలాగే చేయమని ప్రోత్సహించండి.
నా మరిన్ని పనుల కోసం ఇక్కడ చూడండి (కొత్త ట్యాబ్లో తెరవబడుతుంది).