এড়িয়ে গিয়ে মূল কন্টেন্টে যান
Change page

স্মার্ট কন্ট্র্যাক্টের অ্যানাটমি

পৃষ্ঠাটি সর্বশেষ আপডেট করা হয়েছে: ২৩ ফেব্রুয়ারী, ২০২৬

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

পূর্বশর্ত

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

ডেটা

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

সংগ্রহস্থল

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

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

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

একটি address টাইপ একটি Ethereum ঠিকানা ধারণ করতে পারে যা 20 বাইট বা 160 বিটের সমান। এটি একটি অগ্রগামী 0x সহ হেক্সাডেসিমেল নোটেশনে রিটার্ন করে।

অন্যান্য টাইপের মধ্যে রয়েছে:

  • বুলিয়ান
  • পূর্ণসংখ্যা
  • ফিক্সড পয়েন্ট সংখ্যা
  • নির্দিষ্ট-আকারের বাইট অ্যারে
  • ডাইনামিকভাবে আকারযুক্ত বাইট অ্যারে
  • যৌক্তিক এবং পূর্ণসংখ্যা লিটারেল
  • স্ট্রিং লিটারেল
  • হেক্সাডেসিমেল লিটারেল
  • এনুমস

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

মেমরি

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

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

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

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

উদাহরণ:

Propস্টেট ভেরিয়েবলবিবরণ
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 হিসাবে ডিক্লেয়ার করা হয়নি, তাই এটি কন্ট্রাক্টের স্টেট পরিবর্তন করতে পারে

ভিউ ফাংশন

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

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. ইনলাইন অ্যাসেম্বলি ব্যবহার করা যাতে নির্দিষ্ট অপকোড থাকে।

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

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 পাঠাতে দেয়।

ফাংশন লেখা

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

  • প্যারামিটার ভেরিয়েবল এবং টাইপ (যদি এটি প্যারামিটার গ্রহণ করে)
  • ইন্টারনাল/এক্সটার্নাল ডিক্লেয়ারেশন
  • 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-তে লেখা কিছু উদাহরণ। আপনি যদি কোডটি নিয়ে খেলতে চান, তাহলে আপনি Remixopens in a new tab-এ তাদের সাথে ইন্টারঅ্যাক্ট করতে পারেন।

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

