اسکیم ٹوکنز کے ذریعہ استعمال ہونے والی کچھ ترکیبیں اور ان کا پتہ لگانے کا طریقہ
اس ٹیوٹوریل میں ہم ایک اسکیم ٹوکن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 پر پراکسیopens in a new tab کے پیچھے بیٹھتا ہے۔ اس معاہدے کا ایک مراعات یافتہ پتہ ہے (چوتھی فائل، ERC1967Upgrade.sol دیکھیں) جسے اپ گریڈ کے لیے استعمال کیا جا سکتا ہے۔
1 /**2 * @dev Stores a new address in the EIP1967 admin slot.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 میں دیکھیں تو ہم دیکھتے ہیں کہ اسکیمر نے اس معاہدے کو صرف 12 گھنٹے کے لیے استعمال کیا (پہلی ٹرانزیکشنopens in a new tab سے آخری ٹرانزیکشنopens in a new tab تک) 19 مئی 2023 کے دوران۔
جعلی _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 C سے ماخوذ ہے، یہ کیس کے لحاظ سے اہم ہے۔ 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 کنٹریکٹ ہے۔ بیرونی ملکیت والے اکاؤنٹ سے کسی بھی دوسری قسم کی منظوری مشکوک ہے۔
یہاں ایک پروگرام ہے جو اس قسم کے ایونٹ کی شناخت کرتا ہےopens in a new tab، viemopens in a new tab اور TypeScriptopens 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)، TypeScript کو بتاتی ہے کہ یہ فنکشن یا تو Event یا null واپس کر سکتا ہے۔ اگر ایونٹ مشکوک نہیں ہے تو ہم null واپس کرتے ہیں۔
1const owner = ev.args._ownerViem کے پاس فیلڈ کے نام ہیں، لہذا اس نے ہمارے لیے ایونٹ کو پارس کیا۔ _owner خرچ کیے جانے والے ٹوکنز کا مالک ہے۔
1// Approvals by contracts are not suspicious2if (await isContract(owner)) return nullاگر مالک ایک کنٹریکٹ ہے، تو فرض کریں کہ یہ منظوری مشکوک نہیں ہے۔ یہ چیک کرنے کے لیے کہ آیا کسی کنٹریکٹ کی منظوری مشکوک ہے یا نہیں، ہمیں ٹرانزیکشن کے مکمل عمل کو ٹریس کرنے کی ضرورت ہوگی تاکہ یہ دیکھا جا سکے کہ کیا یہ کبھی مالک کنٹریکٹ تک پہنچا، اور کیا اس کنٹریکٹ نے براہ راست ERC-20 کنٹریکٹ کو کال کیا۔ یہ اس سے کہیں زیادہ وسائل خرچ کرنے والا ہے جتنا ہم کرنا چاہیں گے۔
1const txn = await getEventTxn(ev)اگر منظوری بیرونی ملکیت والے اکاؤنٹ سے آتی ہے، تو اس ٹرانزیکشن کو حاصل کریں جس کی وجہ سے یہ ہوا۔
1// The approval is suspicious if it comes an EOA owner that isn't the transaction's `from`2if (owner.toLowerCase() != txn.from.toLowerCase()) return evہم صرف اسٹرنگ کی مساوات کی جانچ نہیں کر سکتے کیونکہ پتے ہیکسا ڈیسیمل ہوتے ہیں، لہذا ان میں حروف ہوتے ہیں۔ کبھی کبھی، مثال کے طور پر txn.from میں، وہ حروف سب چھوٹے ہوتے ہیں۔ دیگر معاملات میں، جیسے کہ ev.args._owner، پتہ خرابی کی شناخت کے لیے مخلوط کیسopens in a new tab میں ہوتا ہے۔
لیکن اگر ٹرانزیکشن مالک کی طرف سے نہیں ہے، اور وہ مالک بیرونی طور پر ملکیت میں ہے، تو ہمارے پاس ایک مشکوک ٹرانزیکشن ہے۔
1// It is also suspicious if the transaction destination isn't the ERC-20 contract we are2// investigating3if (txn.to.toLowerCase() != testedAddress) return evاسی طرح، اگر ٹرانزیکشن کا to پتہ، پہلا کال کیا گیا کنٹریکٹ، زیر تفتیش ERC-20 کنٹریکٹ نہیں ہے تو یہ مشکوک ہے۔
1 // If there is no reason to be suspicious, return 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 فنکشن ایک 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 کے ٹکڑوں میں، جہاں بہت سے ٹوکن ہوتے ہیں اور انہیں خود بخود سنبھالنے کی ضرورت ہوتی ہے۔ لیکن ہمیشہ کی طرح caveat emptoropens in a new tab، اپنی تحقیق خود کریں، اور اپنے صارفین کو بھی ایسا کرنے کی ترغیب دیں۔
میرے مزید کام کے لیے یہاں دیکھیںopens in a new tab۔
صفحہ کی آخری تازہ کاری: 25 فروری، 2026