ప్రధాన కంటెంట్‌కి స్కిప్ చేయండి

సేఫ్టీ రైల్స్‌తో ERC-20

erc-20
ప్రారంభ
Ori Pomerantz
15 ఆగస్టు, 2022
7 నిమిషం పఠనం

పరిచయం

ఇతీరియము గురించి గొప్ప విషయాలలో ఒకటి ఏమిటంటే, మీ లావాదేవీలను సవరించగల లేదా రద్దు చేయగల కేంద్ర అధికారం ఏదీ లేదు. ఇతీరియముతో ఉన్న పెద్ద సమస్యలలో ఒకటి ఏమిటంటే, వినియోగదారుడి పొరపాట్లను లేదా చట్టవిరుద్ధమైన లావాదేవీలను రద్దు చేసే అధికారం ఉన్న కేంద్ర అధికారం ఏదీ లేదు. ఈ ఆర్టికల్‌లో మీరు ERC-20 టోకెన్‌లతో వినియోగదారులు చేసే కొన్ని సాధారణ తప్పుల గురించి, అలాగే ఆ తప్పులను నివారించడానికి వినియోగదారులకు సహాయపడే ERC-20 ఒప్పందాలను ఎలా సృష్టించాలో లేదా కేంద్ర అధికారానికి కొంత శక్తిని (ఉదాహరణకు ఖాతాలను ఫ్రీజ్ చేయడానికి) ఎలా ఇవ్వాలో నేర్చుకుంటారు.

OpenZeppelin ERC-20 టోకెన్ ఒప్పందాన్ని (opens in a new tab) మేము ఉపయోగిస్తున్నప్పటికీ, ఈ కథనం దానిని పెద్దగా వివరంగా వివరించదని గమనించండి. మీరు ఈ సమాచారాన్ని ఇక్కడ కనుగొనవచ్చు.

మీరు పూర్తి మూల సంకేత భాషను చూడాలనుకుంటే:

  1. రీమిక్స్ IDE (opens in a new tab)ని తెరవండి.
  2. క్లోన్ గిట్‌హబ్ ఐకాన్‌ను (క్లోన్ గిట్‌హబ్ ఐకాన్) క్లిక్ చేయండి.
  3. గిట్‌హబ్ రిపోజిటరీని https://github.com/qbzzt/20220815-erc20-safety-rails క్లోన్ చేయండి.
  4. contracts > erc20-safety-rails.sol తెరవండి.

ఒక ERC-20 ఒప్పందాన్ని సృష్టించడం

మేము సేఫ్టీ రైల్ ఫంక్షనాలిటీని జోడించే ముందు, మాకు ERC-20 ఒప్పందం అవసరం. ఈ ఆర్టికల్‌లో మనం ది ఓపెన్‌జెప్పెలిన్ కాంట్రాక్ట్స్ విజార్డ్ (opens in a new tab) ను ఉపయోగిస్తాము. దీన్ని మరొక బ్రౌజర్‌లో తెరిచి, ఈ సూచనలను పాటించండి:

  1. ERC20 ఎంచుకోండి.

  2. ఈ సెట్టింగులను నమోదు చేయండి:

    పరామితివిలువ
    పేరుSafetyRailsToken
    చిహ్నంSAFE
    ప్రీమింట్1000
    లక్షణాలుఏదీ లేదు
    యాక్సెస్ కంట్రోల్Ownable
    అప్‌గ్రేడబిలిటీఏదీ లేదు
  3. పైకి స్క్రోల్ చేసి, Remix లో తెరవండి (Remix కోసం) లేదా వేరొక వాతావరణాన్ని ఉపయోగించడానికి డౌన్లోడ్ క్లిక్ చేయండి. మీరు రీమిక్స్ వాడుతున్నారని నేను భావిస్తున్నాను, మీరు వేరేది ఏదైనా వాడితే, తగిన మార్పులు చేసుకోండి.

  4. మన దగ్గర ఇప్పుడు పూర్తిస్థాయిలో పనిచేసే ERC-20 ఒప్పందం ఉంది. దిగుమతి చేసుకున్న సంకేత భాషను చూడటానికి మీరు .deps > npmను విస్తరించవచ్చు.

  5. ఇది ERC-20 ఒప్పందంగా పనిచేస్తుందని చూడటానికి ఒప్పందాన్ని కంపైల్ చేయండి, డిప్లాయ్ చేయండి మరియు దానితో ప్రయోగాలు చేయండి. రీమిక్స్‌ను ఎలా ఉపయోగించాలో మీరు నేర్చుకోవలసి వస్తే, ఈ ట్యుటోరియల్‌ను ఉపయోగించండి (opens in a new tab).

