মূল কন্টেন্টে যান
Change page

স্মার্ট কন্ট্রাক্টের গঠন

পেজ সর্বশেষ আপডেট: ২৩ ফেব্রুয়ারী, ২০২৬

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

পূর্বশর্ত

প্রথমে নিশ্চিত করুন যে আপনি স্মার্ট কন্ট্রাক্ট সম্পর্কে পড়েছেন। এই ডকুমেন্টটি ধরে নেয় যে আপনি ইতিমধ্যেই JavaScript বা Python-এর মতো প্রোগ্রামিং ভাষার সাথে পরিচিত।

ডেটা

যেকোনো কন্ট্রাক্ট ডেটাকে অবশ্যই একটি লোকেশনে অ্যাসাইন করতে হবে: হয় storage অথবা memory-তে। একটি স্মার্ট কন্ট্রাক্টে স্টোরেজ পরিবর্তন করা ব্যয়বহুল, তাই আপনার ডেটা কোথায় থাকা উচিত তা বিবেচনা করা প্রয়োজন।

স্টোরেজ

স্থায়ী ডেটাকে স্টোরেজ বলা হয় এবং এটি স্টেট ভেরিয়েবল দ্বারা উপস্থাপন করা হয়। এই মানগুলো ব্লকচেইন-এ স্থায়ীভাবে সংরক্ষিত হয়। আপনাকে এর ধরন (type) ঘোষণা করতে হবে যাতে কম্পাইল করার সময় কন্ট্রাক্টটি ট্র্যাক করতে পারে যে ব্লকচেইন-এ এর কতটুকু স্টোরেজ প্রয়োজন।

1// সলিডিটি উদাহরণ
2contract SimpleStorage {
3 uint storedData; // স্টেট ভেরিয়েবল
4 // ...
5}
1# ভাইপার উদাহরণ
2storedData: int128

আপনি যদি ইতিমধ্যেই অবজেক্ট-ওরিয়েন্টেড ভাষায় প্রোগ্রামিং করে থাকেন, তবে আপনি সম্ভবত বেশিরভাগ ধরনের (types) সাথেই পরিচিত হবেন। তবে, আপনি যদি Ethereum ডেভেলপমেন্টে নতুন হয়ে থাকেন, তাহলে address আপনার কাছে নতুন মনে হতে পারে।

একটি address টাইপ একটি ইথেরিয়াম এডড্রেস ধারণ করতে পারে যা 20 বাইট বা 160 বিটের সমান। এটি 0x দিয়ে শুরু হওয়া হেক্সাডেসিমাল নোটেশনে রিটার্ন করে।

অন্যান্য টাইপগুলোর মধ্যে রয়েছে:

  • বুলিয়ান (boolean)
  • ইন্টিজার (integer)
  • ফিক্সড পয়েন্ট নাম্বার (fixed point numbers)
  • ফিক্সড-সাইজ বাইট অ্যারে (fixed-size byte arrays)
  • ডায়নামিকালি সাইজড বাইট অ্যারে (dynamically sized byte arrays)
  • র‍্যাশনাল এবং ইন্টিজার লিটারেল (rational and integer literals)
  • স্ট্রিং লিটারেল (string literals)
  • হেক্সাডেসিমাল লিটারেল (hexadecimal literals)
  • এনাম (enums)

আরও ব্যাখ্যার জন্য, ডক্সগুলো দেখুন:

মেমরি

যেসব মান শুধুমাত্র একটি কন্ট্রাক্ট ফাংশন এক্সিকিউট হওয়ার সময়কালের জন্য সংরক্ষিত থাকে, সেগুলোকে মেমরি ভেরিয়েবল বলা হয়। যেহেতু এগুলো ব্লকচেইন-এ স্থায়ীভাবে সংরক্ষিত হয় না, তাই এগুলো ব্যবহার করা অনেক সস্তা।

ইভিএম (EVM) কীভাবে ডেটা সংরক্ষণ করে (স্টোরেজ, মেমরি এবং স্ট্যাক) সে সম্পর্কে Solidity ডক্স (opens in a new tab)-এ আরও জানুন।

এনভায়রনমেন্ট ভেরিয়েবল

আপনার কন্ট্রাক্টে সংজ্ঞায়িত ভেরিয়েবলগুলো ছাড়াও, কিছু বিশেষ গ্লোবাল ভেরিয়েবল রয়েছে। এগুলো মূলত ব্লকচেইন বা বর্তমান লেনদেন সম্পর্কে তথ্য প্রদান করতে ব্যবহৃত হয়।

