- vừa được xem lúc

Viết Smart Contract chain Algorand #2

0 0 1

Người đăng: Cường Phạm Vũ

Theo Viblo Asia

Algorand Smart Contract

Ngôn ngữ lập trình Smart Contract trên Algorand: Teal → PyTeal → Beaker

Application Class

Algorand thì thay vì gọi Smart Contract, họ gọi là Application

Khởi tạo một application

app = beaker.Application("hello_world")

Apply()

Dùng để add các config lên application - ví dụ mình muốn khởi tạo app với các local state mình define ra thì có thể làm như sau

from beaker import Application, GlobalStateValue, unconditional_create_approval
from pyteal import Bytes, Expr, TealType, abi, Int # Define Global State
class AppState: app_state = GlobalStateValue( stack_type=TealType.uint64, default=Int(10), ) # Create Application and Add Global State when Init Application
app = Application("SimpleApp", state=AppState()).apply( unconditional_create_approval, initialize_global_state=True
) # Read Global State
@app.external
def read_state(*, output: abi.Uint64) -> Expr: return output.set(app.state.app_state)

Global State

Có 3 loại Global State

  • Global State Value → hold 1 value
  • Reserve Global State → key pair
  • Global State Blob → sử dụng cho complex data

Global State Value

Dùng để lưu 1 giá trị trên Smart Contract

Để khởi tạo Global State Value, mình tạo một class, sau đó config các thông số cho Global State

  • stack_type: Kiểu dữ liệu
    • TealType.bytes
    • TealTypes.uint64
  • default: Giá trị mặc định khi khởi tạo
  • static
    • True: Biến này sẽ không đổi (const)
    • False: Biến này sẽ có thể đổi

Để thay đổi giá trị cho Global State, mình sử dụng hàm set()

  • eg: app.state.my_description.set(Bytes(”hello))

Để lấy giá trị của Global State, mình sử dụng hàm set() cho output

  • eg: output.set(app.state.my_description)
from beaker import Application, GlobalStateValue, unconditional_create_approval
from pyteal import Bytes, Expr, TealType, abi, Int # Define Global State
class GlobalState: my_description = GlobalStateValue( # Define Type stack_type = TealType.bytes, # Set Value default = Bytes("Henry is the best!"), # Static True mean this Variable will not be changed (const) static = False,
) # Create Application
app = Application("GlobalStateValue",state=GlobalState()).apply( unconditional_create_approval, initialize_global_state = True
) # Set new value for state
@app.external
def set_app_state_val(v: abi.String) -> Expr: return app.state.my_description.set(v.get()) # Get State Value
@app.external
def get_app_state_val(*, output: abi.String) -> Expr: return output.set(app.state.my_description)

Global State Blob

Tương tự với Global State, Global State Blob lưu trên Smart Contract.

Khác với Global State, Global State Blob lưu được nhiều data hơn (32KB data) so với Global State (64 bytes) Global State Blob chỉ lưu dạng dữ liệu Bytes

Global State lưu 1 dữ liệu, còn Global State Blob lưu complex data như array hay maps

Để sử dụng Global State Blob, đầu tiên mình cần define có bao nhiêu keys. (mapping)

Sử dụng app.state.global_blob.write() để gán dữ liệu

  • Truyền bao nhiêu argument phụ thuộc vào khi nãy bạn config bao nhiêu keys

Sử dụng app.state.global_blob.read() để đọc dữ liệu

  • Truyền 2 tham số, lấy dữ liệu từ số thứ tự bao nhiêu, đến số thứ tự bao nhiêu
  • Để lấy số lượng các phần tử có trong Global State Blob, mình sử dụng app.state.global_blob.blob.max_bytes - Int(1)
from beaker import Application, GlobalStateBlob, unconditional_create_approval
from pyteal import Bytes, Expr, TealType, abi, Int # Define Global Blob State
class AppState: global_blob = GlobalStateBlob( keys=2, ) # Create Application
app = Application("Global Blob App", state=AppState()).apply( unconditional_create_approval, initialize_global_state=True
) # Set new value for state
@app.external
def write_app_blob(start: abi.Uint64, v: abi.String) -> Expr: return app.state.global_blob.write(start.get(), v.get()) # Get State Value
@app.external
def get_app_state_val(*, output: abi.String) -> Expr: return output.set( app.state.global_blob.read( Int(0), app.state.global_blob.blob.max_bytes - Int(1) ) )

Local State

Local State lưu dữ liệu theo từng ví

Local State có 3 loại (giống Global State)

  • Local State Value
  • Reserve Local State
  • Local State Blob

Note: User có quyền clear Local State nên anh em becareful khi sử dụng