సాధారణ తప్పులు

తప్పులు

వినియోగదారులు కొన్నిసార్లు తప్పు చిరునామాకు టోకెన్లను పంపుతారు. వారు ఏమి చేయాలనుకుంటున్నారో తెలుసుకోవడానికి మేము వారి మనస్సులను చదవలేనప్పటికీ, చాలా తరచుగా జరిగే మరియు గుర్తించడం సులభం అయిన రెండు రకాల లోపాలు ఉన్నాయి:

  1. ఒప్పందం యొక్క సొంత చిరునామాకు టోకెన్లను పంపడం. ఉదాహరణకు, ఆప్టిమిజం యొక్క OP టోకెన్ (opens in a new tab) రెండు నెలల కన్నా తక్కువ సమయంలో 120,000 కన్నా ఎక్కువ (opens in a new tab) OP టోకెన్లను సేకరించగలిగింది. ఇది ప్రజలు బహుశా కోల్పోయిన గణనీయమైన సంపదను సూచిస్తుంది.

  2. టోకెన్లను ఖాళీ చిరునామాకు పంపడం, అది ఒక బాహ్యంగా యాజమాన్యం గల ఖాతా లేదా స్మార్ట్ ఒప్పందంకు చెందనిది. ఇది ఎంత తరచుగా జరుగుతుందనే దానిపై నా దగ్గర గణాంకాలు లేనప్పటికీ, ఒక సంఘటన 20,000,000 టోకెన్‌లకు ఖర్చు కావచ్చు (opens in a new tab).

బదిలీలను నిరోధించడం

OpenZeppelin ERC-20 ఒప్పందం ఒక టోకెన్ బదిలీ చేయబడటానికి ముందు పిలువబడే ఒక హుక్, _beforeTokenTransfer (opens in a new tab) ను కలిగి ఉంటుంది. డిఫాల్ట్‌గా ఈ హుక్ ఏమీ చేయదు, కానీ మనం దానిపై మన స్వంత ఫంక్షనాలిటీని తగిలించవచ్చు, ఉదాహరణకు సమస్య ఉంటే వెనక్కితిప్పే తనిఖీలు.

హుక్‌ను ఉపయోగించడానికి, కన్‌స్ట్రక్టర్ తర్వాత ఈ ఫంక్షన్‌ను జోడించండి:

1 function _beforeTokenTransfer(address from, address to, uint256 amount)
2 internal virtual
3 override(ERC20)
4 {
5 super._beforeTokenTransfer(from, to, amount);
6 }

మీకు సాలిడిటీతో పెద్దగా పరిచయం లేకపోతే ఈ ఫంక్షన్‌లోని కొన్ని భాగాలు కొత్తగా ఉండవచ్చు:

1 internal virtual

virtual అనే కీవర్డ్ అర్థం ఏమిటంటే, మనం ERC20 నుండి ఫంక్షనాలిటీని వారసత్వంగా పొంది, ఈ ఫంక్షన్‌ను భర్తీ చేసినట్లే, ఇతర ఒప్పందాలు మన నుండి వారసత్వంగా పొంది ఈ ఫంక్షన్‌ను భర్తీ చేయవచ్చు.

1 override(ERC20)

_beforeTokenTransfer యొక్క ERC20 టోకెన్ నిర్వచనాన్ని మనం ఓవర్‌రైడ్ (opens in a new tab) చేస్తున్నామని మనం స్పష్టంగా పేర్కొనాలి. సాధారణంగా, భద్రతా దృక్కోణం నుండి, అవ్యక్త నిర్వచనాల కంటే స్పష్టమైన నిర్వచనాలు చాలా మేలు - మీరు చేసినది మీ కళ్ళ ముందు ఉంటే దాన్ని మీరు మర్చిపోలేరు. అందుకే మనం ఏ సూపర్‌క్లాస్ యొక్క _beforeTokenTransfer ను ఓవర్‌రైడ్ చేస్తున్నామో పేర్కొనవలసి ఉంటుంది.

1 super._beforeTokenTransfer(from, to, amount);