উদাহরণ:

প্রপার্টিস্টেট ভেরিয়েবলবিবরণ
block.timestampuint256বর্তমান ব্লক এপোক টাইমস্ট্যাম্প
msg.senderaddressমেসেজ প্রেরক (বর্তমান কল)

ফাংশন

সহজ কথায়, ফাংশনগুলো আগত লেনদেন-এর প্রতিক্রিয়ায় তথ্য পেতে বা সেট করতে পারে।

দুই ধরনের ফাংশন কল রয়েছে:

  • internal – এগুলো কোনো EVM কল তৈরি করে না
    • ইন্টারনাল ফাংশন এবং স্টেট ভেরিয়েবলগুলো শুধুমাত্র অভ্যন্তরীণভাবে অ্যাক্সেস করা যায় (অর্থাৎ, বর্তমান কন্ট্রাক্ট বা এটি থেকে উদ্ভূত কন্ট্রাক্টগুলোর ভেতর থেকে)
  • external – এগুলো একটি EVM কল তৈরি করে
    • এক্সটার্নাল ফাংশনগুলো কন্ট্রাক্ট ইন্টারফেসের অংশ, যার মানে এগুলো অন্যান্য কন্ট্রাক্ট থেকে এবং লেনদেন-এর মাধ্যমে কল করা যেতে পারে। একটি এক্সটার্নাল ফাংশন f অভ্যন্তরীণভাবে কল করা যায় না (অর্থাৎ, f() কাজ করে না, তবে this.f() কাজ করে)।

এগুলো public বা private ও হতে পারে

  • public ফাংশনগুলো কন্ট্রাক্টের ভেতর থেকে অভ্যন্তরীণভাবে বা মেসেজের মাধ্যমে বাহ্যিকভাবে কল করা যেতে পারে
  • private ফাংশনগুলো শুধুমাত্র সেই কন্ট্রাক্টের জন্যই দৃশ্যমান যেখানে সেগুলো সংজ্ঞায়িত করা হয়েছে এবং উদ্ভূত কন্ট্রাক্টগুলোতে নয়

ফাংশন এবং স্টেট ভেরিয়েবল উভয়কেই পাবলিক বা প্রাইভেট করা যেতে পারে

একটি কন্ট্রাক্টে স্টেট ভেরিয়েবল আপডেট করার জন্য এখানে একটি ফাংশন দেওয়া হলো:

1// সলিডিটি উদাহরণ
2function update_name(string value) public {
3 dapp_name = value;
4}
  • string টাইপের প্যারামিটার value ফাংশনে পাস করা হয়েছে: update_name
  • এটি public হিসেবে ঘোষণা করা হয়েছে, যার মানে যে কেউ এটি অ্যাক্সেস করতে পারে
  • এটি view হিসেবে ঘোষণা করা হয়নি, তাই এটি কন্ট্রাক্ট স্টেট পরিবর্তন করতে পারে

ভিউ ফাংশন

এই ফাংশনগুলো কন্ট্রাক্টের ডেটার স্টেট পরিবর্তন না করার প্রতিশ্রুতি দেয়। সাধারণ উদাহরণ হলো "গেটার" (getter) ফাংশন – উদাহরণস্বরূপ, আপনি কোনো ব্যবহারকারীর ব্যালেন্স জানতে এটি ব্যবহার করতে পারেন।

1// সলিডিটি উদাহরণ
2function balanceOf(address _owner) public view returns (uint256 _balance) {
3 return ownerPizzaCount[_owner];
4}
1dappName: public(string)
2
3@view
4@public
5def readName() -> string:
6 return dappName

স্টেট পরিবর্তন হিসেবে যা বিবেচনা করা হয়:

  1. স্টেট ভেরিয়েবলে লেখা।
  2. ইভেন্ট এমিট করা (opens in a new tab)
  3. অন্যান্য কন্ট্রাক্ট তৈরি করা (opens in a new tab)
  4. selfdestruct ব্যবহার করা।
  5. কলের মাধ্যমে ইথার পাঠানো।
  6. view বা pure হিসেবে চিহ্নিত নয় এমন কোনো ফাংশন কল করা।
  7. লো-লেভেল কল ব্যবহার করা।
  8. নির্দিষ্ট অপকোড (opcodes) ধারণকারী ইনলাইন অ্যাসেম্বলি ব্যবহার করা।

কনস্ট্রাক্টর ফাংশন

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

