Là một trong mạng được xây dựng từ Substrate Framework, và cũng là một đối thủ đáng gờm để trở thành một Parachain cho Polkadot trong tương lai. Polkadot Relaychain về cơ bản không hỗ trợ các Smart Contrac, và đó cũng chính là cơ hội cho Plasm để lấp đầy khoảng trống đó.
Và thêm một điểm mà các lập trình viên vô cùng thích đó chính là PLASM hoàn toàn opensource: https://github.com/PlasmNetwork
Giới thiệu
Thay vì việc viết các smart contract bằng Web thì Plasm đem đến sự quen thuộc cho những Ethereum developer, họ có thể thoải mái viết contract Solidity và deploy lên Plasm vì Plasm hỗ trợ EVM, hiện tại họ có thể hỗ trợ các smart contract chạy trên mạng testnet Dusty (tương lai sẽ là Shiden nếu thành công auction trên Kusama).
Thực hành
Trong phần này mình sẽ hướng dẫn các bước để có thể xây dựng một Dapp hoàn chỉnh trên mạng Dusty
Config metamask
Đầu tiên để tương tác với các Dapp cũng như tương tác với Remix để kí các transaction.
Ta sẽ config lại network với các thông số sau:
- Network Name: Dusty
- New RPC URL: https://rpc.dusty.plasmnet.io:8545
- Chain ID: 80
- Current Symbol: PLD
Tạm thời thì Dusty chưa hộ trợ BlockExplorer do đó việc debug khi transaction gặp lỗi là khá khó khăn, tuy nhiên hãy chờ đợi những bản hoàn chỉnh hơn trên Shiden – hi vọng lúc đó các công cụ cho developers đã được đầu tư nhiều hơn.
Faucet
Để có thể Deploy hay tạo được transaction thì trước tiên chúng ta phải có native token trên Plasm, như trên config thì native token ở đây có symbol là PLD
Để có thể faucet một chút PLD thuận tiện cho việc test, các bạn có thể faucet trực tiếp tại đây :
https://plasm-faucet-frontend.vercel.app/
Tuy nhiên chúng ta đang sử dụng metamask nên địa chỉ account sẽ có dạng của ETH address, do đó chúng ta cần một số bước để có thể lấy đúng được địa chỉ để có thể nhận faucet.
Đầu tiên là convert từ địa chỉ ETH sang dạng prefix 5 thông qua : https://hoonsubin.github.io/evm-substrate-address-converter/index.html
Sau khi lấy được địa chỉ convert sang dạng prefix 5 thì sẽ chuyển sang đây để có thể lấy được đúng địa chỉ trên Plasm tương ứng với địa chi bên Metamask: https://polkadot.subscan.io/tools/ss58_transform
Địa chỉ có Prefix 5 kia chính là thứ mà chúng ta cần tìm kiếm, copy và lấy faucet từ đây thôi nào:
https://plasm-faucet-frontend.vercel.app/
Và sau đó chúng ta đã có lượng PLD cho việc test
Note: Do decimal của PLD là 15 khác với mặc định của Metamask là cho các native token có decimal là 18 do đó với 1 PLD hiển thị trong metamask chúng ta sẽ ngầm hiểu là tương ứng với 1000 PLD trong mạng Dusty.
Và đã đủ tiền để trả phí transaction, tiếp theo chúng ta sẽ xây một vài Dapp
Dapp
Smart Contract
Chúng ta sẽ sử dụng Remix để code cũng như deploy contract lên Dusty : https://remix.ethereum.org/
Trong bài viết mình sẽ demo một Dapp nhỏ đã được demo trong ETH workshop India : Airbnb smart contract
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | pragma solidity <span class="token operator">^</span><span class="token number">0.5</span><span class="token number">.7</span><span class="token punctuation">;</span> contract Airbnb <span class="token punctuation">{</span> <span class="token comment">// Property to be rented out on Airbnb</span> struct Property <span class="token punctuation">{</span> string name<span class="token punctuation">;</span> string description<span class="token punctuation">;</span> bool isActive<span class="token punctuation">;</span> <span class="token comment">// is property active</span> uint256 price<span class="token punctuation">;</span> <span class="token comment">// per day price in wei (1 ether = 10^18 wei)</span> address owner<span class="token punctuation">;</span> <span class="token comment">// Owner of the property</span> <span class="token comment">// Is the property booked on a particular day,</span> <span class="token comment">// For the sake of simplicity, we assign 0 to Jan 1, 1 to Jan 2 and so on</span> <span class="token comment">// so isBooked[31] will denote whether the property is booked for Feb 1</span> bool<span class="token punctuation">[</span><span class="token punctuation">]</span> isBooked<span class="token punctuation">;</span> <span class="token punctuation">}</span> uint256 <span class="token keyword">public</span> propertyId<span class="token punctuation">;</span> <span class="token comment">// mapping of propertyId to Property object</span> <span class="token function">mapping</span><span class="token punctuation">(</span><span class="token parameter">uint256</span> <span class="token operator">=></span> Property<span class="token punctuation">)</span> <span class="token keyword">public</span> properties<span class="token punctuation">;</span> <span class="token comment">// Details of a particular booking</span> struct Booking <span class="token punctuation">{</span> uint256 propertyId<span class="token punctuation">;</span> uint256 checkInDate<span class="token punctuation">;</span> uint256 checkoutDate<span class="token punctuation">;</span> address user<span class="token punctuation">;</span> <span class="token punctuation">}</span> uint256 <span class="token keyword">public</span> bookingId<span class="token punctuation">;</span> <span class="token comment">// mapping of bookingId to Booking object</span> <span class="token function">mapping</span><span class="token punctuation">(</span><span class="token parameter">uint256</span> <span class="token operator">=></span> Booking<span class="token punctuation">)</span> <span class="token keyword">public</span> bookings<span class="token punctuation">;</span> <span class="token comment">// This event is emitted when a new property is put up for sale</span> event <span class="token function">NewProperty</span> <span class="token punctuation">(</span> uint256 indexed propertyId <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// This event is emitted when a NewBooking is made</span> event <span class="token function">NewBooking</span> <span class="token punctuation">(</span> uint256 indexed propertyId<span class="token punctuation">,</span> uint256 indexed bookingId <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/** * @dev Put up an Airbnb property in the market * @param name Name of the property * @param description Short description of your property * @param price Price per day in wei (1 ether = 10^18 wei) */</span> <span class="token keyword">function</span> <span class="token function">rentOutproperty</span><span class="token punctuation">(</span><span class="token parameter">string memory name<span class="token punctuation">,</span> string memory description<span class="token punctuation">,</span> uint256 price</span><span class="token punctuation">)</span> <span class="token keyword">public</span> <span class="token punctuation">{</span> Property memory property <span class="token operator">=</span> <span class="token function">Property</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> description<span class="token punctuation">,</span> <span class="token boolean">true</span> <span class="token comment">/* isActive */</span><span class="token punctuation">,</span> price<span class="token punctuation">,</span> msg<span class="token punctuation">.</span>sender <span class="token comment">/* owner */</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">bool</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token number">365</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Persist `property` object to the "permanent" storage</span> properties<span class="token punctuation">[</span>propertyId<span class="token punctuation">]</span> <span class="token operator">=</span> property<span class="token punctuation">;</span> <span class="token comment">// emit an event to notify the clients</span> emit <span class="token function">NewProperty</span><span class="token punctuation">(</span>propertyId<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/** * @dev Make an Airbnb booking * @param _propertyId id of the property to rent out * @param checkInDate Check-in date * @param checkoutDate Check-out date */</span> <span class="token keyword">function</span> <span class="token function">rentProperty</span><span class="token punctuation">(</span><span class="token parameter">uint256 _propertyId<span class="token punctuation">,</span> uint256 checkInDate<span class="token punctuation">,</span> uint256 checkoutDate</span><span class="token punctuation">)</span> <span class="token keyword">public</span> payable <span class="token punctuation">{</span> <span class="token comment">// Retrieve `property` object from the storage</span> Property storage property <span class="token operator">=</span> properties<span class="token punctuation">[</span>_propertyId<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// Assert that property is active</span> <span class="token function">require</span><span class="token punctuation">(</span> property<span class="token punctuation">.</span>isActive <span class="token operator">==</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token string">"property with this ID is not active"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Assert that property is available for the dates</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>uint256 i <span class="token operator">=</span> checkInDate<span class="token punctuation">;</span> i <span class="token operator"><</span> checkoutDate<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>property<span class="token punctuation">.</span>isBooked<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// if property is booked on a day, revert the transaction</span> <span class="token function">revert</span><span class="token punctuation">(</span><span class="token string">"property is not available for the selected dates"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// Check the customer has sent an amount equal to (pricePerDay * numberOfDays)</span> <span class="token function">require</span><span class="token punctuation">(</span> msg<span class="token punctuation">.</span>value <span class="token operator">==</span> property<span class="token punctuation">.</span>price <span class="token operator">*</span> <span class="token punctuation">(</span>checkoutDate <span class="token operator">-</span> checkInDate<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">"Sent insufficient funds"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// send funds to the owner of the property</span> <span class="token function">_sendFunds</span><span class="token punctuation">(</span>property<span class="token punctuation">.</span>owner<span class="token punctuation">,</span> msg<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// conditions for a booking are satisfied, so make the booking</span> <span class="token function">_createBooking</span><span class="token punctuation">(</span>_propertyId<span class="token punctuation">,</span> checkInDate<span class="token punctuation">,</span> checkoutDate<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">_createBooking</span><span class="token punctuation">(</span><span class="token parameter">uint256 _propertyId<span class="token punctuation">,</span> uint256 checkInDate<span class="token punctuation">,</span> uint256 checkoutDate</span><span class="token punctuation">)</span> internal <span class="token punctuation">{</span> <span class="token comment">// Create a new booking object</span> bookings<span class="token punctuation">[</span>bookingId<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">Booking</span><span class="token punctuation">(</span>_propertyId<span class="token punctuation">,</span> checkInDate<span class="token punctuation">,</span> checkoutDate<span class="token punctuation">,</span> msg<span class="token punctuation">.</span>sender<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Retrieve `property` object from the storage</span> Property storage property <span class="token operator">=</span> properties<span class="token punctuation">[</span>_propertyId<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// Mark the property booked on the requested dates</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>uint256 i <span class="token operator">=</span> checkInDate<span class="token punctuation">;</span> i <span class="token operator"><</span> checkoutDate<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> property<span class="token punctuation">.</span>isBooked<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Emit an event to notify clients</span> emit <span class="token function">NewBooking</span><span class="token punctuation">(</span>_propertyId<span class="token punctuation">,</span> bookingId<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">_sendFunds</span> <span class="token punctuation">(</span><span class="token parameter">address beneficiary<span class="token punctuation">,</span> uint256 value</span><span class="token punctuation">)</span> internal <span class="token punctuation">{</span> <span class="token comment">// address(uint160()) is a weird solidity quirk</span> <span class="token comment">// Read more here: https://solidity.readthedocs.io/en/v0.5.10/050-breaking-changes.html?highlight=address%20payable#explicitness-requirements</span> <span class="token function">address</span><span class="token punctuation">(</span><span class="token function">uint160</span><span class="token punctuation">(</span>beneficiary<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">transfer</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/** * @dev Take down the property from the market * @param _propertyId Property ID */</span> <span class="token keyword">function</span> <span class="token function">markPropertyAsInactive</span><span class="token punctuation">(</span><span class="token parameter">uint256 _propertyId</span><span class="token punctuation">)</span> <span class="token keyword">public</span> <span class="token punctuation">{</span> <span class="token function">require</span><span class="token punctuation">(</span> properties<span class="token punctuation">[</span>_propertyId<span class="token punctuation">]</span><span class="token punctuation">.</span>owner <span class="token operator">==</span> msg<span class="token punctuation">.</span>sender<span class="token punctuation">,</span> <span class="token string">"THIS IS NOT YOUR PROPERTY"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> properties<span class="token punctuation">[</span>_propertyId<span class="token punctuation">]</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Việc còn lại của chúng ta đó chính là compile và connect mạng Dusty qua metamask và deploy, contract sau khi deploy thành công sẽ xuất hiện :
UI
Sau khi deploy xong chúng ta sẽ có một contract chạy trên Dusty, việc tiếp theo đó chính là xây dựng UI để tương tác với contract đó, mình cũng đã chuẩn bị sẵn 1 folder để các bạn có thể test trực tiếp trên đó, các bạn có thể clone về và áp địa chỉ contract vào là có thể test và vọc luôn:
Trong repo này đòi hỏi chúng ta nên tìm hiểu trước một chút về Nuxt và Web3js
https://github.com/tranchien2002/dustyPLM-demo
Đầu tiên là thay đổi địa chỉ contract ở file:
tạm thời sau khi thay bằng địa chỉ contract mới deploy phía trên là chúng ta có thể chạy thử để test luôn
1 2 3 4 | yarn install cd dapp<span class="token operator">-</span>ui yarn dev |
Chạy thử vào tạo một transaction, và đây là kết quả sau khi transaction thành công
Kết luận
Và cuối cùng thì chúng ta cũng đã chạy được một Dapp hoàn chỉnh trên Dusty – testnet của Plasm. Đối với những Ethereum dev thì sẽ khá tưởng đồng với việc xây dựng trên ETH hay các blockchain hỗ trợ EVM khác nói chung. Hi vọng bài viết của mình có thể giúp đỡ được cho các bạn đang bắt đầu tìm hiểu về các parachain của Polkadot