ఈ లైన్ మనం వారసత్వంగా పొందిన ఒప్పందం లేదా ఒప్పందాల యొక్క _beforeTokenTransfer ఫంక్షన్‌ను పిలుస్తుంది. ఈ సందర్భంలో, అది ERC20 మాత్రమే, Ownable కి ఈ హుక్ లేదు. ప్రస్తుతానికి ERC20._beforeTokenTransfer ఏమీ చేయనప్పటికీ, భవిష్యత్తులో ఫంక్షనాలిటీ జోడించబడినప్పుడు (మరియు మేము ఒప్పందాన్ని మళ్లీ అమలు చేయాలని నిర్ణయించుకున్నప్పుడు, ఎందుకంటే ఒప్పందాలు అమలు చేసిన తర్వాత మారవు) మేము దానిని పిలుస్తాము.

అవసరాలను కోడింగ్ చేయడం

మేము ఈ అవసరాలను ఫంక్షన్‌కు జోడించాలనుకుంటున్నాము:

  • to చిరునామా address(this)కు, అంటే ERC-20 ఒప్పందం యొక్క చిరునామాకు సమానంగా ఉండకూడదు.
  • to చిరునామా ఖాళీగా ఉండకూడదు, అది ఈ రెండిటిలో ఒకటి అయి ఉండాలి:
    • ఒక బాహ్యంగా యాజమాన్యం గల ఖాతా (EOA). ఒక చిరునామా EOA అవునో కాదో మనం నేరుగా తనిఖీ చేయలేము, కానీ మనం ఒక చిరునామా యొక్క ETH బ్యాలెన్స్‌ను తనిఖీ చేయవచ్చు. EOAలు దాదాపు ఎల్లప్పుడూ బ్యాలెన్స్‌ను కలిగి ఉంటాయి, అవి ఇకపై ఉపయోగించనప్పటికీ - వాటిని చివరి వీ వరకు క్లియర్ చేయడం కష్టం.
    • ఒక స్మార్ట్ ఒప్పందం. ఒక చిరునామా స్మార్ట్ ఒప్పందం అవునో కాదో పరీక్షించడం కొంచెం కష్టం. బాహ్య సంకేత భాష పొడవును తనిఖీ చేసే ఒక ఆప్‌కోడ్ ఉంది, దానిని EXTCODESIZE (opens in a new tab) అని పిలుస్తారు, కానీ అది సాలిడిటీలో నేరుగా అందుబాటులో లేదు. దాని కోసం మనం యుల్ (opens in a new tab) ను ఉపయోగించాలి, ఇది EVM అసెంబ్లీ. సాలిడిటీ నుండి మనం ఉపయోగించగల ఇతర విలువలు ఉన్నాయి (<address>.code మరియు <address>.codehash (opens in a new tab)), కానీ అవి ఎక్కువ ఖర్చు అవుతాయి.

కొత్త సంకేత భాషను లైన్ వారీగా పరిశీలిద్దాం:

1 require(to != address(this), "ఒప్పందం చిరునామాకు టోకెన్లను పంపలేరు");

ఇది మొదటి అవసరం, to మరియు this(address) ఒకటే కాదని తనిఖీ చేయండి.

1 bool isToContract;
2 assembly {
3 isToContract := gt(extcodesize(to), 0)
4 }

ఒక చిరునామా ఒప్పందం అవునో కాదో మనం ఈ విధంగా తనిఖీ చేస్తాము. మేము Yul నుండి నేరుగా అవుట్‌పుట్‌ను స్వీకరించలేము, కాబట్టి బదులుగా మేము ఫలితాన్ని ఉంచడానికి ఒక వేరియబుల్‌ను నిర్వచిస్తాము (ఈ సందర్భంలో isToContract). Yul పనిచేసే విధానం ఏమిటంటే, ప్రతి ఆప్‌కోడ్ ఒక ఫంక్షన్‌గా పరిగణించబడుతుంది. కాబట్టి మొదట మనం ఒప్పందం పరిమాణాన్ని పొందడానికి EXTCODESIZE (opens in a new tab) ను పిలుస్తాము, ఆపై అది సున్నా కాదని తనిఖీ చేయడానికి GT (opens in a new tab) ని ఉపయోగిస్తాము (మేము అన్‌సైన్డ్ పూర్ణాంకాలతో వ్యవహరిస్తున్నాము, కాబట్టి అది ప్రతికూలంగా ఉండదు). ఆ తర్వాత మనం ఫలితాన్ని isToContract కు వ్రాస్తాము.

1 require(to.balance != 0 || isToContract, "ఖాళీ చిరునామాకు టోకెన్లను పంపలేరు");

చివరగా, ఖాళీ చిరునామాల కోసం అసలైన తనిఖీ మనకు ఉంది.

పరిపాలనా యాక్సెస్