1// সলিডিটি উদাহরণ
2// কন্ট্রাক্টের ডেটা ইনিশিয়ালাইজ করে, `owner` সেট করে
3// কন্ট্রাক্ট তৈরি কারীর ঠিকানায়।
4constructor() public {
5 // সব স্মার্ট কন্ট্রাক্ট এর ফাংশনগুলো ট্রিগার করার জন্য এক্সটার্নাল ট্রানজেকশনের ওপর নির্ভর করে।
6 // `msg` হলো একটি গ্লোবাল ভেরিয়েবল যা প্রদত্ত ট্রানজেকশনের প্রাসঙ্গিক ডেটা ধারণ করে,
7 // যেমন প্রেরকের ঠিকানা এবং ট্রানজেকশনে অন্তর্ভুক্ত ETH এর পরিমাণ।
8 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
9 owner = msg.sender;
10}
সব দেখান
1# ভাইপার উদাহরণ
2
3@external
4def __init__(_beneficiary: address, _bidding_time: uint256):
5 self.beneficiary = _beneficiary
6 self.auctionStart = block.timestamp
7 self.auctionEnd = self.auctionStart + _bidding_time

বিল্ট-ইন ফাংশন

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

  • address.send() – Solidity
  • send(address) – Vyper

এগুলো কন্ট্রাক্টগুলোকে অন্যান্য একাউন্ট-এ ETH পাঠানোর অনুমতি দেয়।

ফাংশন লেখা

আপনার ফাংশনের জন্য প্রয়োজন:

  • প্যারামিটার ভেরিয়েবল এবং টাইপ (যদি এটি প্যারামিটার গ্রহণ করে)
  • internal/external এর ঘোষণা
  • pure/view/payable এর ঘোষণা
  • রিটার্ন টাইপ (যদি এটি কোনো মান রিটার্ন করে)
1pragma solidity >=0.4.0 <=0.6.0;
2
3contract ExampleDapp {
4 string dapp_name; // স্টেট ভেরিয়েবল
5
6 // কন্ট্রাক্ট ডিপ্লয় করার সময় কল করা হয় এবং মান ইনিশিয়ালাইজ করে
7 constructor() public {
8 dapp_name = "My Example dapp";
9 }
10
11 // গেট ফাংশন
12 function read_name() public view returns(string) {
13 return dapp_name;
14 }
15
16 // সেট ফাংশন
17 function update_name(string value) public {
18 dapp_name = value;
19 }
20}
সব দেখান

একটি সম্পূর্ণ কন্ট্রাক্ট দেখতে অনেকটা এরকম হতে পারে। এখানে constructor ফাংশনটি dapp_name ভেরিয়েবলের জন্য একটি প্রাথমিক মান প্রদান করে।

ইভেন্ট এবং লগ

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

টীকাযুক্ত উদাহরণ

এগুলো Solidity-তে লেখা কিছু উদাহরণ। আপনি যদি কোড নিয়ে কাজ করতে চান, তবে আপনি Remix (opens in a new tab)-এ সেগুলোর সাথে ইন্টারঅ্যাক্ট করতে পারেন।

হ্যালো ওয়ার্ল্ড

1// সিমেন্টিক ভার্সনিং ব্যবহার করে সলিডিটির ভার্সন নির্দিষ্ট করে।
2// আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma
3pragma solidity ^0.5.10;
4
5// `HelloWorld` নামের একটি কন্ট্রাক্ট ডিফাইন করে।
6// একটি কন্ট্রাক্ট হলো ফাংশন এবং ডেটার (এর স্টেট) একটি সংগ্রহ।
7// একবার ডিপ্লয় করা হলে, একটি কন্ট্রাক্ট ইথেরিয়াম ব্লকচেইনের একটি নির্দিষ্ট ঠিকানায় অবস্থান করে।
8// আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html
9contract HelloWorld {
10
11 // `string` টাইপের একটি স্টেট ভেরিয়েবল `message` ডিক্লেয়ার করে।
12 // স্টেট ভেরিয়েবল হলো এমন ভেরিয়েবল যার মান কন্ট্রাক্ট স্টোরেজে স্থায়ীভাবে সংরক্ষিত থাকে।
13 // `public` কিওয়ার্ড ভেরিয়েবলগুলোকে কন্ট্রাক্টের বাইরে থেকে অ্যাক্সেসযোগ্য করে তোলে
14 // এবং এমন একটি ফাংশন তৈরি করে যা অন্য কন্ট্রাক্ট বা ক্লায়েন্টরা মান অ্যাক্সেস করতে কল করতে পারে।
15 string public message;
16
17 // অনেক ক্লাস-ভিত্তিক অবজেক্ট-ওরিয়েন্টেড ভাষার মতো, একটি কনস্ট্রাক্টর হলো
18 // একটি বিশেষ ফাংশন যা শুধুমাত্র কন্ট্রাক্ট তৈরির সময় এক্সিকিউট হয়।
19 // কনস্ট্রাক্টরগুলো কন্ট্রাক্টের ডেটা ইনিশিয়ালাইজ করতে ব্যবহৃত হয়।
20 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors
21 constructor(string memory initMessage) public {
22 // একটি স্ট্রিং আর্গুমেন্ট `initMessage` গ্রহণ করে এবং মান সেট করে
23 // কন্ট্রাক্টের `message` স্টোরেজ ভেরিয়েবলে)।
24 message = initMessage;
25 }
26
27 // একটি পাবলিক ফাংশন যা একটি স্ট্রিং আর্গুমেন্ট গ্রহণ করে
28 // এবং `message` স্টোরেজ ভেরিয়েবল আপডেট করে।
29 function update(string memory newMessage) public {
30 message = newMessage;
31 }
32}
সব দেখান

