---
title: "ERC-20 কন্ট্রাক্ট ওয়াক-থ্রু"
description: "ওপেনজেপেলিন ERC-20 কন্ট্রাক্টে কী আছে এবং কেন এটি সেখানে আছে?"
author: "ওরি পোমেরান্টজ"
lang: bn
tags:
  - solidity
  - erc-20
skill: beginner
breadcrumb: "ERC-20 ওয়াক-থ্রু"
published: 2021-03-09
---

## ভূমিকা {#introduction}

ইথেরিয়াম-এর অন্যতম সাধারণ ব্যবহার হলো কোনো গোষ্ঠীর জন্য একটি ট্রেডযোগ্য টোকেন তৈরি করা, যা এক অর্থে তাদের নিজস্ব মুদ্রা। এই টোকেনগুলো সাধারণত একটি স্ট্যান্ডার্ড অনুসরণ করে, [ERC-20](/developers/docs/standards/tokens/erc-20/)। এই স্ট্যান্ডার্ডটি এমন টুল তৈরি করা সম্ভব করে, যেমন তারল্য পুল এবং ওয়ালেট, যা সমস্ত ERC-20 টোকেনের সাথে কাজ করে। এই নিবন্ধে আমরা [ওপেনজেপেলিন Solidity ERC20 ইমপ্লিমেন্টেশন](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol), এবং সেইসাথে [ইন্টারফেস ডেফিনিশন](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol) বিশ্লেষণ করব।