తప్పులను రద్దు చేయగల నిర్వాహకుడు ఉండటం కొన్నిసార్లు ఉపయోగకరంగా ఉంటుంది. దుర్వినియోగం యొక్క సంభావ్యతను తగ్గించడానికి, ఈ నిర్వాహకుడు ఒక మల్టీసిగ్ (opens in a new tab) కావచ్చు, తద్వారా ఒక చర్యపై బహుళ వ్యక్తులు అంగీకరించాలి. ఈ ఆర్టికల్‌లో మనకు రెండు పరిపాలనా లక్షణాలు ఉంటాయి:

  1. ఖాతాలను ఫ్రీజింగ్ మరియు అన్‌ఫ్రీజింగ్ చేయడం. ఉదాహరణకు, ఒక ఖాతా రాజీ పడినప్పుడు ఇది ఉపయోగకరంగా ఉంటుంది.

  2. ఆస్తి శుభ్రపరచడం.

    చట్టబద్ధతను పొందటానికి కొన్నిసార్లు మోసగాళ్ళు నిజమైన టోకెన్ యొక్క ఒప్పందానికి మోసపూరిత టోకెన్లను పంపుతారు. ఉదాహరణకు, ఇక్కడ చూడండి (opens in a new tab). చట్టబద్ధమైన ERC-20 ఒప్పందం 0x4200....0042 (opens in a new tab). అదిగా నటిస్తున్న స్కామ్ 0x234....bbe (opens in a new tab).

    ప్రజలు పొరపాటున మన ఒప్పందానికి చట్టబద్ధమైన ERC-20 టోకెన్లను పంపే అవకాశం కూడా ఉంది, వాటిని బయటకు తీయడానికి ఒక మార్గం కావడానికి ఇది మరొక కారణం.

OpenZeppelin పరిపాలనా యాక్సెస్‌ను ప్రారంభించడానికి రెండు యంత్రాంగాలను అందిస్తుంది:

సరళత కోసం, ఈ ఆర్టికల్‌లో మనం Ownable ని ఉపయోగిస్తాము.

ఒప్పందాలను ఫ్రీజింగ్ మరియు థావింగ్ చేయడం

ఒప్పందాలను ఫ్రీజింగ్ మరియు థావింగ్ చేయడానికి అనేక మార్పులు అవసరం:

  • ఏ చిరునామాలు ఫ్రీజ్ చేయబడ్డాయో ట్రాక్ చేయడానికి చిరునామాల నుండి బూలియన్‌లకు (opens in a new tab) ఒక మ్యాపింగ్ (opens in a new tab). అన్ని విలువలు ప్రారంభంలో సున్నా, ఇది బూలియన్ విలువల కోసం తప్పుగా వ్యాఖ్యానించబడుతుంది. డిఫాల్ట్‌గా ఖాతాలు ఫ్రీజ్ చేయబడవు కాబట్టి మనం కోరుకునేది ఇదే.

    1 mapping(address => bool) public frozenAccounts;
  • ఒక ఖాతా ఫ్రీజ్ చేయబడినప్పుడు లేదా థా చేయబడినప్పుడు ఆసక్తి ఉన్న ఎవరికైనా తెలియజేయడానికి ఈవెంట్‌లు (opens in a new tab). సాంకేతికంగా చెప్పాలంటే ఈ చర్యలకు ఈవెంట్‌లు అవసరం లేదు, కానీ ఇది ఆఫ్‌చైన్ సంకేత భాషకు ఈ ఈవెంట్‌లను వినడానికి మరియు ఏమి జరుగుతుందో తెలుసుకోవడానికి సహాయపడుతుంది. వేరొకరికి సంబంధించినది ఏదైనా జరిగినప్పుడు వాటిని విడుదల చేయడం స్మార్ట్ ఒప్పందం యొక్క మంచి పద్ధతిగా పరిగణించబడుతుంది.

    ఈవెంట్‌లు ఇండెక్స్ చేయబడ్డాయి కాబట్టి ఒక ఖాతా ఫ్రీజ్ చేయబడిన లేదా థా చేయబడిన అన్ని సార్లు శోధించడం సాధ్యమవుతుంది.

    1 // ఖాతాలు ఫ్రీజ్ చేయబడినప్పుడు లేదా అన్‌ఫ్రీజ్ చేయబడినప్పుడు
    2 event AccountFrozen(address indexed _addr);
    3 event AccountThawed(address indexed _addr);
  • ఖాతాలను ఫ్రీజింగ్ మరియు థావింగ్ చేయడానికి ఫంక్షన్లు. ఈ రెండు ఫంక్షన్లు దాదాపు ఒకే విధంగా ఉంటాయి, కాబట్టి మనం ఫ్రీజ్ ఫంక్షన్‌ను మాత్రమే పరిశీలిస్తాము.

    1 function freezeAccount(address addr)
    2 public
    3 onlyOwner

    public (opens in a new tab) అని మార్క్ చేయబడిన ఫంక్షన్లను ఇతర స్మార్ట్ ఒప్పందాల నుండి లేదా నేరుగా లావాదేవీ ద్వారా పిలవవచ్చు.

    1 {
    2 require(!frozenAccounts[addr], "ఖాతా ఇప్పటికే ఫ్రీజ్ చేయబడింది");
    3 frozenAccounts[addr] = true;
    4 emit AccountFrozen(addr);
    5 } // ఫ్రీజ్అకౌంట్

    ఖాతా ఇప్పటికే ఫ్రీజ్ చేయబడితే, వెనక్కి తిప్పండి. లేకపోతే, దానిని ఫ్రీజ్ చేసి, ఒక ఈవెంట్‌ను emit చేయండి.

  • ఫ్రీజ్ చేయబడిన ఖాతా నుండి డబ్బు తరలించకుండా నిరోధించడానికి _beforeTokenTransferని మార్చండి. ఫ్రీజ్ చేయబడిన ఖాతాలోకి ఇంకా డబ్బు బదిలీ చేయవచ్చని గమనించండి.

    1 require(!frozenAccounts[from], "ఖాతా ఫ్రీజ్ చేయబడింది");