টোকেন

1pragma solidity ^0.5.10;
2
3contract Token {
4 // একটি `address` ইমেইল ঠিকানার সাথে তুলনীয় - এটি ইথেরিয়ামে একটি অ্যাকাউন্ট শনাক্ত করতে ব্যবহৃত হয়।
5 // ঠিকানাগুলো একটি স্মার্ট কন্ট্রাক্ট বা এক্সটার্নাল (ব্যবহারকারী) অ্যাকাউন্টকে উপস্থাপন করতে পারে।
6 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/types.html#address
7 address public owner;
8
9 // একটি `mapping` মূলত একটি হ্যাস টেবিল ডেটা স্ট্রাকচার।
10 // এই `mapping` একটি ঠিকানায় (টোকেন হোল্ডার) একটি আনসাইনড ইন্টিজার (টোকেন ব্যালেন্স) অ্যাসাইন করে।
11 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types
12 mapping (address => uint) public balances;
13
14 // ইভেন্টগুলো ব্লকচেইনে অ্যাক্টিভিটি লগ করার অনুমতি দেয়।
15 // কন্ট্রাক্ট স্টেট পরিবর্তনের প্রতিক্রিয়া জানাতে ইথেরিয়াম ক্লায়েন্টরা ইভেন্টগুলো শুনতে পারে।
16 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events
17 event Transfer(address from, address to, uint amount);
18
19 // কন্ট্রাক্টের ডেটা ইনিশিয়ালাইজ করে, `owner` সেট করে
20 // কন্ট্রাক্ট তৈরি কারীর ঠিকানায়।
21 constructor() public {
22 // সব স্মার্ট কন্ট্রাক্ট এর ফাংশনগুলো ট্রিগার করার জন্য এক্সটার্নাল ট্রানজেকশনের ওপর নির্ভর করে।
23 // `msg` হলো একটি গ্লোবাল ভেরিয়েবল যা প্রদত্ত ট্রানজেকশনের প্রাসঙ্গিক ডেটা ধারণ করে,
24 // যেমন প্রেরকের ঠিকানা এবং ট্রানজেকশনে অন্তর্ভুক্ত ETH এর পরিমাণ।
25 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
26 owner = msg.sender;
27 }
28
29 // কিছু পরিমাণ নতুন টোকেন তৈরি করে এবং সেগুলো একটি ঠিকানায় পাঠায়।
30 function mint(address receiver, uint amount) public {
31 // `require` হলো একটি কন্ট্রোল স্ট্রাকচার যা নির্দিষ্ট শর্ত প্রয়োগ করতে ব্যবহৃত হয়।
32 // যদি একটি `require` স্টেটমেন্ট `false` হয়, তবে একটি এক্সেপশন ট্রিগার হয়,
33 // যা বর্তমান কলের সময় স্টেটে করা সমস্ত পরিবর্তন রিভার্ট করে।
34 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
35
36 // শুধুমাত্র কন্ট্রাক্ট ওনার এই ফাংশনটি কল করতে পারেন
37 require(msg.sender == owner, "You are not the owner.");
38
39 // টোকেনের সর্বোচ্চ পরিমাণ প্রয়োগ করে
40 require(amount < 1e60, "Maximum issuance exceeded");
41
42 // `receiver` এর ব্যালেন্স `amount` পরিমাণ বাড়ায়
43 balances[receiver] += amount;
44 }
45
46 // যেকোনো কলার থেকে একটি ঠিকানায় কিছু পরিমাণ বিদ্যমান টোকেন পাঠায়।
47 function transfer(address receiver, uint amount) public {
48 // প্রেরকের কাছে পাঠানোর জন্য পর্যাপ্ত টোকেন থাকতে হবে
49 require(amount <= balances[msg.sender], "Insufficient balance.");
50
51 // দুটি ঠিকানার টোকেন ব্যালেন্স অ্যাডজাস্ট করে
52 balances[msg.sender] -= amount;
53 balances[receiver] += amount;
54
55 // আগে ডিফাইন করা ইভেন্ট এমিট করে
56 emit Transfer(msg.sender, receiver, amount);
57 }
58}
সব দেখান