Local State Value

from beaker import Application, LocalStateValue, unconditional_opt_in_approval
from pyteal import Expr, Int, TealType, Txn, abi # Create Local State
class LocalState: count = LocalStateValue( stack_type=TealType.uint64, default=Int(1), descr="A Counter that keeps track of counts.", ) # Create Application
app = Application("Local State App", state=LocalState()).apply( unconditional_opt_in_approval, initialize_local_state=True
) # Increase Count
@app.external
def incr_local_state(v: abi.Uint64) -> Expr: return app.state.count[Txn.sender()].increment(v.get()) # Read Count
@app.external(read_only=True)
def get_local_state(*, output: abi.Uint64) -> Expr: return output.set(app.state.count[Txn.sender()])

Reserved Local State

from beaker import Application, ReservedLocalStateValue, unconditional_opt_in_approval
from pyteal import Expr, TealType, Txn, abi class ReservedLocalState: favorite_food = ReservedLocalStateValue( stack_type = TealType.bytes, max_keys = 8, descr = "8 key-value pairs of favorite foods ranked from 1 to 8.", ) app = Application("Reserved Local App", state = ReservedLocalState()).apply( unconditional_opt_in_approval, initialize_local_state = True
) @app.external
def set_reserved_local_state_val(k: abi.Uint8, v: abi.String) -> Expr: return app.state.favorite_food[k][Txn.sender()].set(v.get()) @app.external
def get_reserved_local_state_val(k: abi.Uint8, *, output: abi.String) -> Expr: return output.set(app.state.favorite_food[k][Txn.sender()])

Local Blob

Nếu truyền ví là ví call thì [Txn.sender()] có thể bỏ

from beaker import Application, LocalStateBlob, unconditional_opt_in_approval
from pyteal import Expr, Int, abi class LocalBlob: local_blob = LocalStateBlob(keys=2) app = Application("Local Blob App", state = LocalBlob()).apply( unconditional_opt_in_approval, initialize_local_state = True
) @app.external
def write_local_blob(v: abi.String) -> Expr: return app.state.local_blob.write(Int(0), v.get()) @app.external
def read_local_blob(*, output: abi.String) -> Expr: return output.set( app.state.local_blob.read(Int(0),app.state.local_blob.blob.max_bytes - Int(1)) ) 

Decorators

External

@app.external @app.external(read_only=True)
from beaker import Application
from pyteal import Expr, abi app = Application("External Example App") @app.external
def add(a: abi.Uint8, b: abi.Uint8, * , output: abi.Uint8) -> Expr: return output.set(a.get() +b.get())

Authorization

# Require only call by creator of this smart contract
@app.external(authorize = Authorize.only(Global.creator_address()))
def withdraw() -> Expr: return ....
# Require address hold token 123
@app.external(authorize = Authorize.holds_token(asset_id=123))
# Require address opted in this smart contract
@app.external(authorize = Authorize.opted_in())

OnComplete Decorators

# opted in account and execute function
@app.opt_in
@app.update
@app.close_out
@app.clear_state
@app.delete
from beaker import Application, Authorize
from pyteal import Approve, Expr, Global, Reject app = Application("OnComplete App") @app.opt_in
def opt_in() -> Expr: return Approve() @app.close_out
def close_out() -> Expr: return Reject() @app.clear_state
def clear_state() -> Expr: return Approve() @app.update
def update() -> Expr: return Approve() @app.delete(authorize = Authorize.only(Global.creator_address()))
def delete() -> Expr: return Approve()

Internal

Dùng để call các hàm trong smart contract nội bộ, ngoài không call vào được

Dùng để xử lý các complex logic

@Subroutine(TealType.uint64)
def internal_magic(*, output: abi.String) -> Expr: return ...
from beaker import Application
from pyteal import Expr, Subroutine, TealType, abi app = Application("Internal Subroutine Example App") @app.external
def add(a: abi.Uint8, b: abi.Uint8, * , output: abi.Uint8) -> Expr: return output.set(internal_add(a,b)) @Subroutine(TealType.uint64)
def internal_add(a: abi.Uint8, b: abi.Uint8) -> Expr: return a.get() + b.get()

Box Storage

aka Infinite State Made Easy

  • BoxMapping → mapping of key value pairs
  • BoxList→ store a list in a box

Box Mapping

