স্মার্ট কন্ট্র্যাক্টের অ্যানাটমি
পৃষ্ঠাটি সর্বশেষ আপডেট করা হয়েছে: ২৩ ফেব্রুয়ারী, ২০২৬
স্মার্ট কন্ট্র্যাক্ট হল এমন একটি প্রোগ্রাম যা 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.timestamp | uint256 | বর্তমান ব্লক ইপক টাইমস্ট্যাম্প |
msg.sender | address | বার্তার প্রেরক (বর্তমান কল) |
ফাংশন
সবচেয়ে সহজ ভাষায়, ফাংশনগুলি ইনকামিং লেনদেনের প্রতিক্রিয়া হিসাবে তথ্য পেতে বা সেট করতে পারে।
দুই ধরনের ফাংশন কল আছে:
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)23@view4@public5def readName() -> string:6 return dappNameস্টেট পরিবর্তন করা বলতে যা বোঝায়:
- স্টেট ভেরিয়েবলে লেখা।
- ইভেন্ট এমিট করাopens in a new tab।
- অন্যান্য কন্ট্রাক্ট তৈরি করাopens in a new tab।
selfdestructব্যবহার করা।- কলের মাধ্যমে ইথার পাঠানো।
viewবাpureহিসাবে চিহ্নিত নয় এমন কোনো ফাংশন কল করা।- নিম্ন-স্তরের কল ব্যবহার করা।
- ইনলাইন অ্যাসেম্বলি ব্যবহার করা যাতে নির্দিষ্ট অপকোড থাকে।
কনস্ট্রাক্টর ফাংশন
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-properties9 owner = msg.sender;10}সবকটি দেখুন1# ভাইপার উদাহরণ23@external4def __init__(_beneficiary: address, _bidding_time: uint256):5 self.beneficiary = _beneficiary6 self.auctionStart = block.timestamp7 self.auctionEnd = self.auctionStart + _bidding_timeঅন্তর্নির্মিত ফাংশন
আপনার কন্ট্রাক্টে আপনি যে ভেরিয়েবল এবং ফাংশনগুলি সংজ্ঞায়িত করেন সেগুলি ছাড়াও, কিছু বিশেষ অন্তর্নির্মিত ফাংশন রয়েছে। সবচেয়ে সুস্পষ্ট উদাহরণ হল:
address.send()– Soliditysend(address)– Vyper
এগুলি কন্ট্রাক্টগুলিকে অন্য অ্যাকাউন্টে ETH পাঠাতে দেয়।
ফাংশন লেখা
আপনার ফাংশনের প্রয়োজন:
- প্যারামিটার ভেরিয়েবল এবং টাইপ (যদি এটি প্যারামিটার গ্রহণ করে)
- ইন্টারনাল/এক্সটার্নাল ডিক্লেয়ারেশন
- pure/view/payable-এর ডিক্লেয়ারেশন
- রিটার্নস টাইপ (যদি এটি একটি মান রিটার্ন করে)
1pragma solidity >=0.4.0 <=0.6.0;23contract ExampleDapp {4 string dapp_name; // স্টেট ভেরিয়েবল56 // কন্ট্রাক্টটি ডেপ্লয় করার সময় কল করা হয় এবং মানটি ইনিশিয়ালাইজ করে7 constructor() public {8 dapp_name = "My Example dapp";9 }1011 // গেট ফাংশন12 function read_name() public view returns(string) {13 return dapp_name;14 }1516 // সেট ফাংশন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#pragma3pragma solidity ^0.5.10;45// `HelloWorld` নামের একটি কন্ট্রাক্ট সংজ্ঞায়িত করে।6// একটি কন্ট্রাক্ট হল ফাংশন এবং ডেটার (তার স্টেট) একটি সংগ্রহ।7// একবার ডেপ্লয় করা হলে, একটি কন্ট্রাক্ট Ethereum ব্লকচেইনের একটি নির্দিষ্ট ঠিকানায় থাকে।8// আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html9contract HelloWorld {1011 // `string` টাইপের একটি স্টেট ভেরিয়েবল `message` ডিক্লেয়ার করে।12 // স্টেট ভেরিয়েবল হল এমন ভেরিয়েবল যার মান স্থায়ীভাবে কন্ট্রাক্টের সংগ্রহস্থলে সংরক্ষণ করা হয়।13 // `public` কীওয়ার্ডটি একটি কন্ট্রাক্টের বাইরে থেকে ভেরিয়েবলগুলিকে অ্যাক্সেসযোগ্য করে তোলে14 // এবং একটি ফাংশন তৈরি করে যা অন্য কন্ট্রাক্ট বা ক্লায়েন্টরা মান অ্যাক্সেস করার জন্য কল করতে পারে।15 string public message;1617 // অনেক ক্লাস-ভিত্তিক অবজেক্ট-ওরিয়েন্টেড ভাষার মতো, একটি কনস্ট্রাক্টর হল18 // একটি বিশেষ ফাংশন যা শুধুমাত্র কন্ট্রাক্ট তৈরির সময় এক্সিকিউট করা হয়।19 // কনস্ট্রাক্টরগুলি কন্ট্রাক্টের ডেটা ইনিশিয়ালাইজ করতে ব্যবহৃত হয়।20 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors21 constructor(string memory initMessage) public {22 // একটি স্ট্রিং আর্গুমেন্ট `initMessage` গ্রহণ করে এবং মানটি সেট করে23 // কন্ট্রাক্টের `message` সংগ্রহস্থল ভেরিয়েবলে)।24 message = initMessage;25 }2627 // একটি পাবলিক ফাংশন যা একটি স্ট্রিং আর্গুমেন্ট গ্রহণ করে28 // এবং `message` সংগ্রহস্থল ভেরিয়েবল আপডেট করে।29 function update(string memory newMessage) public {30 message = newMessage;31 }32}সবকটি দেখুনটোকেন
1pragma solidity ^0.5.10;23contract Token {4 // একটি `address` একটি ইমেল ঠিকানার সাথে তুলনীয় - এটি Ethereum-এ একটি অ্যাকাউন্ট শনাক্ত করতে ব্যবহৃত হয়।5 // ঠিকানাগুলি একটি স্মার্ট কন্ট্র্যাক্ট বা একটি এক্সটার্নাল (ব্যবহারকারী) অ্যাকাউন্টকে প্রতিনিধিত্ব করতে পারে।6 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/types.html#address7 address public owner;89 // একটি `mapping` মূলত একটি হ্যাস টেবিল ডেটা স্ট্রাকচার।10 // এই `mapping` একটি আনসাইন্ড ইন্টিজার (টোকেন ব্যালেন্স) একটি ঠিকানায় (টোকেন হোল্ডার) বরাদ্দ করে।11 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types12 mapping (address => uint) public balances;1314 // ইভেন্টগুলি ব্লকচেইনে কার্যকলাপ লগ করার অনুমতি দেয়।15 // Ethereum ক্লায়েন্টরা কন্ট্রাক্ট স্টেট পরিবর্তনের প্রতিক্রিয়া জানাতে ইভেন্ট শুনতে পারে।16 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events17 event Transfer(address from, address to, uint amount);1819 // কন্ট্রাক্টের ডেটা ইনিশিয়ালাইজ করে, `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-properties26 owner = msg.sender;27 }2829 // নতুন টোকেনের একটি পরিমাণ তৈরি করে এবং সেগুলিকে একটি ঠিকানায় পাঠায়।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-exceptions3536 // শুধুমাত্র কন্ট্রাক্টের মালিক এই ফাংশনটি কল করতে পারেন37 require(msg.sender == owner, "আপনি মালিক নন।");3839 // টোকেনের সর্বোচ্চ পরিমাণ প্রয়োগ করে40 require(amount < 1e60, "সর্বোচ্চ ইস্যুয়েন্স অতিক্রম করেছে");4142 // `receiver`-এর ব্যালেন্স `amount` দ্বারা বৃদ্ধি করে43 balances[receiver] += amount;44 }4546 // যেকোনো কলার থেকে একটি ঠিকানায় বিদ্যমান টোকেনের একটি পরিমাণ পাঠায়।47 function transfer(address receiver, uint amount) public {48 // প্রেরকের পাঠানোর জন্য যথেষ্ট টোকেন থাকতে হবে49 require(amount <= balances[msg.sender], "অপর্যাপ্ত ব্যালেন্স।");5051 // দুটি ঠিকানার টোকেন ব্যালেন্স সামঞ্জস্য করে52 balances[msg.sender] -= amount;53 balances[receiver] += amount;5455 // পূর্বে সংজ্ঞায়িত ইভেন্ট এমিট করে56 emit Transfer(msg.sender, receiver, amount);57 }58}সবকটি দেখুনঅনন্য ডিজিটাল সম্পদ
1pragma solidity ^0.5.10;23// বর্তমান কন্ট্রাক্টে অন্যান্য ফাইল থেকে প্রতীক ইম্পোর্ট করে।4// এই ক্ষেত্রে, OpenZeppelin থেকে হেল্পার কন্ট্রাক্টের একটি সিরিজ।5// আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#importing-other-source-files67import "../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";1112// `is` কীওয়ার্ডটি এক্সটার্নাল কন্ট্রাক্ট থেকে ফাংশন এবং কীওয়ার্ড উত্তরাধিকার সূত্রে পেতে ব্যবহৃত হয়।13// এই ক্ষেত্রে, `CryptoPizza` `IERC721` এবং `ERC165` কন্ট্রাক্ট থেকে উত্তরাধিকার সূত্রে প্রাপ্ত।14// আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#inheritance15contract CryptoPizza is IERC721, ERC165 {16 // নিরাপদে গাণিতিক ক্রিয়াকলাপ সম্পাদনের জন্য OpenZeppelin-এর SafeMath লাইব্রেরি ব্যবহার করে।17 // আরও জানুন: https://docs.openzeppelin.com/contracts/2.x/api/math#SafeMath18 using SafeMath for uint256;1920 // সলিডিটিতে ধ্রুবক স্টেট ভেরিয়েবলগুলি অন্যান্য ভাষার মতোই21 // কিন্তু আপনাকে অবশ্যই একটি এক্সপ্রেশন থেকে বরাদ্দ করতে হবে যা কম্পাইলের সময় ধ্রুবক।22 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constant-state-variables23 uint256 constant dnaDigits = 10;24 uint256 constant dnaModulus = 10 ** dnaDigits;25 bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;2627 // স্ট্রাক্ট টাইপ আপনাকে আপনার নিজের টাইপ সংজ্ঞায়িত করতে দেয়28 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/types.html#structs29 struct Pizza {30 string name;31 uint256 dna;32 }3334 // পিৎজা স্ট্রাক্টের একটি খালি অ্যারে তৈরি করে35 Pizza[] public pizzas;3637 // পিৎজা আইডি থেকে তার মালিকের ঠিকানায় ম্যাপিং38 mapping(uint256 => address) public pizzaToOwner;3940 // মালিকের ঠিকানা থেকে মালিকানাধীন টোকেনের সংখ্যায় ম্যাপিং41 mapping(address => uint256) public ownerPizzaCount;4243 // টোকেন আইডি থেকে অনুমোদিত ঠিকানায় ম্যাপিং44 mapping(uint256 => address) pizzaApprovals;4546 // আপনি ম্যাপিং নেস্ট করতে পারেন, এই উদাহরণটি অপারেটর অনুমোদনের জন্য মালিককে ম্যাপ করে47 mapping(address => mapping(address => bool)) private operatorApprovals;4849 // স্ট্রিং (নাম) এবং ডিএনএ থেকে একটি র্যান্ডম পিৎজা তৈরি করার জন্য ইন্টারনাল ফাংশন50 function _createPizza(string memory _name, uint256 _dna)51 // `internal` কীওয়ার্ডটির অর্থ হল এই ফাংশনটি শুধুমাত্র দৃশ্যমান52 // এই কন্ট্রাক্ট এবং এই কন্ট্রাক্ট থেকে প্রাপ্ত কন্ট্রাক্টের মধ্যে53 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#visibility-and-getters54 internal55 // `isUnique` একটি ফাংশন মডিফায়ার যা পিৎজা আগে থেকেই বিদ্যমান কিনা তা পরীক্ষা করে56 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers57 isUnique(_name, _dna)58 {59 // পিৎজাকে পিৎজার অ্যারেতে যোগ করে এবং আইডি পায়60 uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1);6162 // পিৎজার মালিক বর্তমান ব্যবহারকারীর সমান কিনা তা পরীক্ষা করে63 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions6465 // মনে রাখবেন যে address(0) হল শূন্য ঠিকানা,66 // যা নির্দেশ করে যে pizza[id] এখনও কোনো নির্দিষ্ট ব্যবহারকারীকে বরাদ্দ করা হয়নি।6768 assert(pizzaToOwner[id] == address(0));6970 // পিৎজাকে মালিকের সাথে ম্যাপ করে71 pizzaToOwner[id] = msg.sender;72 ownerPizzaCount[msg.sender] = SafeMath.add(73 ownerPizzaCount[msg.sender],74 175 );76 }7778 // স্ট্রিং (নাম) থেকে একটি র্যান্ডম পিৎজা তৈরি করে79 function createRandomPizza(string memory _name) public {80 uint256 randDna = generateRandomDna(_name, msg.sender);81 _createPizza(_name, randDna);82 }8384 // স্ট্রিং (নাম) এবং মালিকের (নির্মাতা) ঠিকানা থেকে র্যান্ডম ডিএনএ তৈরি করে85 function generateRandomDna(string memory _str, address _owner)86 public87 // `pure` হিসাবে চিহ্নিত ফাংশনগুলি স্টেট থেকে পড়া বা পরিবর্তন না করার প্রতিশ্রুতি দেয়88 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions89 pure90 returns (uint256)91 {92 // স্ট্রিং (নাম) + ঠিকানা (মালিক) থেকে র্যান্ডম ইউইন্ট তৈরি করে93 uint256 rand = uint256(keccak256(abi.encodePacked(_str))) +94 uint256(_owner);95 rand = rand % dnaModulus;96 return rand;97 }9899 // মালিক দ্বারা পাওয়া পিৎজার অ্যারে রিটার্ন করে100 function getPizzasByOwner(address _owner)101 public102 // `view` হিসাবে চিহ্নিত ফাংশনগুলি স্টেট পরিবর্তন না করার প্রতিশ্রুতি দেয়103 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions104 view105 returns (uint256[] memory)106 {107 // শুধুমাত্র এই ফাংশন কলের জীবনচক্রের জন্য মান সঞ্চয় করতে `memory` সংগ্রহস্থল অবস্থান ব্যবহার করে।108 // আরও জানুন: https://solidity.readthedocs.io/en/v0.5.10/introduction-to-smart-contracts.html#storage-memory-and-the-stack109 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 }119120 // পিৎজা এবং মালিকানা অন্য ঠিকানায় স্থানান্তর করে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), "ঠিকানাটি অনুমোদিত নয়।");126127 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);128 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);129 pizzaToOwner[_pizzaId] = _to;130131 // ইম্পোর্ট করা IERC721 কন্ট্রাক্টে সংজ্ঞায়িত ইভেন্ট এমিট করে132 emit Transfer(_from, _to, _pizzaId);133 _clearApproval(_to, _pizzaId);134 }135136 /**137 * একটি প্রদত্ত টোকেন আইডির মালিকানা নিরাপদে অন্য ঠিকানায় স্থানান্তর করে138 * যদি টার্গেট ঠিকানা একটি কন্ট্রাক্ট হয়, তবে এটি অবশ্যই `onERC721Received` প্রয়োগ করবে,139 * যা একটি নিরাপদ স্থানান্তরের উপর কল করা হয়, এবং ম্যাজিক মান রিটার্ন করে140 * `bytes4(keccak256(\"onERC721Received(address,address,uint256,bytes)\"))`;141 * অন্যথায়, স্থানান্তরটি ফিরিয়ে দেওয়া হয়।142 */143 function safeTransferFrom(address from, address to, uint256 pizzaId)144 public145 {146 // solium-disable-next-line arg-overflow147 this.safeTransferFrom(from, to, pizzaId, "");148 }149150 /**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 _data162 ) public {163 this.transferFrom(from, to, pizzaId);164 require(_checkOnERC721Received(from, to, pizzaId, _data), "অবশ্যই onERC721Received প্রয়োগ করতে হবে।");165 }166167 /**168 * একটি টার্গেট ঠিকানায় `onERC721Received`-কে আহ্বান করার জন্য ইন্টারনাল ফাংশন169 * যদি টার্গেট ঠিকানা একটি কন্ট্রাক্ট না হয় তবে কলটি এক্সিকিউট করা হয় না170 */171 function _checkOnERC721Received(172 address from,173 address to,174 uint256 pizzaId,175 bytes memory _data176 ) internal returns (bool) {177 if (!isContract(to)) {178 return true;179 }180181 bytes4 retval = IERC721Receiver(to).onERC721Received(182 msg.sender,183 from,184 pizzaId,185 _data186 );187 return (retval == _ERC721_RECEIVED);188 }189190 // একটি পিৎজা বার্ন করে - টোকেন সম্পূর্ণরূপে ধ্বংস করে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), "ঠিকানাটি অনুমোদিত নয়।");197198 ownerPizzaCount[msg.sender] = SafeMath.sub(199 ownerPizzaCount[msg.sender],200 1201 );202 pizzaToOwner[_pizzaId] = address(0);203 }204205 // ঠিকানা দ্বারা পিৎজার সংখ্যা রিটার্ন করে206 function balanceOf(address _owner) public view returns (uint256 _balance) {207 return ownerPizzaCount[_owner];208 }209210 // আইডি দ্বারা পাওয়া পিৎজার মালিককে রিটার্ন করে211 function ownerOf(uint256 _pizzaId) public view returns (address _owner) {212 address owner = pizzaToOwner[_pizzaId];213 require(owner != address(0), "অবৈধ পিৎজা আইডি।");214 return owner;215 }216217 // পিৎজার মালিকানা স্থানান্তরের জন্য অন্য ঠিকানাকে অনুমোদন দেয়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 }223224 // নির্দিষ্ট পিৎজার জন্য অনুমোদিত ঠিকানা রিটার্ন করে225 function getApproved(uint256 _pizzaId)226 public227 view228 returns (address operator)229 {230 require(_exists(_pizzaId), "পিৎজা বিদ্যমান নেই।");231 return pizzaApprovals[_pizzaId];232 }233234 /**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 }245246 /*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 }255256 // একটি প্রদত্ত মালিক দ্বারা একজন অপারেটর অনুমোদিত কিনা তা বলে257 function isApprovedForAll(address owner, address operator)258 public259 view260 returns (bool)261 {262 return operatorApprovals[owner][operator];263 }264265 // পিৎজার মালিকানা নেয় - শুধুমাত্র অনুমোদিত ব্যবহারকারীদের জন্য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 }271272 // পিৎজা বিদ্যমান কিনা তা পরীক্ষা করে273 function _exists(uint256 pizzaId) internal view returns (bool) {274 address owner = pizzaToOwner[pizzaId];275 return owner != address(0);276 }277278 // ঠিকানাটি মালিক বা পিৎজা স্থানান্তরের জন্য অনুমোদিত কিনা তা পরীক্ষা করে279 function _isApprovedOrOwner(address spender, uint256 pizzaId)280 internal281 view282 returns (bool)283 {284 address owner = pizzaToOwner[pizzaId];285 // solium চেক অক্ষম করুন কারণ286 // https://github.com/duaraghav8/Solium/issues/175287 // solium-disable-next-line operator-whitespace288 return (spender == owner ||289 this.getApproved(pizzaId) == spender ||290 this.isApprovedForAll(owner, spender));291 }292293 // পিৎজা অনন্য এবং এখনও বিদ্যমান নেই কিনা তা পরীক্ষা করুন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 == _dna301 ) {302 result = false;303 }304 }305 require(result, "এই নামের পিৎজা ইতিমধ্যে বিদ্যমান।");306 _;307 }308309 // টার্গেট ঠিকানাটি একটি কন্ট্রাক্ট কিনা তা রিটার্ন করে310 function isContract(address account) internal view returns (bool) {311 uint256 size;312 // বর্তমানে একটি ঠিকানায় একটি কন্ট্রাক্ট আছে কিনা তা পরীক্ষা করার জন্য এর থেকে ভালো কোনো উপায় নেই313 // সেই ঠিকানার কোডের আকার পরীক্ষা করা ছাড়া।314 // এটি কীভাবে কাজ করে সে সম্পর্কে আরও জানতে দেখুন https://ethereum.stackexchange.com/a/14016/36603315 // ।316 // TODO Serenity রিলিজের আগে এটি আবার পরীক্ষা করুন, কারণ তখন সমস্ত ঠিকানা317 // কন্ট্রাক্ট হবে।318 // solium-disable-next-line security/no-inline-assembly319 assembly {320 size := extcodesize(account)321 }322 return size > 0;323 }324}সবকটি দেখুনআরও পড়ুন
স্মার্ট কন্ট্র্যাক্টগুলির একটি আরো সম্পূর্ণ ওভারভিউর জন্য Solidity এবং Vyper-এর ডকুমেন্টেশন দেখুন:
সম্পর্কিত বিষয়
সম্পর্কিত টিউটোরিয়াল
- কন্ট্রাক্টের আকারের সীমার সাথে লড়াই করার জন্য কন্ট্রাক্ট ছোট করা – আপনার স্মার্ট কন্ট্র্যাক্টের আকার কমানোর জন্য কিছু ব্যবহারিক টিপস।
- ইভেন্টের মাধ্যমে স্মার্ট কন্ট্র্যাক্ট থেকে ডেটা লগ করা – স্মার্ট কন্ট্র্যাক্ট ইভেন্টের একটি ভূমিকা এবং আপনি ডেটা লগ করতে কীভাবে সেগুলি ব্যবহার করতে পারেন।
- Solidity থেকে অন্যান্য কন্ট্র্যাক্টের সাথে ইন্টারঅ্যাক্ট করুন – কীভাবে একটি বিদ্যমান কন্ট্রাক্ট থেকে একটি স্মার্ট কন্ট্র্যাক্ট ডেপ্লয় করবেন এবং এটির সাথে ইন্টারঅ্যাক্ট করবেন।