ERC-20 కాంట్రాక్ట్ వాక్త్రూ
పరిచయం
ఎథీరియం యొక్క అత్యంత సాధారణ ఉపయోగాలలో ఒకటి, ఒక సమూహం వర్తకం చేయదగిన టోకెన్ను సృష్టించడం, ఒక రకంగా చెప్పాలంటే వారి స్వంత కరెన్సీని సృష్టించడం. ఈ టోకెన్లు సాధారణంగా ఒక ప్రమాణాన్ని అనుసరిస్తాయి, అదే ERC-20. ఈ ప్రమాణం అన్ని ERC-20 టోకెన్లతో పనిచేసే లిక్విడిటీ పూల్స్ మరియు వాలెట్ల వంటి సాధనాలను వ్రాయడాన్ని సాధ్యం చేస్తుంది. ఈ వ్యాసంలో మనం ఓపెన్జెప్పెలిన్ Solidity ERC20 అమలు (opens in a new tab)తో పాటు ఇంటర్ఫేస్ నిర్వచనాన్ని (opens in a new tab) విశ్లేషిస్తాము.
ఇది ఉల్లేఖించబడిన సోర్స్ కోడ్. మీరు ERC-20ని అమలు చేయాలనుకుంటే, ఈ ట్యుటోరియల్ చదవండి (opens in a new tab).
ఇంటర్ఫేస్
ERC-20 వంటి ప్రమాణం యొక్క ఉద్దేశ్యం ఏమిటంటే, వాలెట్లు మరియు వికేంద్రీకృత ఎక్స్ఛేంజీల వంటి అప్లికేషన్లలో పరస్పరం పనిచేయగల అనేక టోకెన్ల అమలులను అనుమతించడం. దానిని సాధించడానికి, మనం ఒక ఇంటర్ఫేస్ (opens in a new tab)ని సృష్టిస్తాము. టోకెన్ కాంట్రాక్ట్ను ఉపయోగించాల్సిన ఏ కోడ్ అయినా ఇంటర్ఫేస్లోని అవే నిర్వచనాలను ఉపయోగించవచ్చు మరియు దానిని ఉపయోగించే అన్ని టోకెన్ కాంట్రాక్ట్లకు అనుకూలంగా ఉంటుంది, అది మెటామాస్క్ వంటి వాలెట్ అయినా, etherscan.io వంటి dapp అయినా లేదా లిక్విడిటీ పూల్ వంటి వేరే కాంట్రాక్ట్ అయినా.
మీరు అనుభవజ్ఞులైన ప్రోగ్రామర్ అయితే, Java (opens in a new tab)లో లేదా C హెడర్ ఫైల్లలో (opens in a new tab) కూడా ఇలాంటి నిర్మాణాలను చూసినట్లు మీకు బహుశా గుర్తుండే ఉంటుంది.
ఇది ఓపెన్జెప్పెలిన్ నుండి ERC-20 ఇంటర్ఫేస్ (opens in a new tab) యొక్క నిర్వచనం. ఇది మానవులు చదవగలిగే ప్రమాణం (opens in a new tab) యొక్క Solidity కోడ్లోకి అనువాదం. వాస్తవానికి, ఇంటర్ఫేస్ దేనినైనా ఎలా చేయాలో నిర్వచించదు. అది దిగువ కాంట్రాక్ట్ సోర్స్ కోడ్లో వివరించబడింది.
// SPDX-License-Identifier: MIT
Solidity ఫైల్లు లైసెన్స్ ఐడెంటిఫైయర్ను కలిగి ఉండాలి. మీరు లైసెన్స్ల జాబితాను ఇక్కడ చూడవచ్చు (opens in a new tab). మీకు వేరే లైసెన్స్ అవసరమైతే, దానిని వ్యాఖ్యలలో వివరించండి.
pragma solidity >=0.6.0 <0.8.0;
Solidity భాష ఇప్పటికీ వేగంగా అభివృద్ధి చెందుతోంది మరియు కొత్త వెర్షన్లు పాత కోడ్కు అనుకూలంగా ఉండకపోవచ్చు (ఇక్కడ చూడండి (opens in a new tab)). అందువల్ల, భాష యొక్క కనీస వెర్షన్ను మాత్రమే కాకుండా, గరిష్ట వెర్షన్ను కూడా పేర్కొనడం మంచిది, అంటే మీరు కోడ్ను పరీక్షించిన తాజా వెర్షన్.
/**
* @dev EIP లో నిర్వచించిన విధంగా ERC-20 ప్రమాణం యొక్క ఇంటర్ఫేస్.
*/
వ్యాఖ్యలోని @dev అనేది NatSpec ఫార్మాట్ (opens in a new tab)లో భాగం, ఇది సోర్స్ కోడ్ నుండి డాక్యుమెంటేషన్ను రూపొందించడానికి ఉపయోగించబడుతుంది.
interface IERC20 {
సాధారణంగా, ఇంటర్ఫేస్ పేర్లు Iతో ప్రారంభమవుతాయి.
/**
* @dev ఉనికిలో ఉన్న టోకెన్ల మొత్తాన్ని అందిస్తుంది.
*/
function totalSupply() external view returns (uint256);
ఈ ఫంక్షన్ external, అంటే దీనిని కాంట్రాక్ట్ వెలుపల నుండి మాత్రమే కాల్ చేయవచ్చు (opens in a new tab).
ఇది కాంట్రాక్ట్లోని టోకెన్ల మొత్తం సరఫరాను అందిస్తుంది. ఈ విలువ ఎథీరియంలో అత్యంత సాధారణ రకమైన అన్సైన్డ్ 256 బిట్లను ఉపయోగించి అందించబడుతుంది (256 బిట్లు అనేది EVM యొక్క స్థానిక వర్డ్ సైజు). ఈ ఫంక్షన్ view కూడా, అంటే ఇది స్థితిని మార్చదు, కాబట్టి బ్లాక్చైన్లోని ప్రతి నోడ్ దీనిని రన్ చేయడానికి బదులుగా ఒకే నోడ్లో అమలు చేయవచ్చు. ఈ రకమైన ఫంక్షన్ లావాదేవీని రూపొందించదు మరియు గ్యాస్ ఖర్చు చేయదు.
గమనిక: సిద్ధాంతపరంగా, కాంట్రాక్ట్ సృష్టికర్త వాస్తవ విలువ కంటే తక్కువ మొత్తం సరఫరాను అందించడం ద్వారా మోసం చేయవచ్చని అనిపించవచ్చు, తద్వారా ప్రతి టోకెన్ వాస్తవానికి ఉన్నదానికంటే ఎక్కువ విలువైనదిగా కనిపిస్తుంది. అయితే, ఆ భయం బ్లాక్చైన్ యొక్క నిజమైన స్వభావాన్ని విస్మరిస్తుంది. బ్లాక్చైన్లో జరిగే ప్రతిదీ ప్రతి నోడ్ ద్వారా ధృవీకరించబడుతుంది. దీనిని సాధించడానికి, ప్రతి కాంట్రాక్ట్ యొక్క మెషిన్ లాంగ్వేజ్ కోడ్ మరియు నిల్వ ప్రతి నోడ్లో అందుబాటులో ఉంటుంది. మీ కాంట్రాక్ట్ కోసం మీరు Solidity కోడ్ను ప్రచురించాల్సిన అవసరం లేనప్పటికీ, మీరు సోర్స్ కోడ్ను మరియు అది కంపైల్ చేయబడిన Solidity వెర్షన్ను ప్రచురిస్తే తప్ప ఎవరూ మిమ్మల్ని తీవ్రంగా పరిగణించరు, తద్వారా మీరు అందించిన మెషిన్ లాంగ్వేజ్ కోడ్తో దాన్ని ధృవీకరించవచ్చు. ఉదాహరణకు, ఈ కాంట్రాక్ట్ (opens in a new tab) చూడండి.
/**
* @dev `account` (ఖాతా) స్వంతమైన టోకెన్ల మొత్తాన్ని అందిస్తుంది.
*/
function balanceOf(address account) external view returns (uint256);
పేరు సూచించినట్లుగా, balanceOf ఒక ఖాతా యొక్క బ్యాలెన్స్ను అందిస్తుంది. ఎథీరియం ఖాతాలు Solidityలో address రకాన్ని ఉపయోగించి గుర్తించబడతాయి, ఇది 160 బిట్లను కలిగి ఉంటుంది.
ఇది external మరియు view కూడా.
/**
* @dev కాలర్ ఖాతా నుండి `recipient` కు `amount` టోకెన్లను బదిలీ చేస్తుంది.
*
* ఆపరేషన్ విజయవంతమైందో లేదో సూచించే బూలియన్ విలువను అందిస్తుంది.
*
* {Transfer} ఈవెంట్ను విడుదల చేస్తుంది.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
transfer ఫంక్షన్ కాలర్ నుండి వేరే చిరునామాకు టోకెన్లను బదిలీ చేస్తుంది. ఇది స్థితి మార్పును కలిగి ఉంటుంది, కాబట్టి ఇది view కాదు.
వినియోగదారు ఈ ఫంక్షన్ను కాల్ చేసినప్పుడు అది లావాదేవీని సృష్టిస్తుంది మరియు గ్యాస్ ఖర్చు అవుతుంది. ఇది ఈవెంట్ గురించి బ్లాక్చైన్లోని ప్రతి ఒక్కరికీ తెలియజేయడానికి Transfer అనే ఈవెంట్ను కూడా విడుదల చేస్తుంది.
ఈ ఫంక్షన్ రెండు వేర్వేరు రకాల కాలర్ల కోసం రెండు రకాల అవుట్పుట్లను కలిగి ఉంటుంది:
- వినియోగదారు ఇంటర్ఫేస్ నుండి నేరుగా ఫంక్షన్ను కాల్ చేసే వినియోగదారులు. సాధారణంగా వినియోగదారు లావాదేవీని సమర్పిస్తారు మరియు ప్రతిస్పందన కోసం వేచి ఉండరు, దీనికి అనిశ్చిత సమయం పట్టవచ్చు. లావాదేవీ రశీదు (ఇది లావాదేవీ హాష్ ద్వారా గుర్తించబడుతుంది) కోసం వెతకడం ద్వారా లేదా
Transferఈవెంట్ కోసం వెతకడం ద్వారా వినియోగదారు ఏమి జరిగిందో చూడగలరు. - మొత్తం లావాదేవీలో భాగంగా ఫంక్షన్ను కాల్ చేసే ఇతర కాంట్రాక్ట్లు. ఆ కాంట్రాక్ట్లు వెంటనే ఫలితాన్ని పొందుతాయి, ఎందుకంటే అవి ఒకే లావాదేవీలో రన్ అవుతాయి, కాబట్టి అవి ఫంక్షన్ రిటర్న్ విలువను ఉపయోగించగలవు.
కాంట్రాక్ట్ స్థితిని మార్చే ఇతర ఫంక్షన్ల ద్వారా కూడా ఇదే రకమైన అవుట్పుట్ సృష్టించబడుతుంది.
అనుమతి మొత్తాలు ఒక ఖాతా వేరొక యజమానికి చెందిన కొన్ని టోకెన్లను ఖర్చు చేయడానికి అనుమతిస్తాయి. ఉదాహరణకు, విక్రేతలుగా వ్యవహరించే కాంట్రాక్ట్లకు ఇది ఉపయోగకరంగా ఉంటుంది. కాంట్రాక్ట్లు ఈవెంట్ల కోసం పర్యవేక్షించలేవు, కాబట్టి కొనుగోలుదారు నేరుగా విక్రేత కాంట్రాక్ట్కు టోకెన్లను బదిలీ చేస్తే, దానికి చెల్లింపు జరిగిందని ఆ కాంట్రాక్ట్కు తెలియదు. బదులుగా, కొనుగోలుదారు విక్రేత కాంట్రాక్ట్ను కొంత మొత్తాన్ని ఖర్చు చేయడానికి అనుమతిస్తాడు మరియు విక్రేత ఆ మొత్తాన్ని బదిలీ చేస్తాడు. ఇది విక్రేత కాంట్రాక్ట్ కాల్ చేసే ఫంక్షన్ ద్వారా చేయబడుతుంది, కాబట్టి అది విజయవంతమైందో లేదో విక్రేత కాంట్రాక్ట్ తెలుసుకోగలదు.
/**
* @dev {transferFrom} ద్వారా `owner` తరపున ఖర్చు చేయడానికి `spender` కు అనుమతించబడిన మిగిలిన టోకెన్ల సంఖ్యను అందిస్తుంది. ఇది అప్రమేయంగా సున్నా ఉంటుంది.
*
* {approve} లేదా {transferFrom} కాల్ చేసినప్పుడు ఈ విలువ మారుతుంది.
*/
function allowance(address owner, address spender) external view returns (uint256);
allowance ఫంక్షన్ ఒక చిరునామా (owner) మరొక చిరునామా (spender) ఖర్చు చేయడానికి అనుమతించే అనుమతి మొత్తం ఏమిటో చూడటానికి ఎవరినైనా క్వెరీ చేయడానికి అనుమతిస్తుంది.
/**
* @dev కాలర్ టోకెన్లపై `spender` యొక్క అనుమతి మొత్తం గా `amount` ను సెట్ చేస్తుంది.
*
* ఆపరేషన్ విజయవంతమైందో లేదో సూచించే బూలియన్ విలువను అందిస్తుంది.
*
* ముఖ్యం: ఈ పద్ధతితో అనుమతి మొత్తం మార్చడం వల్ల, దురదృష్టకర లావాదేవీ క్రమం ద్వారా ఎవరైనా పాత మరియు కొత్త అనుమతి మొత్తం రెండింటినీ ఉపయోగించే ప్రమాదం ఉందని గమనించండి. ఈ రేస్ కండిషన్ను తగ్గించడానికి ఒక పరిష్కారం ఏమిటంటే, ముందుగా ఖర్చు చేసేవారి అనుమతి మొత్తం 0 కి తగ్గించి, ఆ తర్వాత కావలసిన విలువను సెట్ చేయడం:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* {Approval} ఈవెంట్ను విడుదల చేస్తుంది.
*/
function approve(address spender, uint256 amount) external returns (bool);
approve ఫంక్షన్ అనుమతి మొత్తాన్ని సృష్టిస్తుంది. ఇది ఎలా దుర్వినియోగం చేయబడుతుందనే దాని గురించి సందేశాన్ని తప్పకుండా చదవండి. ఎథీరియంలో మీరు మీ స్వంత లావాదేవీల క్రమాన్ని నియంత్రిస్తారు, కానీ అవతలి వైపు లావాదేవీ జరిగిందని మీరు చూసే వరకు మీ స్వంత లావాదేవీని సమర్పించకపోతే తప్ప, ఇతరుల లావాదేవీలు ఏ క్రమంలో అమలు చేయబడతాయో మీరు నియంత్రించలేరు.
/**
* @dev అనుమతి మొత్తం యంత్రాంగాన్ని ఉపయోగించి `sender` నుండి `recipient` కు `amount` టోకెన్లను బదిలీ చేస్తుంది. ఆ తర్వాత కాలర్ యొక్క అనుమతి మొత్తం నుండి `amount` తీసివేయబడుతుంది.
*
* ఆపరేషన్ విజయవంతమైందో లేదో సూచించే బూలియన్ విలువను అందిస్తుంది.
*
* {Transfer} ఈవెంట్ను విడుదల చేస్తుంది.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
చివరగా, అనుమతి మొత్తాన్ని వాస్తవంగా ఖర్చు చేయడానికి ఖర్చు చేసే వ్యక్తి ద్వారా transferFrom ఉపయోగించబడుతుంది.
/**
* @dev ఒక ఖాతా (`from`) నుండి మరొక ఖాతా (`to`) కు `value` టోకెన్లు బదిలీ చేయబడినప్పుడు విడుదల చేయబడుతుంది.
*
* `value` సున్నా కూడా కావచ్చని గమనించండి.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev {approve} కు కాల్ చేయడం ద్వారా `owner` కోసం `spender` యొక్క అనుమతి మొత్తం సెట్ చేయబడినప్పుడు విడుదల చేయబడుతుంది. `value` అనేది కొత్త అనుమతి మొత్తం.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
ERC-20 కాంట్రాక్ట్ యొక్క స్థితి మారినప్పుడు ఈ ఈవెంట్లు విడుదల చేయబడతాయి.
అసలు కాంట్రాక్ట్
ఇది ERC-20 ప్రమాణాన్ని అమలు చేసే అసలు కాంట్రాక్ట్, ఇక్కడ నుండి తీసుకోబడింది (opens in a new tab). ఇది ఉన్నది ఉన్నట్లుగా ఉపయోగించడానికి ఉద్దేశించబడలేదు, కానీ మీరు దానిని ఉపయోగించదగినదిగా విస్తరించడానికి దాని నుండి వారసత్వంగా పొందవచ్చు (opens in a new tab).
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
దిగుమతి స్టేట్మెంట్లు
పై ఇంటర్ఫేస్ నిర్వచనాలతో పాటు, కాంట్రాక్ట్ నిర్వచనం మరో రెండు ఫైల్లను దిగుమతి చేస్తుంది:
import "../../GSN/Context.sol";
import "./IERC20.sol";
import "../../math/SafeMath.sol";
GSN/Context.solఅనేది OpenGSN (opens in a new tab)ని ఉపయోగించడానికి అవసరమైన నిర్వచనాలు, ఇది ఈథర్ లేని వినియోగదారులను బ్లాక్చైన్ను ఉపయోగించడానికి అనుమతించే సిస్టమ్. ఇది పాత వెర్షన్ అని గమనించండి, మీరు OpenGSNతో అనుసంధానించాలనుకుంటే ఈ ట్యుటోరియల్ని ఉపయోగించండి (opens in a new tab).- SafeMath లైబ్రరీ (opens in a new tab), ఇది Solidity వెర్షన్లు <0.8.0 కోసం అంకగణిత ఓవర్ఫ్లోలు/అండర్ఫ్లోలను నిరోధిస్తుంది. Solidity ≥0.8.0లో, అంకగణిత కార్యకలాపాలు ఓవర్ఫ్లో/అండర్ఫ్లోపై స్వయంచాలకంగా రివర్ట్ అవుతాయి, తద్వారా SafeMath అనవసరం అవుతుంది. పాత కంపైలర్ వెర్షన్లతో బ్యాక్వర్డ్ అనుకూలత కోసం ఈ కాంట్రాక్ట్ SafeMathని ఉపయోగిస్తుంది.
ఈ వ్యాఖ్య కాంట్రాక్ట్ యొక్క ఉద్దేశ్యాన్ని వివరిస్తుంది.
/**
* @dev {IERC20} ఇంటర్ఫేస్ యొక్క అమలు.
*
* ఈ అమలు టోకెన్లు సృష్టించబడే విధానానికి సంబంధం లేకుండా ఉంటుంది. అంటే {_mint} ఉపయోగించి ఉత్పాదక కాంట్రాక్ట్ లో సరఫరా యంత్రాంగాన్ని జోడించాలి.
* సాధారణ యంత్రాంగం కోసం {ERC20PresetMinterPauser} చూడండి.
*
* చిట్కా: వివరణాత్మక వ్యాసం కోసం మా గైడ్ చూడండి
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[సరఫరా యంత్రాంగాలను ఎలా అమలు చేయాలి].
*
* మేము సాధారణ ఓపెన్జెప్పెలిన్ మార్గదర్శకాలను అనుసరించాము: విఫలమైనప్పుడు `false` అందించడానికి బదులుగా ఫంక్షన్లు రివర్ట్ అవుతాయి. ఈ ప్రవర్తన సాంప్రదాయకమైనది మరియు ERC-20 అప్లికేషన్ల అంచనాలతో విభేదించదు.
*
* అదనంగా, {transferFrom} కు కాల్ చేసినప్పుడు {Approval} ఈవెంట్ విడుదల చేయబడుతుంది.
* ఇది అప్లికేషన్లు ఆ ఈవెంట్లను వినడం ద్వారా అన్ని ఖాతా ల కోసం అనుమతి మొత్తం ను పునర్నిర్మించడానికి అనుమతిస్తుంది. EIP యొక్క ఇతర అమలులు ఈ ఈవెంట్లను విడుదల చేయకపోవచ్చు, ఎందుకంటే ఇది స్పెసిఫికేషన్ ద్వారా అవసరం లేదు.
*
* చివరగా, అనుమతి మొత్తం సెట్ చేయడంలో ఉన్న ప్రసిద్ధ సమస్యలను తగ్గించడానికి ప్రామాణికం కాని {decreaseAllowance} మరియు {increaseAllowance}
* ఫంక్షన్లు జోడించబడ్డాయి. {IERC20-approve} చూడండి.
*/
కాంట్రాక్ట్ నిర్వచనం
contract ERC20 is Context, IERC20 {
ఈ లైన్ వారసత్వాన్ని నిర్దేశిస్తుంది, ఈ సందర్భంలో పై నుండి IERC20 మరియు OpenGSN కోసం Context నుండి.
using SafeMath for uint256;
ఈ లైన్ SafeMath లైబ్రరీని uint256 రకానికి జత చేస్తుంది. మీరు ఈ లైబ్రరీని
ఇక్కడ (opens in a new tab) కనుగొనవచ్చు.
వేరియబుల్ నిర్వచనాలు
ఈ నిర్వచనాలు కాంట్రాక్ట్ యొక్క స్థితి వేరియబుల్స్ను నిర్దేశిస్తాయి. ఈ వేరియబుల్స్ privateగా ప్రకటించబడ్డాయి, కానీ దాని అర్థం బ్లాక్చైన్లోని ఇతర కాంట్రాక్ట్లు వాటిని చదవలేవని మాత్రమే. బ్లాక్చైన్లో ఎలాంటి రహస్యాలు లేవు, ప్రతి నోడ్లోని సాఫ్ట్వేర్ ప్రతి బ్లాక్ వద్ద ప్రతి కాంట్రాక్ట్ యొక్క స్థితిని కలిగి ఉంటుంది. సాధారణంగా, స్థితి వేరియబుల్స్కు _<something> అని పేరు పెడతారు.
మొదటి రెండు వేరియబుల్స్ మ్యాపింగ్లు (opens in a new tab), అంటే కీలు సంఖ్యా విలువలు కావడం మినహా అవి దాదాపు అసోసియేటివ్ అర్రేల (opens in a new tab) వలె ప్రవర్తిస్తాయి. డిఫాల్ట్ (సున్నా) కంటే భిన్నమైన విలువలను కలిగి ఉన్న ఎంట్రీలకు మాత్రమే నిల్వ కేటాయించబడుతుంది.
mapping (address => uint256) private _balances;
మొదటి మ్యాపింగ్, _balances, అనేది చిరునామాలు మరియు ఈ టోకెన్ యొక్క వాటి సంబంధిత బ్యాలెన్స్లు. బ్యాలెన్స్ను యాక్సెస్ చేయడానికి, ఈ సింటాక్స్ను ఉపయోగించండి: _balances[<address>].
mapping (address => mapping (address => uint256)) private _allowances;
ఈ వేరియబుల్, _allowances, ఇంతకు ముందు వివరించిన అనుమతి మొత్తాలను నిల్వ చేస్తుంది. మొదటి సూచిక టోకెన్ల యజమాని, మరియు రెండవది అనుమతి మొత్తంతో ఉన్న కాంట్రాక్ట్. చిరునామా B ఖాతా నుండి చిరునామా A ఖర్చు చేయగల మొత్తాన్ని యాక్సెస్ చేయడానికి, _allowances[B][A] ఉపయోగించండి.
uint256 private _totalSupply;
పేరు సూచించినట్లుగా, ఈ వేరియబుల్ టోకెన్ల మొత్తం సరఫరాను ట్రాక్ చేస్తుంది.
string private _name;
string private _symbol;
uint8 private _decimals;
ఈ మూడు వేరియబుల్స్ చదవడానికి వీలుగా ఉండటానికి ఉపయోగించబడతాయి. మొదటి రెండు స్వయంగా అర్థమయ్యేలా ఉంటాయి, కానీ _decimals
అలా కాదు.
ఒక వైపు, ఎథీరియంలో ఫ్లోటింగ్ పాయింట్ లేదా ఫ్రాక్షనల్ వేరియబుల్స్ లేవు. మరోవైపు, మానవులు టోకెన్లను విభజించగలగడాన్ని ఇష్టపడతారు. కరెన్సీ కోసం ప్రజలు బంగారాన్ని ఎంచుకోవడానికి ఒక కారణం ఏమిటంటే, ఎవరైనా ఒక బాతు విలువైన ఆవును కొనాలనుకున్నప్పుడు చిల్లర ఇవ్వడం కష్టంగా ఉండేది.
దీనికి పరిష్కారం పూర్ణాంకాలను ట్రాక్ చేయడం, కానీ నిజమైన టోకెన్కు బదులుగా దాదాపు విలువలేని ఫ్రాక్షనల్ టోకెన్ను లెక్కించడం. ఈథర్ విషయంలో, ఫ్రాక్షనల్ టోకెన్ను Wei అని పిలుస్తారు మరియు 10^18 Wei ఒక ETHకి సమానం. రాసే సమయానికి, 10,000,000,000,000 Wei సుమారుగా ఒక US లేదా యూరో సెంట్కి సమానం.
టోకెన్ బ్యాలెన్స్ను ఎలా ప్రదర్శించాలో అప్లికేషన్లు తెలుసుకోవాలి. ఒక వినియోగదారు వద్ద 3,141,000,000,000,000,000 Wei ఉంటే, అది
3.14 ETH ఆ? 31.41 ETH ఆ? 3,141 ETH ఆ? ఈథర్ విషయంలో ఇది ETHకి 10^18 Weiగా నిర్వచించబడింది, కానీ మీ టోకెన్ కోసం మీరు వేరే విలువను ఎంచుకోవచ్చు. టోకెన్ను విభజించడం అర్థవంతంగా లేకపోతే, మీరు సున్నా యొక్క
_decimals విలువను ఉపయోగించవచ్చు. మీరు ETH వలె అదే ప్రమాణాన్ని ఉపయోగించాలనుకుంటే, విలువ 18ని ఉపయోగించండి.
కన్స్ట్రక్టర్
/**
* @dev {name} మరియు {symbol} కోసం విలువలను సెట్ చేస్తుంది, {decimals} ను 18 అప్రమేయ విలువతో ప్రారంభిస్తుంది.
*
* {decimals} కోసం వేరే విలువను ఎంచుకోవడానికి, {_setupDecimals} ను ఉపయోగించండి.
*
* ఈ మూడు విలువలు మార్చలేనివి: కన్స్ట్రక్టర్ సమయంలో వాటిని ఒక్కసారి మాత్రమే సెట్ చేయవచ్చు.
*/
constructor (string memory name_, string memory symbol_) public {
// Solidity ≥0.7.0 లో, 'public' అనేది అవ్యక్తంగా ఉంటుంది మరియు వదిలివేయవచ్చు.
_name = name_;
_symbol = symbol_;
_decimals = 18;
}
కాంట్రాక్ట్ మొదటిసారి సృష్టించబడినప్పుడు కన్స్ట్రక్టర్ కాల్ చేయబడుతుంది. సాధారణంగా, ఫంక్షన్ పారామితులకు <something>_ అని పేరు పెడతారు.
యూజర్ ఇంటర్ఫేస్ ఫంక్షన్లు
/**
* @dev టోకెన్ పేరును అందిస్తుంది.
*/
function name() public view returns (string memory) {
return _name;
}
/**
* @dev టోకెన్ యొక్క చిహ్నాన్ని అందిస్తుంది, సాధారణంగా ఇది పేరు యొక్క చిన్న రూపం.
*/
function symbol() public view returns (string memory) {
return _symbol;
}
/**
* @dev వినియోగదారు ప్రాతినిధ్యాన్ని పొందడానికి ఉపయోగించే దశాంశాల సంఖ్యను అందిస్తుంది.
* ఉదాహరణకు, `decimals` `2` కి సమానమైతే, `505` టోకెన్ల బ్యాలెన్స్ వినియోగదారుకు `5,05` (`505 / 10 ** 2`) గా ప్రదర్శించబడాలి.
*
* ఈథర్ మరియు Wei మధ్య సంబంధాన్ని అనుకరిస్తూ, టోకెన్లు సాధారణంగా 18 విలువను ఎంచుకుంటాయి. {_setupDecimals} కాల్ చేయకపోతే, {ERC-20} ఉపయోగించే విలువ ఇదే.
*
* గమనిక: ఈ సమాచారం కేవలం _ప్రదర్శన_ ప్రయోజనాల కోసం మాత్రమే ఉపయోగించబడుతుంది: ఇది {IERC20-balanceOf} మరియు {IERC20-transfer} తో సహా కాంట్రాక్ట్ యొక్క ఏ అంకగణితాన్ని ఏ విధంగానూ ప్రభావితం చేయదు.
*/
function decimals() public view returns (uint8) {
return _decimals;
}
ఈ ఫంక్షన్లు, name, symbol, మరియు decimals యూజర్ ఇంటర్ఫేస్లకు మీ కాంట్రాక్ట్ గురించి తెలుసుకోవడానికి సహాయపడతాయి, తద్వారా అవి దానిని సరిగ్గా ప్రదర్శించగలవు.
రిటర్న్ రకం string memory, అంటే మెమరీలో నిల్వ చేయబడిన స్ట్రింగ్ను తిరిగి ఇవ్వడం. స్ట్రింగ్ల వంటి వేరియబుల్స్ మూడు ప్రదేశాలలో నిల్వ చేయబడతాయి:
| జీవితకాలం | కాంట్రాక్ట్ యాక్సెస్ | గ్యాస్ ఖర్చు | |
|---|---|---|---|
| మెమరీ | ఫంక్షన్ కాల్ | చదవడం/వ్రాయడం | పదులు లేదా వందలు (అధిక స్థానాలకు ఎక్కువ) |
| కాల్ డేటా | ఫంక్షన్ కాల్ | చదవడం మాత్రమే | రిటర్న్ రకంగా ఉపయోగించబడదు, ఫంక్షన్ పారామీటర్ రకంగా మాత్రమే |
| నిల్వ | మార్చే వరకు | చదవడం/వ్రాయడం | ఎక్కువ (చదవడానికి 800, వ్రాయడానికి 20k) |
ఈ సందర్భంలో, memory ఉత్తమ ఎంపిక.
టోకెన్ సమాచారాన్ని చదవడం
ఇవి టోకెన్ గురించి, అంటే మొత్తం సరఫరా లేదా ఖాతా బ్యాలెన్స్ గురించి సమాచారాన్ని అందించే ఫంక్షన్లు.
/**
* @dev {IERC20-totalSupply} చూడండి.
*/
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
totalSupply ఫంక్షన్ టోకెన్ల మొత్తం సరఫరాను అందిస్తుంది.
/**
* @dev {IERC20-balanceOf} చూడండి.
*/
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
ఖాతా బ్యాలెన్స్ను చదవడం. ఎవరైనా ఇతరుల ఖాతా బ్యాలెన్స్ను పొందడానికి అనుమతించబడతారని గమనించండి. ఈ సమాచారాన్ని దాచడానికి ప్రయత్నించడంలో అర్థం లేదు, ఎందుకంటే ఇది ఎలాగైనా ప్రతి నోడ్లో అందుబాటులో ఉంటుంది. బ్లాక్చైన్లో ఎలాంటి రహస్యాలు లేవు.
టోకెన్లను బదిలీ చేయడం
/**
* @dev {IERC20-transfer} చూడండి.
*
* అవసరాలు:
*
* - `recipient` శూన్య చిరునామా కాకూడదు.
* - కాలర్ కనీసం `amount` బ్యాలెన్స్ కలిగి ఉండాలి.
*/
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
పంపినవారి ఖాతా నుండి వేరొక దానికి టోకెన్లను బదిలీ చేయడానికి transfer ఫంక్షన్ కాల్ చేయబడుతుంది. ఇది బూలియన్ విలువను అందించినప్పటికీ, ఆ విలువ ఎల్లప్పుడూ true అని గమనించండి. బదిలీ విఫలమైతే కాంట్రాక్ట్ కాల్ను రివర్ట్ చేస్తుంది.
_transfer(_msgSender(), recipient, amount);
return true;
}
_transfer ఫంక్షన్ అసలు పనిని చేస్తుంది. ఇది ఇతర కాంట్రాక్ట్ ఫంక్షన్ల ద్వారా మాత్రమే కాల్ చేయబడే ప్రైవేట్ ఫంక్షన్. సాధారణంగా ప్రైవేట్ ఫంక్షన్లకు స్థితి వేరియబుల్స్ వలె _<something> అని పేరు పెడతారు.
సాధారణంగా Solidityలో మనం సందేశం పంపినవారి కోసం msg.senderని ఉపయోగిస్తాము. అయితే, అది
OpenGSN (opens in a new tab)ని విచ్ఛిన్నం చేస్తుంది. మనం మన టోకెన్తో ఈథర్ లేని లావాదేవీలను అనుమతించాలనుకుంటే, మనం _msgSender()ని ఉపయోగించాలి. ఇది సాధారణ లావాదేవీల కోసం msg.senderని అందిస్తుంది, కానీ ఈథర్ లేని వాటి కోసం సందేశాన్ని ప్రసారం చేసిన కాంట్రాక్ట్ను కాకుండా అసలు సంతకం చేసిన వ్యక్తిని అందిస్తుంది.
అనుమతి మొత్తం ఫంక్షన్లు
ఇవి అనుమతి మొత్తం కార్యాచరణను అమలు చేసే ఫంక్షన్లు: allowance, approve, transferFrom,
మరియు _approve. అదనంగా, ఓపెన్జెప్పెలిన్ అమలు భద్రతను మెరుగుపరిచే కొన్ని లక్షణాలను చేర్చడానికి ప్రాథమిక ప్రమాణానికి మించి వెళుతుంది: increaseAllowance, మరియు decreaseAllowance.
allowance ఫంక్షన్
/**
* @dev {IERC20-allowance} చూడండి.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
allowance ఫంక్షన్ ఎవరైనా ఏదైనా అనుమతి మొత్తాన్ని తనిఖీ చేయడానికి అనుమతిస్తుంది.
approve ఫంక్షన్
/**
* @dev {IERC20-approve} చూడండి.
*
* అవసరాలు:
*
* - `spender` శూన్య చిరునామా కాకూడదు.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
అనుమతి మొత్తాన్ని సృష్టించడానికి ఈ ఫంక్షన్ కాల్ చేయబడుతుంది. ఇది పై transfer ఫంక్షన్ను పోలి ఉంటుంది:
- ఫంక్షన్ కేవలం అసలు పని చేసే అంతర్గత ఫంక్షన్ను (ఈ సందర్భంలో,
_approve) కాల్ చేస్తుంది. - ఫంక్షన్
trueని అందిస్తుంది (విజయవంతమైతే) లేదా రివర్ట్ అవుతుంది (లేకపోతే).
_approve(_msgSender(), spender, amount);
return true;
}
స్థితి మార్పులు జరిగే ప్రదేశాల సంఖ్యను తగ్గించడానికి మనం అంతర్గత ఫంక్షన్లను ఉపయోగిస్తాము. స్థితిని మార్చే ఏదైనా ఫంక్షన్ భద్రత కోసం ఆడిట్ చేయాల్సిన సంభావ్య భద్రతా ప్రమాదం. ఈ విధంగా మనం తప్పు చేయడానికి తక్కువ అవకాశాలు ఉంటాయి.
transferFrom ఫంక్షన్
ఇది అనుమతి మొత్తాన్ని ఖర్చు చేయడానికి ఖర్చు చేసే వ్యక్తి కాల్ చేసే ఫంక్షన్. దీనికి రెండు కార్యకలాపాలు అవసరం: ఖర్చు చేస్తున్న మొత్తాన్ని బదిలీ చేయడం మరియు ఆ మొత్తం ద్వారా అనుమతి మొత్తాన్ని తగ్గించడం.
/**
* @dev {IERC20-transferFrom} చూడండి.
*
* నవీకరించబడిన అనుమతి మొత్తం ను సూచించే {Approval} ఈవెంట్ను విడుదల చేస్తుంది. ఇది EIP ద్వారా అవసరం లేదు. {ERC-20} ప్రారంభంలో ఉన్న గమనికను చూడండి.
*
* అవసరాలు:
*
* - `sender` మరియు `recipient` శూన్య చిరునామా కాకూడదు.
* - `sender` కనీసం `amount` బ్యాలెన్స్ కలిగి ఉండాలి.
* - కాలర్ కనీసం `amount` కోసం ``sender`` టోకెన్ల అనుమతి మొత్తం కలిగి ఉండాలి.
*/
function transferFrom(address sender, address recipient, uint256 amount) public virtual
override returns (bool) {
_transfer(sender, recipient, amount);
a.sub(b, "message") ఫంక్షన్ కాల్ రెండు పనులు చేస్తుంది. మొదట, ఇది కొత్త అనుమతి మొత్తం అయిన a-bని గణిస్తుంది. రెండవది, ఈ ఫలితం ప్రతికూలంగా లేదని ఇది తనిఖీ చేస్తుంది. ఇది ప్రతికూలంగా ఉంటే, అందించిన సందేశంతో కాల్ రివర్ట్ అవుతుంది. కాల్ రివర్ట్ అయినప్పుడు ఆ కాల్ సమయంలో గతంలో చేసిన ఏదైనా ప్రాసెసింగ్ విస్మరించబడుతుందని గమనించండి, కాబట్టి మనం _transferని అన్డూ చేయాల్సిన అవసరం లేదు.
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount,
"ERC20: transfer amount exceeds allowance"));
return true;
}
ఓపెన్జెప్పెలిన్ భద్రతా చేర్పులు
సున్నా కాని అనుమతి మొత్తాన్ని మరొక సున్నా కాని విలువకు సెట్ చేయడం ప్రమాదకరం, ఎందుకంటే మీరు మీ స్వంత లావాదేవీల క్రమాన్ని మాత్రమే నియంత్రిస్తారు, ఇతరులది కాదు. మీకు ఇద్దరు వినియోగదారులు ఉన్నారని ఊహించుకోండి, అమాయకురాలైన ఆలిస్ మరియు నిజాయితీ లేని బిల్. ఆలిస్ బిల్ నుండి కొంత సేవను కోరుకుంటుంది, దానికి ఐదు టోకెన్లు ఖర్చవుతాయని ఆమె భావిస్తుంది - కాబట్టి ఆమె బిల్కు ఐదు టోకెన్ల అనుమతి మొత్తాన్ని ఇస్తుంది.
అప్పుడు ఏదో మారుతుంది మరియు బిల్ ధర పది టోకెన్లకు పెరుగుతుంది. ఇప్పటికీ సేవను కోరుకునే ఆలిస్, బిల్ అనుమతి మొత్తాన్ని పదికి సెట్ చేసే లావాదేవీని పంపుతుంది. లావాదేవీల పూల్లో ఈ కొత్త లావాదేవీని బిల్ చూసిన క్షణంలో, అతను ఆలిస్ యొక్క ఐదు టోకెన్లను ఖర్చు చేసే లావాదేవీని పంపుతాడు మరియు దానికి చాలా ఎక్కువ గ్యాస్ ధర ఉంటుంది కాబట్టి అది వేగంగా మైన్ చేయబడుతుంది. ఆ విధంగా బిల్ మొదట ఐదు టోకెన్లను ఖర్చు చేయవచ్చు మరియు ఆ తర్వాత, ఆలిస్ యొక్క కొత్త అనుమతి మొత్తం మైన్ చేయబడిన తర్వాత, ఆలిస్ అధికారం ఇవ్వాలనుకున్న దానికంటే ఎక్కువగా మొత్తం పదిహేను టోకెన్ల ధరకు మరో పది ఖర్చు చేయవచ్చు. ఈ సాంకేతికతను ముందుగా అమలు చేయడం (opens in a new tab) అంటారు
| ఆలిస్ లావాదేవీ | ఆలిస్ నాన్స్ | బిల్ లావాదేవీ | బిల్ నాన్స్ | బిల్ అనుమతి మొత్తం | ఆలిస్ నుండి బిల్ మొత్తం ఆదాయం |
|---|---|---|---|---|---|
| approve(Bill, 5) | 10 | 5 | 0 | ||
| transferFrom(Alice, Bill, 5) | 10,123 | 0 | 5 | ||
| approve(Bill, 10) | 11 | 10 | 5 | ||
| transferFrom(Alice, Bill, 10) | 10,124 | 0 | 15 |
ఈ సమస్యను నివారించడానికి, ఈ రెండు ఫంక్షన్లు (increaseAllowance మరియు decreaseAllowance) నిర్దిష్ట మొత్తం ద్వారా అనుమతి మొత్తాన్ని సవరించడానికి మిమ్మల్ని అనుమతిస్తాయి. కాబట్టి బిల్ ఇప్పటికే ఐదు టోకెన్లను ఖర్చు చేసి ఉంటే, అతను మరో ఐదు మాత్రమే ఖర్చు చేయగలడు. సమయాన్ని బట్టి, ఇది పని చేయడానికి రెండు మార్గాలు ఉన్నాయి, రెండూ బిల్ పది టోకెన్లను మాత్రమే పొందడంతో ముగుస్తాయి:
A:
| ఆలిస్ లావాదేవీ | ఆలిస్ నాన్స్ | బిల్ లావాదేవీ | బిల్ నాన్స్ | బిల్ అనుమతి మొత్తం | ఆలిస్ నుండి బిల్ మొత్తం ఆదాయం |
|---|---|---|---|---|---|
| approve(Bill, 5) | 10 | 5 | 0 | ||
| transferFrom(Alice, Bill, 5) | 10,123 | 0 | 5 | ||
| increaseAllowance(Bill, 5) | 11 | 0+5 = 5 | 5 | ||
| transferFrom(Alice, Bill, 5) | 10,124 | 0 | 10 |
B:
| ఆలిస్ లావాదేవీ | ఆలిస్ నాన్స్ | బిల్ లావాదేవీ | బిల్ నాన్స్ | బిల్ అనుమతి మొత్తం | ఆలిస్ నుండి బిల్ మొత్తం ఆదాయం |
|---|---|---|---|---|---|
| approve(Bill, 5) | 10 | 5 | 0 | ||
| increaseAllowance(Bill, 5) | 11 | 5+5 = 10 | 0 | ||
| transferFrom(Alice, Bill, 10) | 10,124 | 0 | 10 |
/**
* @dev కాలర్ ద్వారా `spender` కు మంజూరు చేయబడిన అనుమతి మొత్తం ను అటామిక్గా పెంచుతుంది.
*
* ఇది {approve} కు ప్రత్యామ్నాయం, దీనిని {IERC20-approve} లో వివరించిన సమస్యలకు ఉపశమనంగా ఉపయోగించవచ్చు.
*
* నవీకరించబడిన అనుమతి మొత్తం ను సూచించే {Approval} ఈవెంట్ను విడుదల చేస్తుంది.
*
* అవసరాలు:
*
* - `spender` శూన్య చిరునామా కాకూడదు.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
a.add(b) ఫంక్షన్ సురక్షితమైన కూడిక. a+b>=2^256 అయ్యే అరుదైన సందర్భంలో, ఇది సాధారణ కూడిక చేసే విధంగా ర్యాప్ అరౌండ్ చేయదు.
/**
* @dev కాలర్ ద్వారా `spender` కు మంజూరు చేయబడిన అనుమతి మొత్తం ను అటామిక్గా తగ్గిస్తుంది.
*
* ఇది {approve} కు ప్రత్యామ్నాయం, దీనిని {IERC20-approve} లో వివరించిన సమస్యలకు ఉపశమనంగా ఉపయోగించవచ్చు.
*
* నవీకరించబడిన అనుమతి మొత్తం ను సూచించే {Approval} ఈవెంట్ను విడుదల చేస్తుంది.
*
* అవసరాలు:
*
* - `spender` శూన్య చిరునామా కాకూడదు.
* - `spender` కాలర్ కోసం కనీసం `subtractedValue` అనుమతి మొత్తం కలిగి ఉండాలి.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue,
"ERC20: decreased allowance below zero"));
return true;
}
టోకెన్ సమాచారాన్ని సవరించే ఫంక్షన్లు
అసలు పని చేసే నాలుగు ఫంక్షన్లు ఇవి: _transfer, _mint, _burn, మరియు _approve.
_transfer ఫంక్షన్
/**
* @dev `sender` నుండి `recipient` కు `amount` టోకెన్లను బదిలీ చేస్తుంది.
*
* ఈ అంతర్గత ఫంక్షన్ {transfer} కు సమానం, మరియు ఉదాహరణకు ఆటోమేటిక్ టోకెన్ ఫీజులు, స్లాషింగ్ యంత్రాంగాలు మొదలైనవాటిని అమలు చేయడానికి ఉపయోగించవచ్చు.
*
* {Transfer} ఈవెంట్ను విడుదల చేస్తుంది.
*
* అవసరాలు:
*
* - `sender` శూన్య చిరునామా కాకూడదు.
* - `recipient` శూన్య చిరునామా కాకూడదు.
* - `sender` కనీసం `amount` బ్యాలెన్స్ కలిగి ఉండాలి.
*/
function _transfer(address sender, address recipient, uint256 amount) internal virtual {
ఈ ఫంక్షన్, _transfer, ఒక ఖాతా నుండి మరొక ఖాతాకు టోకెన్లను బదిలీ చేస్తుంది. ఇది transfer (పంపినవారి స్వంత ఖాతా నుండి బదిలీల కోసం) మరియు transferFrom (వేరొకరి ఖాతా నుండి బదిలీ చేయడానికి అనుమతి మొత్తాలను ఉపయోగించడం కోసం) రెండింటి ద్వారా కాల్ చేయబడుతుంది.
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
ఎథీరియంలో వాస్తవానికి శూన్య చిరునామా ఎవరికీ స్వంతం కాదు (అంటే, సరిపోలే పబ్లిక్ కీ శూన్య చిరునామాగా మార్చబడిన ప్రైవేట్ కీ ఎవరికీ తెలియదు). ప్రజలు ఆ చిరునామాను ఉపయోగించినప్పుడు, అది సాధారణంగా సాఫ్ట్వేర్ బగ్ - కాబట్టి పంపినవారు లేదా స్వీకరించేవారిగా శూన్య చిరునామా ఉపయోగించబడితే మనం విఫలమవుతాము.
_beforeTokenTransfer(sender, recipient, amount);
ఈ కాంట్రాక్ట్ను ఉపయోగించడానికి రెండు మార్గాలు ఉన్నాయి:
- మీ స్వంత కోడ్ కోసం దీన్ని టెంప్లేట్గా ఉపయోగించండి
- దాని నుండి వారసత్వంగా పొందండి (opens in a new tab), మరియు మీరు సవరించాల్సిన ఫంక్షన్లను మాత్రమే ఓవర్రైడ్ చేయండి
రెండవ పద్ధతి చాలా ఉత్తమమైనది ఎందుకంటే ఓపెన్జెప్పెలిన్ ERC-20 కోడ్ ఇప్పటికే ఆడిట్ చేయబడింది మరియు సురక్షితమైనదిగా చూపబడింది. మీరు వారసత్వాన్ని ఉపయోగించినప్పుడు మీరు సవరించే ఫంక్షన్లు ఏమిటో స్పష్టంగా తెలుస్తుంది మరియు మీ కాంట్రాక్ట్ను విశ్వసించడానికి ప్రజలు ఆ నిర్దిష్ట ఫంక్షన్లను మాత్రమే ఆడిట్ చేయాలి.
టోకెన్లు చేతులు మారిన ప్రతిసారీ ఫంక్షన్ను నిర్వహించడం తరచుగా ఉపయోగకరంగా ఉంటుంది. అయితే, _transfer అనేది చాలా ముఖ్యమైన ఫంక్షన్ మరియు దానిని అసురక్షితంగా వ్రాయడం సాధ్యమవుతుంది (క్రింద చూడండి), కాబట్టి దానిని ఓవర్రైడ్ చేయకపోవడమే మంచిది. దీనికి పరిష్కారం _beforeTokenTransfer, ఇది ఒక
హుక్ ఫంక్షన్ (opens in a new tab). మీరు ఈ ఫంక్షన్ను ఓవర్రైడ్ చేయవచ్చు మరియు ప్రతి బదిలీపై ఇది కాల్ చేయబడుతుంది.
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
వాస్తవానికి బదిలీ చేసే పంక్తులు ఇవి. వాటి మధ్య ఏమీ లేదని గమనించండి మరియు స్వీకరించేవారికి జోడించే ముందు పంపినవారి నుండి బదిలీ చేయబడిన మొత్తాన్ని మనం తీసివేస్తాము. ఇది ముఖ్యం ఎందుకంటే మధ్యలో వేరే కాంట్రాక్ట్కు కాల్ ఉంటే, ఈ కాంట్రాక్ట్ను మోసం చేయడానికి దానిని ఉపయోగించి ఉండవచ్చు. ఈ విధంగా బదిలీ అటామిక్గా ఉంటుంది, దాని మధ్యలో ఏమీ జరగదు.
emit Transfer(sender, recipient, amount);
}
చివరగా, Transfer ఈవెంట్ను విడుదల చేయండి. ఈవెంట్లు స్మార్ట్ కాంట్రాక్ట్లకు అందుబాటులో ఉండవు, కానీ బ్లాక్చైన్ వెలుపల రన్ అవుతున్న కోడ్ ఈవెంట్ల కోసం వినగలదు మరియు వాటికి ప్రతిస్పందించగలదు. ఉదాహరణకు, యజమాని ఎప్పుడు ఎక్కువ టోకెన్లను పొందుతాడో వాలెట్ ట్రాక్ చేయగలదు.
_mint మరియు _burn ఫంక్షన్లు
ఈ రెండు ఫంక్షన్లు (_mint మరియు _burn) టోకెన్ల మొత్తం సరఫరాను సవరిస్తాయి.
అవి అంతర్గతమైనవి మరియు ఈ కాంట్రాక్ట్లో వాటిని కాల్ చేసే ఫంక్షన్ ఏదీ లేదు,
కాబట్టి మీరు కాంట్రాక్ట్ నుండి వారసత్వంగా పొంది, ఏ పరిస్థితులలో కొత్త టోకెన్లను ముద్రించాలి లేదా ఉన్నవాటిని దహనం చేయాలి అని నిర్ణయించడానికి మీ స్వంత లాజిక్ను జోడిస్తే మాత్రమే అవి ఉపయోగపడతాయి.
గమనిక: ప్రతి ERC-20 టోకెన్ టోకెన్ నిర్వహణను నిర్దేశించే దాని స్వంత వ్యాపార లాజిక్ను కలిగి ఉంటుంది.
ఉదాహరణకు, స్థిర సరఫరా కాంట్రాక్ట్ కన్స్ట్రక్టర్లో మాత్రమే _mintని కాల్ చేయవచ్చు మరియు ఎప్పుడూ _burnని కాల్ చేయకపోవచ్చు. టోకెన్లను విక్రయించే కాంట్రాక్ట్ దానికి చెల్లించినప్పుడు _mintని కాల్ చేస్తుంది మరియు రన్అవే ద్రవ్యోల్బణాన్ని నివారించడానికి ఏదో ఒక సమయంలో _burnని కాల్ చేయవచ్చు.
/** @dev `amount` టోకెన్లను సృష్టిస్తుంది మరియు వాటిని `account` కు కేటాయిస్తుంది, మొత్తం సరఫరాను పెంచుతుంది.
*
* `from` ను శూన్య చిరునామా కు సెట్ చేసి {Transfer} ఈవెంట్ను విడుదల చేస్తుంది.
*
* అవసరాలు:
*
* - `to` శూన్య చిరునామా కాకూడదు.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0), account, amount);
}
టోకెన్ల మొత్తం సంఖ్య మారినప్పుడు _totalSupplyని అప్డేట్ చేయాలని నిర్ధారించుకోండి.
/**
* @dev `account` నుండి `amount` టోకెన్లను నాశనం చేస్తుంది, మొత్తం సరఫరాను తగ్గిస్తుంది.
*
* `to` ను శూన్య చిరునామా కు సెట్ చేసి {Transfer} ఈవెంట్ను విడుదల చేస్తుంది.
*
* అవసరాలు:
*
* - `account` శూన్య చిరునామా కాకూడదు.
* - `account` కనీసం `amount` టోకెన్లను కలిగి ఉండాలి.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
_balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
_totalSupply = _totalSupply.sub(amount);
emit Transfer(account, address(0), amount);
}
_burn ఫంక్షన్ దాదాపు _mint వలె ఉంటుంది, కాకపోతే ఇది వ్యతిరేక దిశలో వెళుతుంది.
_approve ఫంక్షన్
ఇది వాస్తవానికి అనుమతి మొత్తాలను నిర్దేశించే ఫంక్షన్. యజమాని ప్రస్తుత బ్యాలెన్స్ కంటే ఎక్కువ అనుమతి మొత్తాన్ని పేర్కొనడానికి ఇది యజమానిని అనుమతిస్తుందని గమనించండి. ఇది సరే ఎందుకంటే బదిలీ సమయంలో బ్యాలెన్స్ తనిఖీ చేయబడుతుంది, అప్పుడు అది అనుమతి మొత్తం సృష్టించబడినప్పటి బ్యాలెన్స్ కంటే భిన్నంగా ఉండవచ్చు.
/**
* @dev `owner` టోకెన్లపై `spender` యొక్క అనుమతి మొత్తం గా `amount` ను సెట్ చేస్తుంది.
*
* ఈ అంతర్గత ఫంక్షన్ `approve` కు సమానం, మరియు ఉదాహరణకు నిర్దిష్ట ఉపవ్యవస్థల కోసం ఆటోమేటిక్ అనుమతి మొత్తాలను సెట్ చేయడానికి ఉపయోగించవచ్చు.
*
* {Approval} ఈవెంట్ను విడుదల చేస్తుంది.
*
* అవసరాలు:
*
* - `owner` శూన్య చిరునామా కాకూడదు.
* - `spender` శూన్య చిరునామా కాకూడదు.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
Approval ఈవెంట్ను విడుదల చేయండి. అప్లికేషన్ ఎలా వ్రాయబడిందనే దానిపై ఆధారపడి, ఖర్చు చేసే కాంట్రాక్ట్కు ఆమోదం గురించి యజమాని ద్వారా లేదా ఈ ఈవెంట్లను వినే సర్వర్ ద్వారా చెప్పవచ్చు.
emit Approval(owner, spender, amount);
}
Decimals వేరియబుల్ను సవరించడం
/**
* @dev {decimals} ను అప్రమేయమైన 18 కాకుండా వేరే విలువకు సెట్ చేస్తుంది.
*
* హెచ్చరిక: ఈ ఫంక్షన్ కన్స్ట్రక్టర్ నుండి మాత్రమే కాల్ చేయబడాలి. టోకెన్ కాంట్రాక్ట్ లతో పరస్పర చర్య చేసే చాలా అప్లికేషన్లు {decimals} ఎప్పుడైనా మారుతుందని ఆశించవు, మరియు అలా జరిగితే తప్పుగా పనిచేయవచ్చు.
*/
function _setupDecimals(uint8 decimals_) internal {
_decimals = decimals_;
}
ఈ ఫంక్షన్ _decimals వేరియబుల్ను సవరిస్తుంది, ఇది మొత్తాన్ని ఎలా అర్థం చేసుకోవాలో యూజర్ ఇంటర్ఫేస్లకు చెప్పడానికి ఉపయోగించబడుతుంది. మీరు దానిని కన్స్ట్రక్టర్ నుండి కాల్ చేయాలి. తదుపరి ఏ సమయంలోనైనా దానిని కాల్ చేయడం నిజాయితీ లేని పని అవుతుంది మరియు అప్లికేషన్లు దానిని నిర్వహించడానికి రూపొందించబడలేదు.
హుక్స్
/**
* @dev టోకెన్ల బదిలీకి ముందు కాల్ చేయబడే హుక్. ఇందులో మింటింగ్ మరియు బర్నింగ్ కూడా ఉంటాయి.
*
* కాలింగ్ షరతులు:
*
* - `from` మరియు `to` రెండూ సున్నా కానప్పుడు, ``from`` యొక్క `amount` టోకెన్లు `to` కు బదిలీ చేయబడతాయి.
* - `from` సున్నా అయినప్పుడు, `to` కోసం `amount` టోకెన్లు మింట్ చేయబడతాయి.
* - `to` సున్నా అయినప్పుడు, ``from`` యొక్క `amount` టోకెన్లు బర్న్ చేయబడతాయి.
* - `from` మరియు `to` ఎప్పుడూ రెండూ సున్నా కావు.
*
* హుక్స్ గురించి మరింత తెలుసుకోవడానికి, xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks] కు వెళ్లండి.
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}
ఇది బదిలీల సమయంలో కాల్ చేయాల్సిన హుక్ ఫంక్షన్. ఇది ఇక్కడ ఖాళీగా ఉంది, కానీ అది ఏదైనా చేయాలని మీకు అవసరమైతే మీరు దానిని ఓవర్రైడ్ చేయండి.
ముగింపు
సమీక్ష కోసం, ఈ కాంట్రాక్ట్లోని కొన్ని ముఖ్యమైన ఆలోచనలు ఇక్కడ ఉన్నాయి (నా అభిప్రాయం ప్రకారం, మీది మారవచ్చు):
- బ్లాక్చైన్లో ఎలాంటి రహస్యాలు లేవు. స్మార్ట్ కాంట్రాక్ట్ యాక్సెస్ చేయగల ఏదైనా సమాచారం ప్రపంచం మొత్తానికి అందుబాటులో ఉంటుంది.
- మీరు మీ స్వంత లావాదేవీల క్రమాన్ని నియంత్రించవచ్చు, కానీ ఇతరుల లావాదేవీలు ఎప్పుడు జరుగుతాయో కాదు. అనుమతి మొత్తాన్ని మార్చడం ప్రమాదకరం కావడానికి ఇదే కారణం, ఎందుకంటే ఇది రెండు అనుమతి మొత్తాల మొత్తాన్ని ఖర్చు చేయడానికి ఖర్చు చేసే వ్యక్తిని అనుమతిస్తుంది.
uint256రకం విలువలు ర్యాప్ అరౌండ్ అవుతాయి. మరో మాటలో చెప్పాలంటే, 0-1=2^256-1. అది ఆశించిన ప్రవర్తన కాకపోతే, మీరు దాని కోసం తనిఖీ చేయాలి (లేదా మీ కోసం ఆ పని చేసే SafeMath లైబ్రరీని ఉపయోగించండి). ఇది Solidity 0.8.0 (opens in a new tab)లో మారిందని గమనించండి.- నిర్దిష్ట రకమైన అన్ని స్థితి మార్పులను ఒక నిర్దిష్ట ప్రదేశంలో చేయండి, ఎందుకంటే ఇది ఆడిటింగ్ను సులభతరం చేస్తుంది.
ఉదాహరణకు, మనకు
_approveఉండటానికి ఇదే కారణం, ఇదిapprove,transferFrom,increaseAllowance, మరియుdecreaseAllowanceద్వారా కాల్ చేయబడుతుంది - స్థితి మార్పులు అటామిక్గా ఉండాలి, వాటి మధ్యలో ఎలాంటి ఇతర చర్య లేకుండా (మీరు
_transferలో చూడగలిగినట్లుగా). ఎందుకంటే స్థితి మార్పు సమయంలో మీకు అస్థిరమైన స్థితి ఉంటుంది. ఉదాహరణకు, పంపినవారి బ్యాలెన్స్ నుండి తీసివేసిన సమయానికి మరియు స్వీకరించేవారి బ్యాలెన్స్కు జోడించిన సమయానికి మధ్య ఉండాల్సిన దానికంటే తక్కువ టోకెన్లు ఉనికిలో ఉంటాయి. వాటి మధ్య కార్యకలాపాలు ఉంటే, ముఖ్యంగా వేరే కాంట్రాక్ట్కు కాల్స్ ఉంటే ఇది దుర్వినియోగం అయ్యే అవకాశం ఉంది.
ఓపెన్జెప్పెలిన్ ERC-20 కాంట్రాక్ట్ ఎలా వ్రాయబడిందో మరియు ముఖ్యంగా అది ఎలా మరింత సురక్షితంగా చేయబడిందో ఇప్పుడు మీరు చూశారు కాబట్టి, వెళ్లి మీ స్వంత సురక్షిత కాంట్రాక్ట్లు మరియు అప్లికేషన్లను వ్రాయండి.