from beaker import *
from pyteal import * from beaker.lib.storage import BoxMapping # Our customer Struct
class GroceryItem(abi.NamedTuple): item: abi.Field[abi.String] purchased: abi.Field[abi.Bool] class GroceryStates: grocery_item = BoxMapping(abi.String, GroceryItem) app = Application("Grocery Checklist with bearker", state=GroceryStates()) ### Add Grocery with Boxed ###
@app.external
def addGrocery(item_name: abi.String) -> Expr: purchased = abi.Bool() grocery_tuple = GroceryItem() return Seq( purchased.set(Int(0)), grocery_tuple.set(item_name, purchased), app.state.grocery_item[item_name.get()].set(grocery_tuple), ) ### update Grocery Item ###
@app.external
def updatePurchased(item_name: abi.String, *, output: GroceryItem) -> Expr: existing_grocery_item = GroceryItem() new_purchased = abi.Bool() return Seq( existing_grocery_item.decode(app.state.grocery_item[item_name.get()].get()), new_purchased.set(Int(1)), existing_grocery_item.set(item_name, new_purchased), app.state.grocery_item[item_name.get()].set(existing_grocery_item), app.state.grocery_item[item_name.get()].store_into(output), ) ### Read Grocery Item ###
@app.external
def readItem(item_name: abi.String, *, output: GroceryItem) -> Expr: return app.state.grocery_item[item_name.get()].store_into(output) ### Delete ###
@app.external
def deleteGrocery(item_name: abi.String) -> Expr: return Pop(app.state.grocery_item[item_name.get()].delete())

BoxList

from beaker import *
from pyteal import * from beaker.lib.storage import BoxList class SubscriberStates: idx = GlobalStateValue( stack_type=TealType.uint64, default=Int(0), descr="number of subscribers" ) addr_list = BoxList(abi.Address, 10) app = Application("Subscriber Count App", state=SubscriberStates()) ### Create Box List and Initalize Global state ###
@app.external
def bootstrap() -> Expr: return Seq( Pop(app.state.addr_list.create()), # Create a Box with name "addr_list" app.initialize_global_state(), ) ### Subscribe ###
@app.external
def subscribe(addr: abi.Address) -> Expr: return Seq(app.state.addr_list[app.state.idx].set(addr), app.state.idx.increment()) ### Read Subscriber ###
@app.external
def readSubscriber(idx: abi.Uint32, *, output: abi.Address) -> Expr: return app.state.addr_list[idx.get()].store_into(output) ### Delete ###
@app.external(authorize=Authorize.only(Global.creator_address()))
def deleteBox() -> Expr: return Assert(App.box_delete(Bytes("addr_list")))

Bình luận

Bài viết tương tự

- vừa được xem lúc

Code Smart Contract bằng Assembly ?

Introduction. Hồi còn học trong ghế nhà trường bộ môn lập trình tốn nhiều não nhất của mình là code assembly. Nôm na thì bất cứ ngôn ngữ bậc cao nào như C , Go, Java,... được sinh ra để người dễ hiểu và dễ code , tuy nhiên chúng đều sẽ được compiled down xuống assembly một ngôn ngữ bậc thấp để máy h

0 0 44

- vừa được xem lúc

Tích hợp Band Protocol để lấy dữ liệu off-chain cho smart contract

Khoan nói về Band Protocol là gì, mình sẽ đi thẳng vào công dụng của nó, có thể đây chính là mảnh ghép mà bạn vẫn luôn tìm kiếm cho Dapp của mình. Band protocol hỗ trợ các contract giao tiếp với dữ liệu từ thế giới bên ngoài như các dữ liệu về thời tiết, thể thao, giá trị cổ phiếu, tỉ giá các đồng n

0 0 52

- vừa được xem lúc

Xây dựng ứng dụng Dapps đầu tiên của bạn

Tutorial này sẽ giúp bạn xây dựng dapp đầu tiên của bạn – một hệ thống theo dõi chủ nuôi trong một tiệm thú cưng! Được dịch từ tutorial của Truffle. .

1 1 726

- vừa được xem lúc

Làm thế nào để một smart contract có thể nhận NFT (Non-Fungible Token)?

Mở đầu. Như chúng ta đã biết, trên các chain chạy evm ngày nay ngoài Native coin (ETH) và Fungible Token (ERC20) thì chúng còn cón Non-Fungible Token (ERC721 và ERC1155).

0 0 124

- vừa được xem lúc

Lập trình smart contract để tạo NFT kết hợp với Chainklink và IPFS

NFTs hay tên tiếng Anh là Non-Fungible Tokens có nghĩa là token duy nhất mà không bất kì token nào khác giống như nó. .

0 0 282

- vừa được xem lúc

Tản mạn về lỗ hổng trong smart contract của Fairmoon Token, các dấu hiệu bất thường và nguy cơ từ crypto

Hôm nay (19/05/2021) là một ngày đen tối đối với cộng đồng crypto khi:. .

0 0 58