1// সেমান্টিক ভার্শনিং ব্যবহার করে Solidity-এর সংস্করণ নির্দিষ্ট করে।
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// একবার ডেপ্লয় করা হলে, একটি কন্ট্রাক্ট Ethereum ব্লকচেইনের একটি নির্দিষ্ট ঠিকানায় থাকে।
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` একটি ইমেল ঠিকানার সাথে তুলনীয় - এটি Ethereum-এ একটি অ্যাকাউন্ট শনাক্ত করতে ব্যবহৃত হয়।
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 // Ethereum ক্লায়েন্টরা কন্ট্রাক্ট স্টেট পরিবর্তনের প্রতিক্রিয়া জানাতে ইভেন্ট শুনতে পারে।
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, "আপনি মালিক নন।");
38
39 // টোকেনের সর্বোচ্চ পরিমাণ প্রয়োগ করে
40 require(amount < 1e60, "সর্বোচ্চ ইস্যুয়েন্স অতিক্রম করেছে");
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], "অপর্যাপ্ত ব্যালেন্স।");
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 // পিৎজা স্ট্রাক্টের একটি খালি অ্যারে তৈরি করে
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 // স্ট্রিং (নাম) + ঠিকানা (মালিক) থেকে র‍্যান্ডম ইউইন্ট তৈরি করে
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 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/introduction-to-smart-contracts.html#storage-memory-and-the-stack
109 uint256[] memory result = new uint256[](ownerPizzaCount[_owner]);
110 uint256 counter = 0;
111 for (uint256 i = 0; i < pizzas.length; i++) {
112 if (pizzaToOwner[i] == _owner) {
113 result[counter] = i;
114 counter++;
115 }
116 }
117 return result;
118 }
119
120 // পিৎজা এবং মালিকানা অন্য ঠিকানায় স্থানান্তর করে
121 function transferFrom(address _from, address _to, uint256 _pizzaId) public {
122 require(_from != address(0) && _to != address(0), "অবৈধ ঠিকানা।");
123 require(_exists(_pizzaId), "পিৎজা বিদ্যমান নেই।");
124 require(_from != _to, "একই ঠিকানায় স্থানান্তর করা যাবে না।");
125 require(_isApprovedOrOwner(msg.sender, _pizzaId), "ঠিকানাটি অনুমোদিত নয়।");
126
127 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);
128 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);
129 pizzaToOwner[_pizzaId] = _to;
130
131 // ইম্পোর্ট করা IERC721 কন্ট্রাক্টে সংজ্ঞায়িত ইভেন্ট এমিট করে
132 emit Transfer(_from, _to, _pizzaId);
133 _clearApproval(_to, _pizzaId);
134 }
135
136 /**
137 * একটি প্রদত্ত টোকেন আইডির মালিকানা নিরাপদে অন্য ঠিকানায় স্থানান্তর করে
138 * যদি টার্গেট ঠিকানা একটি কন্ট্রাক্ট হয়, তবে এটি অবশ্যই `onERC721Received` প্রয়োগ করবে,
139 * যা একটি নিরাপদ স্থানান্তরের উপর কল করা হয়, এবং ম্যাজিক মান রিটার্ন করে
140 * `bytes4(keccak256(\"onERC721Received(address,address,uint256,bytes)\"))`;
141 * অন্যথায়, স্থানান্তরটি ফিরিয়ে দেওয়া হয়।
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 */
157 function safeTransferFrom(
158 address from,
159 address to,
160 uint256 pizzaId,
161 bytes memory _data
162 ) public {
163 this.transferFrom(from, to, pizzaId);
164 require(_checkOnERC721Received(from, to, pizzaId, _data), "অবশ্যই onERC721Received প্রয়োগ করতে হবে।");
165 }
166
167 /**
168 * একটি টার্গেট ঠিকানায় `onERC721Received`-কে আহ্বান করার জন্য ইন্টারনাল ফাংশন
169 * যদি টার্গেট ঠিকানা একটি কন্ট্রাক্ট না হয় তবে কলটি এক্সিকিউট করা হয় না
170 */
171 function _checkOnERC721Received(
172 address from,
173 address to,
174 uint256 pizzaId,
175 bytes memory _data
176 ) internal returns (bool) {
177 if (!isContract(to)) {
178 return true;
179 }
180
181 bytes4 retval = IERC721Receiver(to).onERC721Received(
182 msg.sender,
183 from,
184 pizzaId,
185 _data
186 );
187 return (retval == _ERC721_RECEIVED);
188 }
189
190 // একটি পিৎজা বার্ন করে - টোকেন সম্পূর্ণরূপে ধ্বংস করে
191 // `external` ফাংশন মডিফায়ারের অর্থ হল এই ফাংশনটি
192 // কন্ট্রাক্ট ইন্টারফেসের অংশ এবং অন্যান্য কন্ট্রাক্ট এটিকে কল করতে পারে
193 function burn(uint256 _pizzaId) external {
194 require(msg.sender != address(0), "অবৈধ ঠিকানা।");
195 require(_exists(_pizzaId), "পিৎজা বিদ্যমান নেই।");
196 require(_isApprovedOrOwner(msg.sender, _pizzaId), "ঠিকানাটি অনুমোদিত নয়।");
197
198 ownerPizzaCount[msg.sender] = SafeMath.sub(
199 ownerPizzaCount[msg.sender],
200 1
201 );
202 pizzaToOwner[_pizzaId] = address(0);
203 }
204
205 // ঠিকানা দ্বারা পিৎজার সংখ্যা রিটার্ন করে
206 function balanceOf(address _owner) public view returns (uint256 _balance) {
207 return ownerPizzaCount[_owner];
208 }
209
210 // আইডি দ্বারা পাওয়া পিৎজার মালিককে রিটার্ন করে
211 function ownerOf(uint256 _pizzaId) public view returns (address _owner) {
212 address owner = pizzaToOwner[_pizzaId];
213 require(owner != address(0), "অবৈধ পিৎজা আইডি।");
214 return owner;
215 }
216
217 // পিৎজার মালিকানা স্থানান্তরের জন্য অন্য ঠিকানাকে অনুমোদন দেয়
218 function approve(address _to, uint256 _pizzaId) public {
219 require(msg.sender == pizzaToOwner[_pizzaId], "অবশ্যই পিৎজার মালিক হতে হবে।");
220 pizzaApprovals[_pizzaId] = _to;
221 emit Approval(msg.sender, _to, _pizzaId);
222 }
223
224 // নির্দিষ্ট পিৎজার জন্য অনুমোদিত ঠিকানা রিটার্ন করে
225 function getApproved(uint256 _pizzaId)
226 public
227 view
228 returns (address operator)
229 {
230 require(_exists(_pizzaId), "পিৎজা বিদ্যমান নেই।");
231 return pizzaApprovals[_pizzaId];
232 }
233
234 /**
235 * একটি প্রদত্ত টোকেন আইডির বর্তমান অনুমোদন পরিষ্কার করার জন্য প্রাইভেট ফাংশন
236 * যদি প্রদত্ত ঠিকানাটি টোকেনের মালিক না হয় তবে ফিরিয়ে দেয়
237 */
238 function _clearApproval(address owner, uint256 _pizzaId) private {
239 require(pizzaToOwner[_pizzaId] == owner, "অবশ্যই পিৎজার মালিক হতে হবে।");
240 require(_exists(_pizzaId), "পিৎজা বিদ্যমান নেই।");
241 if (pizzaApprovals[_pizzaId] != address(0)) {
242 pizzaApprovals[_pizzaId] = address(0);
243 }
244 }
245
246 /*
247 * একটি প্রদত্ত অপারেটরের অনুমোদন সেট বা আনসেট করে
248 * একজন অপারেটর প্রেরকের পক্ষ থেকে তার সমস্ত টোকেন স্থানান্তর করার অনুমতি পায়
249 */
250 function setApprovalForAll(address to, bool approved) public {
251 require(to != msg.sender, "নিজের ঠিকানা অনুমোদন করা যাবে না");
252 operatorApprovals[msg.sender][to] = approved;
253 emit ApprovalForAll(msg.sender, to, approved);
254 }
255
256 // একটি প্রদত্ত মালিক দ্বারা একজন অপারেটর অনুমোদিত কিনা তা বলে
257 function isApprovedForAll(address owner, address operator)
258 public
259 view
260 returns (bool)
261 {
262 return operatorApprovals[owner][operator];
263 }
264
265 // পিৎজার মালিকানা নেয় - শুধুমাত্র অনুমোদিত ব্যবহারকারীদের জন্য
266 function takeOwnership(uint256 _pizzaId) public {
267 require(_isApprovedOrOwner(msg.sender, _pizzaId), "ঠিকানাটি অনুমোদিত নয়।");
268 address owner = this.ownerOf(_pizzaId);
269 this.transferFrom(owner, msg.sender, _pizzaId);
270 }
271
272 // পিৎজা বিদ্যমান কিনা তা পরীক্ষা করে
273 function _exists(uint256 pizzaId) internal view returns (bool) {
274 address owner = pizzaToOwner[pizzaId];
275 return owner != address(0);
276 }
277
278 // ঠিকানাটি মালিক বা পিৎজা স্থানান্তরের জন্য অনুমোদিত কিনা তা পরীক্ষা করে
279 function _isApprovedOrOwner(address spender, uint256 pizzaId)
280 internal
281 view
282 returns (bool)
283 {
284 address owner = pizzaToOwner[pizzaId];
285 // solium চেক অক্ষম করুন কারণ
286 // https://github.com/duaraghav8/Solium/issues/175
287 // solium-disable-next-line operator-whitespace
288 return (spender == owner ||
289 this.getApproved(pizzaId) == spender ||
290 this.isApprovedForAll(owner, spender));
291 }
292
293 // পিৎজা অনন্য এবং এখনও বিদ্যমান নেই কিনা তা পরীক্ষা করুন
294 modifier isUnique(string memory _name, uint256 _dna) {
295 bool result = true;
296 for (uint256 i = 0; i < pizzas.length; i++) {
297 if (
298 keccak256(abi.encodePacked(pizzas[i].name)) ==
299 keccak256(abi.encodePacked(_name)) &&
300 pizzas[i].dna == _dna
301 ) {
302 result = false;
303 }
304 }
305 require(result, "এই নামের পিৎজা ইতিমধ্যে বিদ্যমান।");
306 _;
307 }
308
309 // টার্গেট ঠিকানাটি একটি কন্ট্রাক্ট কিনা তা রিটার্ন করে
310 function isContract(address account) internal view returns (bool) {
311 uint256 size;
312 // বর্তমানে একটি ঠিকানায় একটি কন্ট্রাক্ট আছে কিনা তা পরীক্ষা করার জন্য এর থেকে ভালো কোনো উপায় নেই
313 // সেই ঠিকানার কোডের আকার পরীক্ষা করা ছাড়া।
314 // এটি কীভাবে কাজ করে সে সম্পর্কে আরও জানতে দেখুন https://ethereum.stackexchange.com/a/14016/36603
315 // ।
316 // TODO Serenity রিলিজের আগে এটি আবার পরীক্ষা করুন, কারণ তখন সমস্ত ঠিকানা
317 // কন্ট্রাক্ট হবে।
318 // solium-disable-next-line security/no-inline-assembly
319 assembly {
320 size := extcodesize(account)
321 }
322 return size > 0;
323 }
324}
সবকটি দেখুন

আরও পড়ুন

স্মার্ট কন্ট্র্যাক্টগুলির একটি আরো সম্পূর্ণ ওভারভিউর জন্য Solidity এবং Vyper-এর ডকুমেন্টেশন দেখুন:

এই প্রবন্ধটা কি সহায়ক ছিল?