এটি টীকাযুক্ত সোর্স কোড। আপনি যদি ERC-20 ইমপ্লিমেন্ট করতে চান, তবে [এই টিউটোরিয়ালটি পড়ুন](https://docs.openzeppelin.com/contracts/2.x/erc20-supply)।

## ইন্টারফেস {#the-interface}

ERC-20 এর মতো একটি স্ট্যান্ডার্ডের উদ্দেশ্য হলো এমন অনেক টোকেন ইমপ্লিমেন্টেশনের অনুমতি দেওয়া যা ওয়ালেট এবং বিকেন্দ্রীকৃত এক্সচেঞ্জের মতো অ্যাপ্লিকেশনগুলোর মধ্যে আন্তঃক্রিয়াশীল। এটি অর্জন করতে, আমরা একটি [ইন্টারফেস](https://www.geeksforgeeks.org/solidity/solidity-basics-of-interface/) তৈরি করি। টোকেন কন্ট্রাক্ট ব্যবহার করার প্রয়োজন এমন যেকোনো কোড ইন্টারফেসে একই ডেফিনিশন ব্যবহার করতে পারে এবং এটি ব্যবহার করে এমন সমস্ত টোকেন কন্ট্রাক্টের সাথে সামঞ্জস্যপূর্ণ হতে পারে, তা মেটামাস্ক-এর মতো ওয়ালেট হোক, etherscan.io-এর মতো একটি বিকেন্দ্রীকৃত অ্যাপ্লিকেশন (dapp) হোক, বা তারল্য পুল-এর মতো ভিন্ন কোনো কন্ট্রাক্ট হোক।

![Illustration of the ERC-20 interface](erc20_interface.png)

আপনি যদি একজন অভিজ্ঞ প্রোগ্রামার হন, তবে সম্ভবত আপনার [Java](https://www.w3schools.com/java/java_interface.asp) বা এমনকি [C হেডার ফাইলে](https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html) একই ধরনের গঠন দেখার কথা মনে আছে।

এটি ওপেনজেপেলিন থেকে [ERC-20 ইন্টারফেস](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol)-এর একটি ডেফিনিশন। এটি [মানুষের পাঠযোগ্য স্ট্যান্ডার্ড](https://eips.ethereum.org/EIPS/eip-20)-এর Solidity কোডে অনুবাদ। অবশ্যই, ইন্টারফেস নিজে থেকে _কীভাবে_ কিছু করতে হবে তা নির্ধারণ করে না। এটি নিচের কন্ট্রাক্ট সোর্স কোডে ব্যাখ্যা করা হয়েছে।

&nbsp;

```solidity
// SPDX-License-Identifier: MIT
```

Solidity ফাইলে একটি লাইসেন্স আইডেন্টিফায়ার অন্তর্ভুক্ত থাকার কথা। [আপনি এখানে লাইসেন্সের তালিকা দেখতে পারেন](https://spdx.org/licenses/)। আপনার যদি ভিন্ন কোনো লাইসেন্সের প্রয়োজন হয়, তবে মন্তব্যে তা ব্যাখ্যা করুন।

&nbsp;

```solidity
pragma solidity >=0.6.0 <0.8.0;
```

Solidity ভাষাটি এখনও দ্রুত বিকশিত হচ্ছে, এবং নতুন সংস্করণগুলো পুরোনো কোডের সাথে সামঞ্জস্যপূর্ণ নাও হতে পারে ([এখানে দেখুন](https://docs.soliditylang.org/en/v0.7.0/070-breaking-changes.html))। তাই, শুধুমাত্র ভাষার ন্যূনতম সংস্করণ নয়, বরং সর্বোচ্চ সংস্করণটিও নির্দিষ্ট করা একটি ভালো ধারণা, যা দিয়ে আপনি সর্বশেষ কোডটি পরীক্ষা করেছেন।

&nbsp;

```solidity
/**
 * @dev EIP-তে সংজ্ঞায়িত ERC-20 স্ট্যান্ডার্ডের ইন্টারফেস।
 */
```

মন্তব্যে থাকা `@dev` হলো [NatSpec ফরম্যাট](https://docs.soliditylang.org/en/develop/natspec-format.html)-এর অংশ, যা সোর্স কোড থেকে ডকুমেন্টেশন তৈরি করতে ব্যবহৃত হয়।

&nbsp;

```solidity
interface IERC20 {
```

প্রথা অনুযায়ী, ইন্টারফেসের নাম `I` দিয়ে শুরু হয়।

&nbsp;

```solidity
    /**
     * @dev বর্তমানে বিদ্যমান টোকেনের পরিমাণ রিটার্ন করে।
     */
    function totalSupply() external view returns (uint256);
```

এই ফাংশনটি হলো `external`, যার অর্থ [এটি শুধুমাত্র কন্ট্রাক্টের বাইরে থেকে কল করা যেতে পারে](https://docs.soliditylang.org/en/v0.7.0/cheatsheet.html#index-2)।
এটি কন্ট্রাক্টে টোকেনের মোট সরবরাহ (total supply) রিটার্ন করে। এই মানটি ইথেরিয়াম-এর সবচেয়ে সাধারণ টাইপ, আনসাইনড 256 বিট ব্যবহার করে রিটার্ন করা হয় (256 বিট হলো EVM-এর নেটিভ ওয়ার্ড সাইজ)। এই ফাংশনটি একটি `view`-ও, যার অর্থ এটি স্টেট পরিবর্তন করে না, তাই ব্লকচেইন-এর প্রতিটি নোড-এ এটি চালানোর পরিবর্তে একটি একক নোড-এ এটি এক্সিকিউট করা যেতে পারে। এই ধরনের ফাংশন কোনো ট্রানজ্যাকশন তৈরি করে না এবং এতে কোনো [গ্যাস](/developers/docs/gas/) খরচ হয় না।

**দ্রষ্টব্য:** তাত্ত্বিকভাবে মনে হতে পারে যে কোনো কন্ট্রাক্টের নির্মাতা আসল মানের চেয়ে কম মোট সরবরাহ রিটার্ন করে প্রতারণা করতে পারে, যার ফলে প্রতিটি টোকেন বাস্তবে যতটা মূল্যবান তার চেয়ে বেশি মূল্যবান বলে মনে হয়। তবে, এই ভয় ব্লকচেইন-এর প্রকৃত প্রকৃতিকে উপেক্ষা করে। ব্লকচেইন-এ যা কিছু ঘটে তা প্রতিটি নোড দ্বারা যাচাই করা যেতে পারে। এটি অর্জন করতে, প্রতিটি কন্ট্রাক্টের মেশিন ল্যাঙ্গুয়েজ কোড এবং স্টোরেজ প্রতিটি নোড-এ উপলব্ধ থাকে। যদিও আপনার কন্ট্রাক্টের জন্য Solidity কোড প্রকাশ করা বাধ্যতামূলক নয়, তবে আপনি সোর্স কোড এবং যে Solidity সংস্করণ দিয়ে এটি কম্পাইল করা হয়েছিল তা প্রকাশ না করলে কেউ আপনাকে গুরুত্ব সহকারে নেবে না, যাতে এটি আপনার দেওয়া মেশিন ল্যাঙ্গুয়েজ কোডের বিপরীতে যাচাই করা যায়।
উদাহরণস্বরূপ, [এই কন্ট্রাক্টটি](https://eth.blockscout.com/address/0xa530F85085C6FE2f866E7FdB716849714a89f4CD?tab=contract) দেখুন।

&nbsp;

```solidity
    /**
     * @dev `account` অ্যাকাউন্টের মালিকানাধীন টোকেনের পরিমাণ রিটার্ন করে।
     */
    function balanceOf(address account) external view returns (uint256);
```

নাম থেকেই বোঝা যায়, `balanceOf` একটি অ্যাকাউন্টের ব্যালেন্স রিটার্ন করে। ইথেরিয়াম অ্যাকাউন্টগুলো Solidity-তে `address` টাইপ ব্যবহার করে চিহ্নিত করা হয়, যা 160 বিট ধারণ করে।
এটি `external` এবং `view`-ও।

&nbsp;

```solidity
    /**
     * @dev কলারের অ্যাকাউন্ট থেকে `recipient`-এ `amount` টোকেন হস্তান্তর করে।
     *
     * অপারেশনটি সফল হয়েছে কিনা তা নির্দেশ করে একটি বুলিয়ান মান রিটার্ন করে।
     *
     * একটি {Transfer} ইভেন্ট এমিট করে।
     */
    function transfer(address recipient, uint256 amount) external returns (bool);
```

`transfer` ফাংশনটি কলারের কাছ থেকে একটি ভিন্ন ঠিকানায় টোকেন হস্তান্তর করে। এর সাথে স্টেট-এর পরিবর্তন জড়িত, তাই এটি কোনো `view` নয়।
যখন কোনো ব্যবহারকারী এই ফাংশনটি কল করে তখন এটি একটি ট্রানজ্যাকশন তৈরি করে এবং গ্যাস খরচ হয়। এটি ব্লকচেইন-এর সবাইকে ইভেন্ট সম্পর্কে জানাতে একটি ইভেন্ট, `Transfer`, এমিট করে।

দুটি ভিন্ন ধরনের কলারের জন্য ফাংশনটির দুই ধরনের আউটপুট রয়েছে:

- ব্যবহারকারীরা যারা সরাসরি ইউজার ইন্টারফেস থেকে ফাংশনটি কল করে। সাধারণত ব্যবহারকারী একটি ট্রানজ্যাকশন সাবমিট করে এবং কোনো প্রতিক্রিয়ার জন্য অপেক্ষা করে না, যা অনির্দিষ্ট পরিমাণ সময় নিতে পারে। ব্যবহারকারী ট্রানজ্যাকশন রসিদ (যা ট্রানজ্যাকশন হ্যাশ দ্বারা চিহ্নিত করা হয়) বা `Transfer` ইভেন্টটি দেখে কী ঘটেছে তা দেখতে পারে।
- অন্যান্য কন্ট্রাক্ট, যা একটি সামগ্রিক ট্রানজ্যাকশনের অংশ হিসেবে ফাংশনটি কল করে। সেই কন্ট্রাক্টগুলো অবিলম্বে ফলাফল পায়, কারণ তারা একই ট্রানজ্যাকশনে চলে, তাই তারা ফাংশনের রিটার্ন ভ্যালু ব্যবহার করতে পারে।

কন্ট্রাক্টের স্টেট পরিবর্তন করে এমন অন্যান্য ফাংশন দ্বারা একই ধরনের আউটপুট তৈরি করা হয়।

&nbsp;

অ্যালাউন্স একটি অ্যাকাউন্টকে অন্য মালিকের কিছু টোকেন খরচ করার অনুমতি দেয়।
এটি কার্যকর, উদাহরণস্বরূপ, বিক্রেতা হিসেবে কাজ করা কন্ট্রাক্টগুলোর জন্য। কন্ট্রাক্টগুলো
ইভেন্টগুলোর জন্য নজরদারি করতে পারে না, তাই যদি কোনো ক্রেতা সরাসরি বিক্রেতা কন্ট্রাক্টে টোকেন হস্তান্তর করে
তবে সেই কন্ট্রাক্টটি জানতে পারবে না যে তাকে অর্থ প্রদান করা হয়েছে। এর পরিবর্তে, ক্রেতা
বিক্রেতা কন্ট্রাক্টকে একটি নির্দিষ্ট পরিমাণ খরচ করার অনুমতি দেয় এবং বিক্রেতা সেই পরিমাণটি হস্তান্তর করে।
এটি বিক্রেতা কন্ট্রাক্ট কল করে এমন একটি ফাংশনের মাধ্যমে করা হয়, যাতে বিক্রেতা কন্ট্রাক্ট
জানতে পারে যে এটি সফল হয়েছে কিনা।

```solidity
    /**
     * @dev {transferFrom}-এর মাধ্যমে `owner`-এর পক্ষে `spender`-কে যে পরিমাণ অবশিষ্ট টোকেন খরচ করার অনুমতি দেওয়া হবে তা রিটার্ন করে। ডিফল্টরূপে এটি শূন্য থাকে।
     *
     * {approve} বা {transferFrom} কল করা হলে এই মানটি পরিবর্তিত হয়।
     */
    function allowance(address owner, address spender) external view returns (uint256);
```

`allowance` ফাংশনটি যে কাউকে কোয়েরি করে দেখতে দেয় যে একটি ঠিকানা
(`owner`) অন্য একটি ঠিকানাকে (`spender`) কী পরিমাণ অ্যালাউন্স খরচ করতে দেয়।

&nbsp;

```solidity
    /**
     * @dev কলারের টোকেনের উপর `spender`-এর অ্যালাউন্স হিসেবে `amount` সেট করে।
     *
     * অপারেশনটি সফল হয়েছে কিনা তা নির্দেশ করে একটি বুলিয়ান মান রিটার্ন করে।
     *
     * গুরুত্বপূর্ণ: সতর্ক থাকুন যে এই পদ্ধতির মাধ্যমে অ্যালাউন্স পরিবর্তন করলে এমন ঝুঁকি তৈরি হয় যে দুর্ভাগ্যজনক ট্রানজ্যাকশন অর্ডারিংয়ের কারণে কেউ পুরানো এবং নতুন উভয় অ্যালাউন্স ব্যবহার করতে পারে। এই রেস কন্ডিশন প্রশমিত করার একটি সম্ভাব্য সমাধান হলো প্রথমে স্পেন্ডারের অ্যালাউন্স কমিয়ে 0 করা এবং পরে কাঙ্ক্ষিত মান সেট করা:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * একটি {Approval} ইভেন্ট এমিট করে।
     */
    function approve(address spender, uint256 amount) external returns (bool);
```

`approve` ফাংশনটি একটি অ্যালাউন্স তৈরি করে। এটি কীভাবে অপব্যবহার করা যেতে পারে
সে সম্পর্কে বার্তাটি পড়তে ভুলবেন না। ইথেরিয়াম-এ আপনি আপনার নিজের ট্রানজ্যাকশনের ক্রম নিয়ন্ত্রণ করেন,
কিন্তু অন্য লোকেদের ট্রানজ্যাকশনগুলো কোন ক্রমে এক্সিকিউট করা হবে তা আপনি নিয়ন্ত্রণ করতে পারবেন না,
যদি না আপনি অন্য পক্ষের ট্রানজ্যাকশনটি সম্পন্ন হতে দেখার আগে আপনার নিজের ট্রানজ্যাকশন সাবমিট না করেন।

&nbsp;

```solidity
    /**
     * @dev অ্যালাউন্স মেকানিজম ব্যবহার করে `sender` থেকে `recipient`-এ `amount` টোকেন হস্তান্তর করে। এরপর কলারের অ্যালাউন্স থেকে `amount` কেটে নেওয়া হয়।
     *
     * অপারেশনটি সফল হয়েছে কিনা তা নির্দেশ করে একটি বুলিয়ান মান রিটার্ন করে।
     *
     * একটি {Transfer} ইভেন্ট এমিট করে।
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
```

অবশেষে, `transferFrom` স্পেন্ডার দ্বারা প্রকৃতপক্ষে অ্যালাউন্স খরচ করতে ব্যবহৃত হয়।

&nbsp;

```solidity

    /**
     * @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 কন্ট্রাক্টের স্টেট পরিবর্তিত হলে এই ইভেন্টগুলো এমিট করা হয়।

## আসল কন্ট্রাক্ট {#the-actual-contract}

এটি হলো আসল কন্ট্রাক্ট যা ERC-20 স্ট্যান্ডার্ড ইমপ্লিমেন্ট করে,
যা [এখান থেকে নেওয়া হয়েছে](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol)।
এটি যেমন আছে তেমন ব্যবহার করার উদ্দেশ্যে নয়, তবে আপনি
এটিকে ব্যবহারযোগ্য কিছুতে প্রসারিত করতে এটি থেকে [ইনহেরিট](https://www.tutorialspoint.com/solidity/solidity_inheritance.htm) করতে পারেন।

```solidity
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
```

&nbsp;

### ইমপোর্ট স্টেটমেন্ট {#import-statements}

উপরের ইন্টারফেস ডেফিনিশনগুলো ছাড়াও, কন্ট্রাক্ট ডেফিনিশনটি আরও দুটি ফাইল ইমপোর্ট করে:

```solidity

import "../../GSN/Context.sol";
import "./IERC20.sol";
import "../../math/SafeMath.sol";
```

- `GSN/Context.sol` হলো [OpenGSN](https://opengsn.org/) ব্যবহার করার জন্য প্রয়োজনীয় ডেফিনিশন, এটি এমন একটি সিস্টেম যা ইথার ছাড়া ব্যবহারকারীদের ব্লকচেইন ব্যবহার করতে দেয়। মনে রাখবেন যে এটি একটি পুরোনো সংস্করণ, আপনি যদি OpenGSN-এর সাথে ইন্টিগ্রেট করতে চান তবে [এই টিউটোরিয়ালটি ব্যবহার করুন](https://docs.opengsn.org/javascript-client/tutorial.html)।
- [SafeMath লাইব্রেরি](https://ethereumdev.io/using-safe-math-library-to-prevent-from-overflows/), যা **&lt;0.8.0** Solidity সংস্করণগুলোর জন্য গাণিতিক ওভারফ্লো/আন্ডারফ্লো প্রতিরোধ করে। ≥0.8.0 Solidity-তে, গাণিতিক ক্রিয়াকলাপগুলো ওভারফ্লো/আন্ডারফ্লো হলে স্বয়ংক্রিয়ভাবে রিভার্ট হয়, যা SafeMath-কে অপ্রয়োজনীয় করে তোলে। এই কন্ট্রাক্টটি পুরোনো কম্পাইলার সংস্করণগুলোর সাথে ব্যাকওয়ার্ড সামঞ্জস্যের জন্য SafeMath ব্যবহার করে।

&nbsp;

এই মন্তব্যটি কন্ট্রাক্টের উদ্দেশ্য ব্যাখ্যা করে।

```solidity
/**
 * @dev {IERC20} ইন্টারফেসের ইমপ্লিমেন্টেশন।
 *
 * এই ইমপ্লিমেন্টেশনটি টোকেন তৈরির পদ্ধতির প্রতি অজ্ঞেয় (agnostic)। এর মানে হলো {_mint} ব্যবহার করে একটি ডিরাইভড কন্ট্রাক্ট-এ সাপ্লাই মেকানিজম যোগ করতে হবে।
 * একটি সাধারণ মেকানিজমের জন্য {ERC20PresetMinterPauser} দেখুন।
 *
 * টিপ: বিস্তারিত লেখার জন্য আমাদের গাইড দেখুন
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms]।
 *
 * আমরা সাধারণ ওপেনজেপেলিন গাইডলাইন অনুসরণ করেছি: ব্যর্থ হলে ফাংশনগুলো `false` রিটার্ন করার পরিবর্তে রিভার্ট করে। এই আচরণটি প্রচলিত এবং এটি ERC-20 অ্যাপ্লিকেশনের প্রত্যাশার সাথে সাংঘর্ষিক নয়।
 *
 * উপরন্তু, {transferFrom} কল করার সময় একটি {Approval} ইভেন্ট এমিট হয়।
 * এটি অ্যাপ্লিকেশনগুলোকে শুধুমাত্র উক্ত ইভেন্টগুলো শুনে সমস্ত অ্যাকাউন্টের জন্য অ্যালাউন্স পুনর্গঠন করতে দেয়। EIP-এর অন্যান্য ইমপ্লিমেন্টেশন এই ইভেন্টগুলো এমিট নাও করতে পারে, কারণ এটি স্পেসিফিকেশন দ্বারা প্রয়োজনীয় নয়।
 *
 * পরিশেষে, অ্যালাউন্স সেট করার সুপরিচিত সমস্যাগুলো প্রশমিত করতে নন-স্ট্যান্ডার্ড {decreaseAllowance} এবং {increaseAllowance}
 * ফাংশনগুলো যোগ করা হয়েছে। {IERC20-approve} দেখুন।
 */

```

### কন্ট্রাক্ট ডেফিনিশন {#contract-definition}

```solidity
contract ERC20 is Context, IERC20 {
```

এই লাইনটি ইনহেরিটেন্স নির্দিষ্ট করে, এই ক্ষেত্রে উপরের `IERC20` থেকে এবং OpenGSN-এর জন্য `Context` থেকে।

&nbsp;

```solidity

    using SafeMath for uint256;

```

এই লাইনটি `SafeMath` লাইব্রেরিটিকে `uint256` টাইপের সাথে যুক্ত করে। আপনি এই লাইব্রেরিটি
[এখানে](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol) খুঁজে পেতে পারেন।

### ভেরিয়েবল ডেফিনিশন {#variable-definitions}

এই ডেফিনিশনগুলো কন্ট্রাক্টের স্টেট ভেরিয়েবলগুলো নির্দিষ্ট করে। এই ভেরিয়েবলগুলো `private` হিসেবে ঘোষণা করা হয়েছে, তবে
এর অর্থ কেবল এই যে ব্লকচেইন-এর অন্যান্য কন্ট্রাক্টগুলো এগুলো পড়তে পারে না। _ব্লকচেইন-এ কোনো
গোপনীয়তা নেই_, প্রতিটি নোড-এর সফ্টওয়্যারে প্রতিটি ব্লক-এ প্রতিটি কন্ট্রাক্টের স্টেট থাকে।
প্রথা অনুযায়ী, স্টেট ভেরিয়েবলগুলোর নাম `_<something>` রাখা হয়।

প্রথম দুটি ভেরিয়েবল হলো [ম্যাপিং](https://www.tutorialspoint.com/solidity/solidity_mappings.htm),
যার অর্থ এগুলো প্রায় [অ্যাসোসিয়েটিভ অ্যারে](https://wikipedia.org/wiki/Associative_array)-এর মতোই আচরণ করে,
তবে পার্থক্য হলো কী (key) গুলো সাংখ্যিক মান। শুধুমাত্র সেই এন্ট্রিগুলোর জন্যই স্টোরেজ বরাদ্দ করা হয় যেগুলোর মান
ডিফল্ট (শূন্য) থেকে আলাদা।

```solidity
    mapping (address => uint256) private _balances;
```

প্রথম ম্যাপিং, `_balances`, হলো ঠিকানা এবং এই টোকেনের তাদের নিজ নিজ ব্যালেন্স। ব্যালেন্স অ্যাক্সেস
করতে, এই সিনট্যাক্সটি ব্যবহার করুন: `_balances[<address>]`।

&nbsp;

```solidity
    mapping (address => mapping (address => uint256)) private _allowances;
```

এই ভেরিয়েবল, `_allowances`, আগে ব্যাখ্যা করা অ্যালাউন্সগুলো সংরক্ষণ করে। প্রথম সূচক হলো টোকেনগুলোর
মালিক এবং দ্বিতীয়টি হলো অ্যালাউন্স সহ কন্ট্রাক্ট। ঠিকানা A ঠিকানা B-এর অ্যাকাউন্ট থেকে যে পরিমাণ
খরচ করতে পারে তা অ্যাক্সেস করতে, `_allowances[B][A]` ব্যবহার করুন।

&nbsp;

```solidity
    uint256 private _totalSupply;
```

নাম থেকেই বোঝা যায়, এই ভেরিয়েবলটি টোকেনের মোট সরবরাহের হিসাব রাখে।

&nbsp;

```solidity
    string private _name;
    string private _symbol;
    uint8 private _decimals;
```

এই তিনটি ভেরিয়েবল পঠনযোগ্যতা উন্নত করতে ব্যবহৃত হয়। প্রথম দুটি স্ব-ব্যাখ্যামূলক, কিন্তু `_decimals`
নয়।

একদিকে, ইথেরিয়াম-এ ফ্লোটিং পয়েন্ট বা ভগ্নাংশ ভেরিয়েবল নেই। অন্যদিকে,
মানুষ টোকেন ভাগ করতে সক্ষম হতে পছন্দ করে। লোকেরা মুদ্রার জন্য সোনা বেছে নেওয়ার একটি কারণ ছিল যে
যখন কেউ একটি হাঁসের মূল্যের সমপরিমাণ গরু কিনতে চাইত তখন খুচরা করা কঠিন ছিল।

এর সমাধান হলো পূর্ণসংখ্যার হিসাব রাখা, কিন্তু আসল টোকেনের পরিবর্তে একটি ভগ্নাংশ টোকেন গণনা করা যা
প্রায় মূল্যহীন। ইথার-এর ক্ষেত্রে, ভগ্নাংশ টোকেনটিকে Wei বলা হয় এবং 10^18 Wei এক
ETH-এর সমান। লেখার সময়, 10,000,000,000,000 Wei প্রায় এক ইউএস বা ইউরো সেন্টের সমান।

অ্যাপ্লিকেশনগুলোর জানা দরকার কীভাবে টোকেন ব্যালেন্স প্রদর্শন করতে হয়। যদি কোনো ব্যবহারকারীর 3,141,000,000,000,000,000 Wei থাকে, তবে তা কি
3.14 ETH? 31.41 ETH? 3,141 ETH? ইথার-এর ক্ষেত্রে এটি ETH-এর জন্য 10^18 Wei হিসেবে সংজ্ঞায়িত করা হয়েছে, তবে আপনার
টোকেনের জন্য আপনি একটি ভিন্ন মান নির্বাচন করতে পারেন। যদি টোকেন ভাগ করা অর্থপূর্ণ না হয়, তবে আপনি একটি
`_decimals` এর মান শূন্য ব্যবহার করতে পারেন। আপনি যদি ETH-এর মতো একই স্ট্যান্ডার্ড ব্যবহার করতে চান, তবে **18** মানটি ব্যবহার করুন।

### কনস্ট্রাক্টর {#the-constructor}

```solidity
    /**
     * @dev {name} এবং {symbol}-এর মান সেট করে, 18-এর ডিফল্ট মান দিয়ে {decimals} ইনিশিয়ালাইজ করে।
     *
     * {decimals}-এর জন্য একটি ভিন্ন মান নির্বাচন করতে, {_setupDecimals} ব্যবহার করুন।
     *
     * এই তিনটি মানই অপরিবর্তনীয় (immutable): এগুলো কনস্ট্রাকশন চলাকালীন শুধুমাত্র একবার সেট করা যেতে পারে।
     */
    constructor (string memory name_, string memory symbol_) public {
        // Solidity ≥0.7.0-এ, 'public' ইমপ্লিসিট এবং এটি বাদ দেওয়া যেতে পারে।

        _name = name_;
        _symbol = symbol_;
        _decimals = 18;
    }
```

কন্ট্রাক্টটি প্রথম তৈরি হওয়ার সময় কনস্ট্রাক্টর কল করা হয়। প্রথা অনুযায়ী, ফাংশন প্যারামিটারগুলোর নাম `<something>_` রাখা হয়।

### ইউজার ইন্টারফেস ফাংশন {#user-interface-functions}

```solidity
    /**
     * @dev টোকেনের নাম রিটার্ন করে।
     */
    function name() public view returns (string memory) {
        return _name;
    }

    /**
     * @dev টোকেনের প্রতীক (symbol) রিটার্ন করে, সাধারণত নামের একটি ছোট সংস্করণ।
     */
    function symbol() public view returns (string memory) {
        return _symbol;
    }

    /**
     * @dev এর ইউজার রিপ্রেজেন্টেশন পেতে ব্যবহৃত ডেসিম্যাল সংখ্যা রিটার্ন করে।
     * উদাহরণস্বরূপ, যদি `decimals` `2` এর সমান হয়, তবে `505` টোকেনের ব্যালেন্স
     * একজন ব্যবহারকারীকে `5,05` (`505 / 10 ** 2`) হিসেবে দেখানো উচিত।
     *
     * ইথার এবং Wei-এর মধ্যকার সম্পর্ক অনুকরণ করে টোকেনগুলো সাধারণত 18 মান বেছে নেয়। {_setupDecimals} কল করা না হলে {ERC-20} এই মানটিই ব্যবহার করে।
     *
     * দ্রষ্টব্য: এই তথ্যটি শুধুমাত্র _প্রদর্শনের_ (display) উদ্দেশ্যে ব্যবহৃত হয়: এটি
     * কোনোভাবেই {IERC20-balanceOf} এবং {IERC20-transfer} সহ কন্ট্রাক্ট-এর কোনো পাটিগণিতকে প্রভাবিত করে না।
     */
    function decimals() public view returns (uint8) {
        return _decimals;
    }
```

এই ফাংশনগুলো, `name`, `symbol`, এবং `decimals` ইউজার ইন্টারফেসগুলোকে আপনার কন্ট্রাক্ট সম্পর্কে জানতে সাহায্য করে যাতে তারা এটি সঠিকভাবে প্রদর্শন করতে পারে।

রিটার্ন টাইপ হলো `string memory`, যার অর্থ মেমরিতে সংরক্ষিত একটি স্ট্রিং রিটার্ন করা। ভেরিয়েবলগুলো, যেমন
স্ট্রিং, তিনটি স্থানে সংরক্ষণ করা যেতে পারে:

|          | লাইফটাইম      | কন্ট্রাক্ট অ্যাক্সেস | গ্যাস খরচ                                                       |
| -------- | ------------- | --------------- | -------------------------------------------------------------- |
| মেমরি   | ফাংশন কল | রিড/রাইট      | দশ বা শত (উচ্চতর লোকেশনের জন্য বেশি)                 |
| কল ডেটা | ফাংশন কল | শুধুমাত্র রিড       | রিটার্ন টাইপ হিসেবে ব্যবহার করা যাবে না, শুধুমাত্র ফাংশন প্যারামিটার টাইপ |
| স্টোরেজ  | পরিবর্তন না হওয়া পর্যন্ত | রিড/রাইট      | বেশি (রিড করার জন্য 800, রাইট করার জন্য 20k)                             |

এই ক্ষেত্রে, `memory` হলো সেরা পছন্দ।

### টোকেন তথ্য পড়ুন {#read-token-information}

এগুলো এমন ফাংশন যা টোকেন সম্পর্কে তথ্য প্রদান করে, হয় মোট সরবরাহ বা কোনো
অ্যাকাউন্টের ব্যালেন্স।

```solidity
    /**
     * @dev {IERC20-totalSupply} দেখুন।
     */
    function totalSupply() public view override returns (uint256) {
        return _totalSupply;
    }
```

`totalSupply` ফাংশনটি টোকেনের মোট সরবরাহ রিটার্ন করে।

&nbsp;

```solidity
    /**
     * @dev {IERC20-balanceOf} দেখুন।
     */
    function balanceOf(address account) public view override returns (uint256) {
        return _balances[account];
    }
```

একটি অ্যাকাউন্টের ব্যালেন্স পড়ুন। মনে রাখবেন যে যে কাউকে অন্য কারও অ্যাকাউন্ট
ব্যালেন্স পাওয়ার অনুমতি দেওয়া হয়েছে। এই তথ্য লুকানোর চেষ্টা করার কোনো মানে নেই, কারণ এটি যেকোনোভাবেই প্রতিটি
নোড-এ উপলব্ধ। _ব্লকচেইন-এ কোনো গোপনীয়তা নেই।_

### টোকেন হস্তান্তর {#transfer-tokens}

```solidity
    /**
     * @dev {IERC20-transfer} দেখুন।
     *
     * প্রয়োজনীয়তা:
     *
     * - `recipient` জিরো অ্যাড্রেস হতে পারবে না।
     * - কলারের ব্যালেন্স কমপক্ষে `amount` হতে হবে।
     */
    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
```

`transfer` ফাংশনটি প্রেরকের অ্যাকাউন্ট থেকে অন্য অ্যাকাউন্টে টোকেন হস্তান্তর করতে কল করা হয়। মনে
রাখবেন যে যদিও এটি একটি বুলিয়ান মান রিটার্ন করে, সেই মানটি সর্বদা **true** হয়। যদি হস্তান্তর
ব্যর্থ হয় তবে কন্ট্রাক্টটি কলটি রিভার্ট করে।

&nbsp;

```solidity
        _transfer(_msgSender(), recipient, amount);
        return true;
    }
```

`_transfer` ফাংশনটি আসল কাজ করে। এটি একটি প্রাইভেট ফাংশন যা শুধুমাত্র অন্যান্য
কন্ট্রাক্ট ফাংশন দ্বারা কল করা যেতে পারে। প্রথা অনুযায়ী প্রাইভেট ফাংশনগুলোর নাম `_<something>` রাখা হয়, যা স্টেট
ভেরিয়েবলগুলোর মতোই।

সাধারণত Solidity-তে আমরা বার্তা প্রেরকের জন্য `msg.sender` ব্যবহার করি। তবে, এটি
[OpenGSN](https://opengsn.org/)-কে ভেঙে দেয়। আমরা যদি আমাদের টোকেনের সাথে ইথারবিহীন ট্রানজ্যাকশনের অনুমতি দিতে চাই, তবে আমাদের
`_msgSender()` ব্যবহার করতে হবে। এটি সাধারণ ট্রানজ্যাকশনের জন্য `msg.sender` রিটার্ন করে, কিন্তু ইথারবিহীন ট্রানজ্যাকশনের জন্য
আসল স্বাক্ষরকারীকে রিটার্ন করে এবং বার্তাটি রিলে করা কন্ট্রাক্টকে নয়।

### অ্যালাউন্স ফাংশন {#allowance-functions}

এগুলো হলো সেই ফাংশন যা অ্যালাউন্স কার্যকারিতা ইমপ্লিমেন্ট করে: `allowance`, `approve`, `transferFrom`,
এবং `_approve`। উপরন্তু, ওপেনজেপেলিন ইমপ্লিমেন্টেশনটি মৌলিক স্ট্যান্ডার্ডের বাইরে গিয়ে কিছু বৈশিষ্ট্য অন্তর্ভুক্ত করে যা নিরাপত্তা
উন্নত করে: `increaseAllowance`, এবং `decreaseAllowance`।

#### allowance ফাংশন {#allowance}

```solidity
    /**
     * @dev {IERC20-allowance} দেখুন।
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }
```

`allowance` ফাংশনটি সবাইকে যেকোনো অ্যালাউন্স চেক করার অনুমতি দেয়।

#### approve ফাংশন {#approve}

```solidity
    /**
     * @dev {IERC20-approve} দেখুন।
     *
     * প্রয়োজনীয়তা:
     *
     * - `spender` জিরো অ্যাড্রেস হতে পারবে না।
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
```

এই ফাংশনটি একটি অ্যালাউন্স তৈরি করতে কল করা হয়। এটি উপরের `transfer` ফাংশনের মতোই:

- ফাংশনটি কেবল একটি ইন্টারনাল ফাংশন কল করে (এই ক্ষেত্রে, `_approve`) যা আসল কাজ করে।
- ফাংশনটি হয় `true` রিটার্ন করে (যদি সফল হয়) অথবা রিভার্ট করে (যদি না হয়)।

&nbsp;

```solidity
        _approve(_msgSender(), spender, amount);
        return true;
    }
```

স্টেট পরিবর্তন হওয়ার স্থানগুলোর সংখ্যা কমানোর জন্য আমরা ইন্টারনাল ফাংশন ব্যবহার করি। স্টেট পরিবর্তন করে এমন _যেকোনো_ ফাংশন একটি সম্ভাব্য নিরাপত্তা ঝুঁকি যা নিরাপত্তার জন্য অডিট করা প্রয়োজন। এইভাবে আমাদের ভুল করার সম্ভাবনা কম থাকে।

#### transferFrom ফাংশন {#transferfrom}

এটি হলো সেই ফাংশন যা একজন স্পেন্ডার একটি অ্যালাউন্স খরচ করতে কল করে। এর জন্য দুটি ক্রিয়াকলাপ প্রয়োজন: খরচ করা পরিমাণটি
হস্তান্তর করা এবং সেই পরিমাণ দ্বারা অ্যালাউন্স কমানো।

```solidity
    /**
     * @dev {IERC20-transferFrom} দেখুন।
     *
     * আপডেট করা অ্যালাউন্স নির্দেশ করে একটি {Approval} ইভেন্ট এমিট করে। এটি EIP দ্বারা প্রয়োজনীয় নয়। {ERC-20}-এর শুরুতে থাকা নোটটি দেখুন।
     *
     * প্রয়োজনীয়তা:
     *
     * - `sender` এবং `recipient` জিরো অ্যাড্রেস হতে পারবে না।
     * - `sender`-এর ব্যালেন্স কমপক্ষে `amount` হতে হবে।
     * - কলারের কাছে ``sender``-এর টোকেনের জন্য কমপক্ষে `amount` অ্যালাউন্স থাকতে হবে।
     */
    function transferFrom(address sender, address recipient, uint256 amount) public virtual
                                                override returns (bool) {
        _transfer(sender, recipient, amount);
```

&nbsp;

`a.sub(b, "message")` ফাংশন কলটি দুটি কাজ করে। প্রথমত, এটি `a-b` গণনা করে, যা হলো নতুন অ্যালাউন্স।
দ্বিতীয়ত, এটি চেক করে যে এই ফলাফলটি নেতিবাচক নয়। যদি এটি নেতিবাচক হয় তবে কলটি প্রদত্ত বার্তার সাথে রিভার্ট করে। মনে রাখবেন যে যখন কোনো কল রিভার্ট হয় তখন সেই কলের সময় আগে করা যেকোনো প্রসেসিং উপেক্ষা করা হয় তাই আমাদের
`_transfer` আনডু করার প্রয়োজন নেই।

```solidity
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount,
             "ERC20: transfer amount exceeds allowance"));
        return true;
    }
```

#### ওপেনজেপেলিন নিরাপত্তা সংযোজন {#openzeppelin-safety-additions}

একটি নন-জিরো অ্যালাউন্সকে অন্য একটি নন-জিরো মানে সেট করা বিপজ্জনক,
কারণ আপনি শুধুমাত্র আপনার নিজের ট্রানজ্যাকশনের ক্রম নিয়ন্ত্রণ করেন, অন্য কারও নয়। কল্পনা করুন আপনার
দুজন ব্যবহারকারী আছে, অ্যালিস যে সরল এবং বিল যে অসৎ। অ্যালিস বিলের কাছ থেকে কিছু পরিষেবা চায়,
যার দাম সে মনে করে পাঁচটি টোকেন - তাই সে বিলকে পাঁচটি টোকেনের একটি অ্যালাউন্স দেয়।

তারপর কিছু পরিবর্তন হয় এবং বিলের দাম বেড়ে দশটি টোকেন হয়। অ্যালিস, যে এখনও পরিষেবাটি চায়,
একটি ট্রানজ্যাকশন পাঠায় যা বিলের অ্যালাউন্স দশে সেট করে। বিল যখন লেনদেন পুল-এ এই নতুন ট্রানজ্যাকশনটি
দেখে, তখন সে একটি ট্রানজ্যাকশন পাঠায় যা অ্যালিসের পাঁচটি টোকেন খরচ করে এবং এর গ্যাস প্রাইস অনেক
বেশি থাকে যাতে এটি দ্রুত মাইন করা হয়। এইভাবে বিল প্রথমে পাঁচটি টোকেন খরচ করতে পারে এবং তারপর,
অ্যালিসের নতুন অ্যালাউন্স মাইন হওয়ার পর, আরও দশটি খরচ করতে পারে মোট পনেরোটি টোকেনের জন্য, যা
অ্যালিস অনুমোদন করতে চেয়েছিল তার চেয়ে বেশি। এই কৌশলটিকে
[ফ্রন্ট-রানিং](https://consensysdiligence.github.io/smart-contract-best-practices/attacks/#front-running) বলা হয়।

| অ্যালিসের ট্রানজ্যাকশন | অ্যালিসের নন্স | বিলের ট্রানজ্যাকশন              | বিলের নন্স | বিলের অ্যালাউন্স | অ্যালিসের কাছ থেকে বিলের মোট আয় |
| ----------------- | ----------- | ----------------------------- | ---------- | ---------------- | ---------------------------- |
| 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 |

```solidity
    /**
     * @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` এটি সাধারণ যোগফলের মতো র‍্যাপ অ্যারাউন্ড (wrap around)
করে না।

```solidity

    /**
     * @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;
    }
```

### টোকেন তথ্য পরিবর্তনকারী ফাংশন {#functions-that-modify-token-information}

এই চারটি ফাংশন আসল কাজ করে: `_transfer`, `_mint`, `_burn`, এবং `_approve`।

#### _transfer ফাংশন {#transfer}

```solidity
    /**
     * @dev `sender` থেকে `recipient`-এ `amount` টোকেন হস্তান্তর করে।
     *
     * এই ইন্টারনাল ফাংশনটি {transfer}-এর সমতুল্য, এবং এটি যেমন স্বয়ংক্রিয় টোকেন ফি, স্ল্যাশিং মেকানিজম ইত্যাদি ইমপ্লিমেন্ট করতে ব্যবহার করা যেতে পারে।
     *
     * একটি {Transfer} ইভেন্ট এমিট করে।
     *
     * প্রয়োজনীয়তা:
     *
     * - `sender` জিরো অ্যাড্রেস হতে পারবে না।
     * - `recipient` জিরো অ্যাড্রেস হতে পারবে না।
     * - `sender`-এর ব্যালেন্স কমপক্ষে `amount` হতে হবে।
     */
    function _transfer(address sender, address recipient, uint256 amount) internal virtual {
```

এই ফাংশন, `_transfer`, এক অ্যাকাউন্ট থেকে অন্য অ্যাকাউন্টে টোকেন হস্তান্তর করে। এটি `transfer` (প্রেরকের নিজস্ব অ্যাকাউন্ট থেকে হস্তান্তরের জন্য) এবং `transferFrom` (অন্য কারও অ্যাকাউন্ট থেকে হস্তান্তর করতে অ্যালাউন্স ব্যবহার করার জন্য) উভয় দ্বারাই
কল করা হয়।

&nbsp;

```solidity
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");
```

ইথেরিয়াম-এ আসলে জিরো অ্যাড্রেস-এর মালিক কেউ নয় (অর্থাৎ, কেউ এমন কোনো প্রাইভেট কী জানে না যার সাথে মিলে যাওয়া পাবলিক কী
জিরো অ্যাড্রেস-এ রূপান্তরিত হয়)। যখন লোকেরা সেই ঠিকানাটি ব্যবহার করে, তখন এটি সাধারণত একটি সফ্টওয়্যার বাগ হয় - তাই
জিরো অ্যাড্রেস প্রেরক বা প্রাপক হিসেবে ব্যবহৃত হলে আমরা ব্যর্থ হই।

&nbsp;

```solidity
        _beforeTokenTransfer(sender, recipient, amount);

```

এই কন্ট্রাক্টটি ব্যবহার করার দুটি উপায় রয়েছে:

1. আপনার নিজের কোডের জন্য এটি একটি টেমপ্লেট হিসেবে ব্যবহার করুন
1. [এটি থেকে ইনহেরিট করুন](https://www.bitdegree.org/learn/solidity-inheritance), এবং শুধুমাত্র সেই ফাংশনগুলো ওভাররাইড করুন যা আপনার পরিবর্তন করা প্রয়োজন

দ্বিতীয় পদ্ধতিটি অনেক ভালো কারণ ওপেনজেপেলিন ERC-20 কোডটি ইতিমধ্যে অডিট করা হয়েছে এবং নিরাপদ হিসেবে দেখানো হয়েছে। আপনি যখন ইনহেরিটেন্স ব্যবহার করেন
তখন এটি স্পষ্ট হয় যে আপনি কোন ফাংশনগুলো পরিবর্তন করেছেন এবং আপনার কন্ট্রাক্টকে বিশ্বাস করার জন্য লোকেদের শুধুমাত্র সেই নির্দিষ্ট ফাংশনগুলো অডিট করতে হবে।

প্রতিবার টোকেন হাতবদল হওয়ার সময় একটি ফাংশন সম্পাদন করা প্রায়শই কার্যকর। তবে, `_transfer` একটি অত্যন্ত গুরুত্বপূর্ণ ফাংশন এবং এটি
অনিরাপদভাবে লেখা সম্ভব (নিচে দেখুন), তাই এটি ওভাররাইড না করাই ভালো। এর সমাধান হলো `_beforeTokenTransfer`, একটি
[হুক ফাংশন](https://wikipedia.org/wiki/Hooking)। আপনি এই ফাংশনটি ওভাররাইড করতে পারেন এবং প্রতিটি হস্তান্তরে এটি কল করা হবে।

&nbsp;

```solidity
        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(amount);
```

এই লাইনগুলোই আসলে হস্তান্তর করে। মনে রাখবেন যে এগুলোর মধ্যে **কিছুই নেই**, এবং আমরা প্রাপকের সাথে যোগ করার আগে
প্রেরকের কাছ থেকে হস্তান্তরিত পরিমাণ বিয়োগ করি। এটি গুরুত্বপূর্ণ কারণ যদি মাঝখানে অন্য কোনো কন্ট্রাক্টে
কল করা হতো, তবে এটি এই কন্ট্রাক্টকে প্রতারণা করতে ব্যবহার করা যেতে পারত। এইভাবে হস্তান্তরটি
পারমাণবিক (atomic), এর মাঝখানে কিছুই ঘটতে পারে না।

&nbsp;

```solidity
        emit Transfer(sender, recipient, amount);
    }
```

অবশেষে, একটি `Transfer` ইভেন্ট এমিট করুন। ইভেন্টগুলো স্মার্ট কন্ট্রাক্ট-এর কাছে অ্যাক্সেসযোগ্য নয়, তবে ব্লকচেইন-এর বাইরে চলা কোড
ইভেন্টগুলোর জন্য শুনতে পারে এবং সেগুলোতে প্রতিক্রিয়া জানাতে পারে। উদাহরণস্বরূপ, মালিক কখন আরও টোকেন পায় তার হিসাব একটি ওয়ালেট রাখতে পারে।

#### _mint এবং _burn ফাংশন {#mint-and-burn}

এই দুটি ফাংশন (`_mint` এবং `_burn`) টোকেনের মোট সরবরাহ পরিবর্তন করে।
এগুলো ইন্টারনাল এবং এই কন্ট্রাক্টে এমন কোনো ফাংশন নেই যা এগুলোকে কল করে,
তাই এগুলো শুধুমাত্র তখনই কার্যকর যদি আপনি কন্ট্রাক্ট থেকে ইনহেরিট করেন এবং কোন পরিস্থিতিতে নতুন টোকেন মিন্ট করতে হবে বা বিদ্যমানগুলো পোড়ানো হবে তা সিদ্ধান্ত নিতে আপনার নিজস্ব
লজিক যোগ করেন।

**দ্রষ্টব্য:** প্রতিটি ERC-20 টোকেনের নিজস্ব ব্যবসায়িক লজিক রয়েছে যা টোকেন পরিচালনা নির্দেশ করে।
উদাহরণস্বরূপ, একটি নির্দিষ্ট সরবরাহ কন্ট্রাক্ট শুধুমাত্র কনস্ট্রাক্টরে `_mint`
কল করতে পারে এবং কখনোই `_burn` কল করতে পারে না। টোকেন বিক্রি করে এমন একটি কন্ট্রাক্ট
অর্থ প্রদান করা হলে `_mint` কল করবে এবং পলাতক মুদ্রাস্ফীতি এড়াতে সম্ভবত কোনো এক সময়ে `_burn` কল করবে।

```solidity
    /** @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` আপডেট করতে ভুলবেন না।

&nbsp;

```solidity
    /**
     * @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 ফাংশন {#approve-2}

এটি হলো সেই ফাংশন যা আসলে অ্যালাউন্সগুলো নির্দিষ্ট করে। মনে রাখবেন যে এটি একজন মালিককে এমন একটি অ্যালাউন্স নির্দিষ্ট করার
অনুমতি দেয় যা মালিকের বর্তমান ব্যালেন্সের চেয়ে বেশি। এটি ঠিক আছে কারণ হস্তান্তরের সময় ব্যালেন্স
চেক করা হয়, যখন এটি অ্যালাউন্স তৈরি হওয়ার সময়ের ব্যালেন্স থেকে আলাদা হতে পারে।

```solidity
    /**
     * @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;
```

&nbsp;

একটি `Approval` ইভেন্ট এমিট করুন। অ্যাপ্লিকেশনটি কীভাবে লেখা হয়েছে তার ওপর নির্ভর করে, স্পেন্ডার কন্ট্রাক্টকে অনুমোদন সম্পর্কে মালিক দ্বারা বা এই ইভেন্টগুলো শোনে এমন একটি সার্ভার দ্বারা জানানো যেতে পারে।

```solidity
        emit Approval(owner, spender, amount);
    }

```

### Decimals ভেরিয়েবল পরিবর্তন করুন {#modify-the-decimals-variable}

```solidity


    /**
     * @dev {decimals}-কে 18-এর ডিফল্ট মান ছাড়া অন্য কোনো মানে সেট করে।
     *
     * সতর্কতা: এই ফাংশনটি শুধুমাত্র কনস্ট্রাক্টর থেকে কল করা উচিত। টোকেন কন্ট্রাক্ট-এর সাথে ইন্টারঅ্যাক্ট করা বেশিরভাগ অ্যাপ্লিকেশন আশা করবে না যে {decimals} কখনো পরিবর্তিত হবে, এবং যদি তা হয় তবে ভুলভাবে কাজ করতে পারে।
     */
    function _setupDecimals(uint8 decimals_) internal {
        _decimals = decimals_;
    }
```

এই ফাংশনটি `_decimals` ভেরিয়েবল পরিবর্তন করে যা ইউজার ইন্টারফেসগুলোকে পরিমাণটি কীভাবে ব্যাখ্যা করতে হবে তা বলতে ব্যবহৃত হয়।
আপনার এটি কনস্ট্রাক্টর থেকে কল করা উচিত। পরবর্তী কোনো সময়ে এটি কল করা অসৎ হবে এবং অ্যাপ্লিকেশনগুলো
এটি পরিচালনা করার জন্য ডিজাইন করা হয়নি।

### হুক {#hooks}

```solidity

    /**
     * @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 { }
}
```

এটি হলো হস্তান্তরের সময় কল করার জন্য হুক ফাংশন। এটি এখানে খালি, তবে আপনার যদি
এটি দিয়ে কিছু করার প্রয়োজন হয় তবে আপনি কেবল এটি ওভাররাইড করুন।

## উপসংহার {#conclusion}

পর্যালোচনার জন্য, এখানে এই কন্ট্রাক্টের সবচেয়ে গুরুত্বপূর্ণ কিছু ধারণা দেওয়া হলো (আমার মতে, আপনারটি ভিন্ন হতে পারে):

- _ব্লকচেইন-এ কোনো গোপনীয়তা নেই_। একটি স্মার্ট কন্ট্রাক্ট অ্যাক্সেস করতে পারে এমন যেকোনো তথ্য
  সমগ্র বিশ্বের কাছে উপলব্ধ।
- আপনি আপনার নিজের ট্রানজ্যাকশনের ক্রম নিয়ন্ত্রণ করতে পারেন, কিন্তু অন্য লোকেদের ট্রানজ্যাকশন
  কখন ঘটবে তা নয়। এই কারণেই একটি অ্যালাউন্স পরিবর্তন করা বিপজ্জনক হতে পারে, কারণ এটি
  স্পেন্ডারকে উভয় অ্যালাউন্সের যোগফল খরচ করতে দেয়।
- `uint256` টাইপের মানগুলো র‍্যাপ অ্যারাউন্ড করে। অন্য কথায়, _0-1=2^256-1_। যদি এটি কাঙ্ক্ষিত
  আচরণ না হয়, তবে আপনাকে এটি চেক করতে হবে (বা SafeMath লাইব্রেরি ব্যবহার করতে হবে যা আপনার জন্য এটি করে)। মনে রাখবেন যে এটি
  [Solidity 0.8.0](https://docs.soliditylang.org/en/breaking/080-breaking-changes.html)-এ পরিবর্তিত হয়েছে।
- একটি নির্দিষ্ট স্থানে একটি নির্দিষ্ট টাইপের সমস্ত স্টেট পরিবর্তন করুন, কারণ এটি অডিটিং সহজ করে তোলে।
  এই কারণেই আমাদের কাছে আছে, উদাহরণস্বরূপ, `_approve`, যা `approve`, `transferFrom`,
  `increaseAllowance`, এবং `decreaseAllowance` দ্বারা কল করা হয়
- স্টেট পরিবর্তনগুলো পারমাণবিক (atomic) হওয়া উচিত, সেগুলোর মাঝখানে অন্য কোনো কাজ ছাড়াই (যেমন আপনি
  `_transfer`-এ দেখতে পাচ্ছেন)। এর কারণ হলো স্টেট পরিবর্তনের সময় আপনার একটি অসামঞ্জস্যপূর্ণ স্টেট থাকে। উদাহরণস্বরূপ,
  আপনি প্রেরকের ব্যালেন্স থেকে বিয়োগ করার সময় এবং প্রাপকের ব্যালেন্সে যোগ করার সময়ের মধ্যে
  বাস্তবে যতটা টোকেন থাকা উচিত তার চেয়ে কম টোকেন থাকে। যদি সেগুলোর মধ্যে কোনো ক্রিয়াকলাপ থাকে, বিশেষ করে অন্য কোনো কন্ট্রাক্টে কল করা হয়, তবে এটি সম্ভাব্যভাবে অপব্যবহার করা যেতে পারে।

এখন যেহেতু আপনি দেখেছেন কীভাবে ওপেনজেপেলিন ERC-20 কন্ট্রাক্ট লেখা হয় এবং বিশেষ করে কীভাবে এটিকে
আরও নিরাপদ করা হয়, যান এবং আপনার নিজস্ব নিরাপদ কন্ট্রাক্ট এবং অ্যাপ্লিকেশনগুলো লিখুন।

[আমার আরও কাজের জন্য এখানে দেখুন](https://cryptodocguy.pro/)।