ఆస్తి శుభ్రపరచడం

ఈ ఒప్పందం ద్వారా ఉంచబడిన ERC-20 టోకెన్లను విడుదల చేయడానికి, మనం అవి చెందిన టోకెన్ ఒప్పందంపై ఒక ఫంక్షన్‌ను పిలవాలి, అది transfer (opens in a new tab) లేదా approve (opens in a new tab). ఈ సందర్భంలో అనుమతులపై గ్యాస్‌ను వృథా చేయడంలో అర్థం లేదు, మనం నేరుగా బదిలీ చేయవచ్చు.

1 function cleanupERC20(
2 address erc20,
3 address dest
4 )
5 public
6 onlyOwner
7 {
8 IERC20 token = IERC20(erc20);

మనం చిరునామాను స్వీకరించినప్పుడు ఒక ఒప్పందం కోసం ఒక ఆబ్జెక్ట్‌ను సృష్టించడానికి ఇది సింటాక్స్. మనం దీన్ని చేయగలం ఎందుకంటే మనకు మూల సంకేత భాషలో భాగంగా ERC20 టోకెన్‌ల నిర్వచనం ఉంది (లైన్ 4 చూడండి), మరియు ఆ ఫైల్ IERC20 కోసం నిర్వచనాన్ని (opens in a new tab), అంటే OpenZeppelin ERC-20 ఒప్పందం కోసం ఇంటర్‌ఫేస్‌ను కలిగి ఉంది.

1 uint balance = token.balanceOf(address(this));
2 token.transfer(dest, balance);
3 }

ఇది ఒక శుభ్రపరిచే ఫంక్షన్, కాబట్టి మనం ఏ టోకెన్లను వదిలివేయకూడదని భావించవచ్చు. వినియోగదారుడి నుండి బ్యాలెన్స్‌ను మాన్యువల్‌గా పొందడానికి బదులుగా, మనం ఈ ప్రక్రియను ఆటోమేట్ చేయవచ్చు.

ముగింపు

ఇది ఒక సంపూర్ణ పరిష్కారం కాదు - "వినియోగదారుడు తప్పు చేసాడు" అనే సమస్యకు సంపూర్ణ పరిష్కారం లేదు. అయితే, ఈ రకమైన తనిఖీలను ఉపయోగించడం కనీసం కొన్ని తప్పులను నివారించగలదు. ఖాతాలను స్తంభింపజేసే సామర్థ్యం ప్రమాదకరమైనప్పటికీ, హ్యాకర్‌కు దొంగిలించబడిన నిధులను నిరాకరించడం ద్వారా కొన్ని హ్యాక్‌ల నష్టాన్ని పరిమితం చేయడానికి ఉపయోగించవచ్చు.

నా మరిన్ని పనుల కోసం ఇక్కడ చూడండి (opens in a new tab).

పేజీ చివరి అప్‌డేట్: 3 మార్చి, 2026

ఈ ట్యుటోరియల్ ఉపయోగపడిందా?