ইউনিক ডিজিটাল অ্যাসেট

1pragma solidity ^0.5.10;
2
3// অন্যান্য ফাইল থেকে বর্তমান কন্ট্রাক্টে সিম্বল ইমপোর্ট করে।
4// এই ক্ষেত্রে, OpenZeppelin থেকে হেল্পার কন্ট্রাক্টের একটি সিরিজ।
5// আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#importing-other-source-files
6
7import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol";
8import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
9import "../node_modules/@openzeppelin/contracts/introspection/ERC165.sol";
10import "../node_modules/@openzeppelin/contracts/math/SafeMath.sol";
11
12// `is` কিওয়ার্ডটি এক্সটার্নাল কন্ট্রাক্ট থেকে ফাংশন এবং কিওয়ার্ড ইনহেরিট করতে ব্যবহৃত হয়।
13// এই ক্ষেত্রে, `CryptoPizza` `IERC721` এবং `ERC165` কন্ট্রাক্ট থেকে ইনহেরিট করে।
14// আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#inheritance
15contract CryptoPizza is IERC721, ERC165 {
16 // নিরাপদে গাণিতিক অপারেশন করতে OpenZeppelin এর SafeMath লাইব্রেরি ব্যবহার করে।
17 // আরও জানুন: https://docs.openzeppelin.com/contracts/2.x/api/math#SafeMath
18 using SafeMath for uint256;
19
20 // সলিডিটিতে কনস্ট্যান্ট স্টেট ভেরিয়েবলগুলো অন্যান্য ভাষার মতোই
21 // তবে আপনাকে এমন একটি এক্সপ্রেশন থেকে অ্যাসাইন করতে হবে যা কম্পাইল টাইমে কনস্ট্যান্ট থাকে।
22 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constant-state-variables
23 uint256 constant dnaDigits = 10;
24 uint256 constant dnaModulus = 10 ** dnaDigits;
25 bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
26
27 // স্ট্রাক্ট টাইপ আপনাকে আপনার নিজস্ব টাইপ ডিফাইন করতে দেয়
28 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/types.html#structs
29 struct Pizza {
30 string name;
31 uint256 dna;
32 }
33
34 // Pizza স্ট্রাক্টের একটি খালি অ্যারে তৈরি করে
35 Pizza[] public pizzas;
36
37 // পিজা আইডি থেকে এর ওনারের ঠিকানায় ম্যাপিং
38 mapping(uint256 => address) public pizzaToOwner;
39
40 // ওনারের ঠিকানা থেকে মালিকানাধীন টোকেনের সংখ্যায় ম্যাপিং
41 mapping(address => uint256) public ownerPizzaCount;
42
43 // টোকেন আইডি থেকে অনুমোদিত ঠিকানায় ম্যাপিং
44 mapping(uint256 => address) pizzaApprovals;
45
46 // আপনি ম্যাপিং নেস্ট করতে পারেন, এই উদাহরণটি ওনার থেকে অপারেটর অ্যাপ্রুভালে ম্যাপ করে
47 mapping(address => mapping(address => bool)) private operatorApprovals;
48
49 // স্ট্রিং (নাম) এবং ডিএনএ থেকে একটি র‍্যান্ডম পিজা তৈরি করার ইন্টারনাল ফাংশন
50 function _createPizza(string memory _name, uint256 _dna)
51 // `internal` কিওয়ার্ডের মানে হলো এই ফাংশনটি শুধুমাত্র দৃশ্যমান
52 // এই কন্ট্রাক্ট এবং এই কন্ট্রাক্ট থেকে ডিরাইভ করা কন্ট্রাক্টগুলোর মধ্যে
53 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#visibility-and-getters
54 internal
55 // `isUnique` হলো একটি ফাংশন মডিফায়ার যা পিজাটি আগে থেকেই আছে কিনা তা চেক করে
56 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers
57 isUnique(_name, _dna)
58 {
59 // পিজাদের অ্যারেতে পিজা যোগ করে এবং আইডি পায়
60 uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1);
61
62 // পিজার ওনার বর্তমান ব্যবহারকারীর সমান কিনা তা চেক করে
63 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
64
65 // খেয়াল রাখবেন যে address(0) হলো জিরো অ্যাড্রেস,
66 // যা নির্দেশ করে যে pizza[id] এখনও কোনো নির্দিষ্ট ব্যবহারকারীকে বরাদ্দ করা হয়নি।
67
68 assert(pizzaToOwner[id] == address(0));
69
70 // পিজাকে ওনারের সাথে ম্যাপ করে
71 pizzaToOwner[id] = msg.sender;
72 ownerPizzaCount[msg.sender] = SafeMath.add(
73 ownerPizzaCount[msg.sender],
74 1
75 );
76 }
77
78 // স্ট্রিং (নাম) থেকে একটি র‍্যান্ডম পিজা তৈরি করে
79 function createRandomPizza(string memory _name) public {
80 uint256 randDna = generateRandomDna(_name, msg.sender);
81 _createPizza(_name, randDna);
82 }
83
84 // স্ট্রিং (নাম) এবং ওনারের (তৈরি কারী) ঠিকানা থেকে র‍্যান্ডম ডিএনএ জেনারেট করে
85 function generateRandomDna(string memory _str, address _owner)
86 public
87 // `pure` হিসেবে চিহ্নিত ফাংশনগুলো স্টেট থেকে রিড বা মডিফাই না করার প্রতিশ্রুতি দেয়
88 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions
89 pure
90 returns (uint256)
91 {
92 // স্ট্রিং (নাম) + ঠিকানা (ওনার) থেকে র‍্যান্ডম uint জেনারেট করে
93 uint256 rand = uint256(keccak256(abi.encodePacked(_str))) +
94 uint256(_owner);
95 rand = rand % dnaModulus;
96 return rand;
97 }
98
99 // ওনারের পাওয়া পিজাদের অ্যারে রিটার্ন করে
100 function getPizzasByOwner(address _owner)
101 public
102 // `view` হিসেবে চিহ্নিত ফাংশনগুলো স্টেট মডিফাই না করার প্রতিশ্রুতি দেয়
103 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions
104 view
105 returns (uint256[] memory)
106 {
107 // মান সংরক্ষণ করতে `memory` স্টোরেজ লোকেশন ব্যবহার করে শুধুমাত্র
108 // এই ফাংশন কলের লাইফসাইকেলের জন্য।
109 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/introduction-to-smart-contracts.html#storage-memory-and-the-stack
110 uint256[] memory result = new uint256[](ownerPizzaCount[_owner]);
111 uint256 counter = 0;
112 for (uint256 i = 0; i < pizzas.length; i++) {
113 if (pizzaToOwner[i] == _owner) {
114 result[counter] = i;
115 counter++;
116 }
117 }
118 return result;
119 }
120
121 // অন্য ঠিকানায় পিজা এবং মালিকানা ট্রান্সফার করে
122 function transferFrom(address _from, address _to, uint256 _pizzaId) public {
123 require(_from != address(0) && _to != address(0), "Invalid address.");
124 require(_exists(_pizzaId), "Pizza does not exist.");
125 require(_from != _to, "Cannot transfer to the same address.");
126 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");
127
128 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);
129 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);
130 pizzaToOwner[_pizzaId] = _to;
131
132 // ইমপোর্ট করা IERC721 কন্ট্রাক্টে ডিফাইন করা ইভেন্ট এমিট করে
133 emit Transfer(_from, _to, _pizzaId);
134 _clearApproval(_to, _pizzaId);
135 }
136
137 /* *
138 * একটি প্রদত্ত টোকেন আইডির মালিকানা নিরাপদে অন্য ঠিকানায় ট্রান্সফার করে
139 * যদি টার্গেট ঠিকানাটি একটি কন্ট্রাক্ট হয়, তবে এটিকে অবশ্যই `onERC721Received` ইমপ্লিমেন্ট করতে হবে,
140 * যা একটি নিরাপদ ট্রান্সফারের সময় কল করা হয়, এবং ম্যাজিক ভ্যালু রিটার্ন করে
141 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;
142 * অন্যথায়, ট্রান্সফারটি রিভার্ট করা হয়। */
143 function safeTransferFrom(address from, address to, uint256 pizzaId)
144 public
145 {
146 // solium-disable-next-line arg-overflow
147 this.safeTransferFrom(from, to, pizzaId, "");
148 }
149
150 /* *
151 * একটি প্রদত্ত টোকেন আইডির মালিকানা নিরাপদে অন্য ঠিকানায় ট্রান্সফার করে
152 * যদি টার্গেট ঠিকানাটি একটি কন্ট্রাক্ট হয়, তবে এটিকে অবশ্যই `onERC721Received` ইমপ্লিমেন্ট করতে হবে,
153 * যা একটি নিরাপদ ট্রান্সফারের সময় কল করা হয়, এবং ম্যাজিক ভ্যালু রিটার্ন করে
154 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;
155 * অন্যথায়, ট্রান্সফারটি রিভার্ট করা হয়। */
156 function safeTransferFrom(
157 address from,
158 address to,
159 uint256 pizzaId,
160 bytes memory _data
161 ) public {
162 this.transferFrom(from, to, pizzaId);
163 require(_checkOnERC721Received(from, to, pizzaId, _data), "Must implement onERC721Received.");
164 }
165
166 /* *
167 * একটি টার্গেট ঠিকানায় `onERC721Received` ইনভোক করার ইন্টারনাল ফাংশন
168 * টার্গেট ঠিকানাটি কন্ট্রাক্ট না হলে কলটি এক্সিকিউট হয় না */
169 function _checkOnERC721Received(
170 address from,
171 address to,
172 uint256 pizzaId,
173 bytes memory _data
174 ) internal returns (bool) {
175 if (!isContract(to)) {
176 return true;
177 }
178
179 bytes4 retval = IERC721Receiver(to).onERC721Received(
180 msg.sender,
181 from,
182 pizzaId,
183 _data
184 );
185 return (retval == _ERC721_RECEIVED);
186 }
187
188 // একটি পিজা বার্ন করে - টোকেনটি সম্পূর্ণ ধ্বংস করে
189 // `external` ফাংশন মডিফায়ারের মানে হলো এই ফাংশনটি
190 // কন্ট্রাক্ট ইন্টারফেসের অংশ এবং অন্যান্য কন্ট্রাক্ট এটি কল করতে পারে
191 function burn(uint256 _pizzaId) external {
192 require(msg.sender != address(0), "Invalid address.");
193 require(_exists(_pizzaId), "Pizza does not exist.");
194 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");
195
196 ownerPizzaCount[msg.sender] = SafeMath.sub(
197 ownerPizzaCount[msg.sender],
198 1
199 );
200 pizzaToOwner[_pizzaId] = address(0);
201 }
202
203 // ঠিকানা অনুযায়ী পিজার সংখ্যা রিটার্ন করে
204 function balanceOf(address _owner) public view returns (uint256 _balance) {
205 return ownerPizzaCount[_owner];
206 }
207
208 // আইডি দ্বারা পাওয়া পিজার ওনার রিটার্ন করে
209 function ownerOf(uint256 _pizzaId) public view returns (address _owner) {
210 address owner = pizzaToOwner[_pizzaId];
211 require(owner != address(0), "Invalid Pizza ID.");
212 return owner;
213 }
214
215 // পিজার মালিকানা ট্রান্সফার করতে অন্য ঠিকানাকে অনুমোদন দেয়
216 function approve(address _to, uint256 _pizzaId) public {
217 require(msg.sender == pizzaToOwner[_pizzaId], "Must be the Pizza owner.");
218 pizzaApprovals[_pizzaId] = _to;
219 emit Approval(msg.sender, _to, _pizzaId);
220 }
221
222 // নির্দিষ্ট পিজার জন্য অনুমোদিত ঠিকানা রিটার্ন করে
223 function getApproved(uint256 _pizzaId)
224 public
225 view
226 returns (address operator)
227 {
228 require(_exists(_pizzaId), "Pizza does not exist.");
229 return pizzaApprovals[_pizzaId];
230 }
231
232 /* *
233 * একটি প্রদত্ত টোকেন আইডির বর্তমান অনুমোদন ক্লিয়ার করার প্রাইভেট ফাংশন
234 * প্রদত্ত ঠিকানাটি টোকেনের প্রকৃত ওনার না হলে রিভার্ট করে */
235 function _clearApproval(address owner, uint256 _pizzaId) private {
236 require(pizzaToOwner[_pizzaId] == owner, "Must be pizza owner.");
237 require(_exists(_pizzaId), "Pizza does not exist.");
238 if (pizzaApprovals[_pizzaId] != address(0)) {
239 pizzaApprovals[_pizzaId] = address(0);
240 }
241 }
242
243 /* * একটি প্রদত্ত অপারেটরের অনুমোদন সেট বা আনসেট করে
244 * একজন অপারেটর প্রেরকের পক্ষে তার সমস্ত টোকেন ট্রান্সফার করার অনুমতি পায় */
245 function setApprovalForAll(address to, bool approved) public {
246 require(to != msg.sender, "Cannot approve own address");
247 operatorApprovals[msg.sender][to] = approved;
248 emit ApprovalForAll(msg.sender, to, approved);
249 }
250
251 // একজন অপারেটর একটি প্রদত্ত ওনার দ্বারা অনুমোদিত কিনা তা বলে
252 function isApprovedForAll(address owner, address operator)
253 public
254 view
255 returns (bool)
256 {
257 return operatorApprovals[owner][operator];
258 }
259
260 // পিজার মালিকানা নেয় - শুধুমাত্র অনুমোদিত ব্যবহারকারীদের জন্য
261 function takeOwnership(uint256 _pizzaId) public {
262 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");
263 address owner = this.ownerOf(_pizzaId);
264 this.transferFrom(owner, msg.sender, _pizzaId);
265 }
266
267 // পিজা আছে কিনা তা চেক করে
268 function _exists(uint256 pizzaId) internal view returns (bool) {
269 address owner = pizzaToOwner[pizzaId];
270 return owner != address(0);
271 }
272
273 // ঠিকানাটি ওনার কিনা বা পিজা ট্রান্সফার করার জন্য অনুমোদিত কিনা তা চেক করে
274 function _isApprovedOrOwner(address spender, uint256 pizzaId)
275 internal
276 view
277 returns (bool)
278 {
279 address owner = pizzaToOwner[pizzaId];
280 // solium চেক নিষ্ক্রিয় করুন কারণ
281 // https://github.com/duaraghav8/Solium/issues/175
282 // solium-disable-next-line operator-whitespace
283 return (spender == owner ||
284 this.getApproved(pizzaId) == spender ||
285 this.isApprovedForAll(owner, spender));
286 }
287
288 // পিজাটি ইউনিক কিনা এবং এখনও বিদ্যমান নেই কিনা তা চেক করুন
289 modifier isUnique(string memory _name, uint256 _dna) {
290 bool result = true;
291 for (uint256 i = 0; i < pizzas.length; i++) {
292 if (
293 keccak256(abi.encodePacked(pizzas[i].name)) ==
294 keccak256(abi.encodePacked(_name)) &&
295 pizzas[i].dna == _dna
296 ) {
297 result = false;
298 }
299 }
300 require(result, "Pizza with such name already exists.");
301 _;
302 }
303
304 // টার্গেট ঠিকানাটি একটি কন্ট্রাক্ট কিনা তা রিটার্ন করে
305 function isContract(address account) internal view returns (bool) {
306 uint256 size;
307 // বর্তমানে কোনো ঠিকানায় কন্ট্রাক্ট আছে কিনা তা চেক করার এর চেয়ে ভালো কোনো উপায় নেই
308 // সেই ঠিকানায় কোডের সাইজ চেক করা ছাড়া।
309 // দেখুন https://ethereum.stackexchange.com/a/14016/36603
310 // এটি কীভাবে কাজ করে সে সম্পর্কে আরও বিস্তারিত জানতে।
311 // TODO Serenity রিলিজের আগে এটি আবার চেক করুন, কারণ তখন সমস্ত ঠিকানা হবে
312 // কন্ট্রাক্ট।
313 // solium-disable-next-line security/no-inline-assembly
314 assembly {
315 size := extcodesize(account)
316 }
317 return size > 0;
318 }
319}
সব দেখান

আরও পড়ুন

স্মার্ট কন্ট্রাক্ট সম্পর্কে আরও সম্পূর্ণ ধারণা পেতে Solidity এবং Vyper-এর ডকুমেন্টেশন দেখুন:

এই আর্টিকেলটি কি সহায়ক ছিল?