Blockchain

Các cách gửi và nhận Ether trong smart contract

Bài viết này sẽ trình bày cách viết một hợp đồng thông minh đơn giản nhưng đầy đủ trong Solidity giúp contract của chúng ta có thể nhận và phân phối Ether

Tài khoản sở hữu Ether (Accounts Own Ether)

Có 2 loại tài khoản Ethereum là smart contracttài khoản thuộc sở hữu ( Externally-Owned Accounts ) cả 2 loại tài khoản này đều có thể sở hữu Ether. Chỉ cần địa chỉ của tài khoản đó thì có thể kiểm tra số dư của tài khoản đó trong Solidity bằng câu lệnh address.balance . Một smart contract có thể truy cập số dư của chính nó bằng câu lệnh address(this).balance . Smart contract minh họa dưới đây sẽ trả lại số dư tài khoản mà nó đang sở hữu:

pragma solidity ^0.4.24;

contract Sandbox {
    function getBalance() public view returns (uint256) {
        return address(this).balance;
    }
}

Tiền Gửi (Deposit)

Để cho phép các tài khoản khác có thể gửi và rút ether từ smart contract , chúng ta sẽ thêm vài hàm . Bắt đầu với hàm gửi ether deposit()

pragma solidity ^0.4.24;

contract Sandbox {
    function deposit() payable public {
        // TODO do something then
    }

    function getBalance() public view returns (uint256) {
        return address(this).balance;
    }
}

Với đoạn code trên :

  • payable trong hàm cho phép contract nhận ether mà người gửi tin nhắn có thể gửi kèm theo trong transaction message
  • Hàm này có thể hiểu là ngầm nhận ether đính kèm được chuyển đến

Do việc ngầm định này nên hàm deposit() rất đơn giản .Mặc dù chúng ta có thể hoàn toàn viết như ở trên nhưng có một cách tốt hơn đó là truyền số tiền qua tham số và kiểm tra số tiền đó thực sự được chuyển chưa. Điều này cho phép smartcontract từ chối các giao dịch có thể bị lỗi

pragma solidity ^0.4.24;

contract Sandbox {
    function deposit(uint256 amount) payable public {
        require(msg.value == amount);
        // TODO do songthing then
    }

    function getBalance() public view returns (uint256) {
        return address(this).balance;
    }
}

Giải thích :

  • msg.value đại diệncho số tiền người gửi đính kèm trong transaction message
  • require(msg.value == amount); kiểm tra số tiền được đính kèm trong transaction message và số tiền mà ng gửi chuyển như 1 đối số của hàm deposit() . Nếu requite fails thì toàn bộ giao dịch thất bại và không gây tổn thất gì .

Đây là một lựa chọn thiết kế cơ bản cho các smart contract , các giao dịch sẽ hoàn thành đầy đủ với tất cả các trạng thái được ghi lại đầy đủ hoặc giao dịch bị hủy bỏ mà không có bất cứ tổn thất gì. Mô hình này được khai thác nhiều khi phải triển các smart contract phức tạp hơn.

Rút tiền ( Withdraw )

Một điều quan trọng của smart contract là hoàn toàn không có cách nào để rút ether khỏi nó ngoài việc thực hiện một số chức năng mà hợp tạo ra. Hoàn toàn không "backdoor" để có thể cho phép tác giả hoặc người pháp triển hợp đồng có thể rút ether mà không thông qua các hàm của smar tcontract. Đây là lí do cơ bản tại sao một smart contract được viết tốt có thể được tin cậy để xử lí giao dịch ether thay cho người dùng.

Hãy thử viết 1 hàm withdraw để rút tất cả số tiền của contract cho địa chỉ gọi hàm withdraw()

pragma solidity ^0.4.24;

contract Sandbox {
    function withdraw() public {
        msg.sender.transfer(address(this).balance);
    }

    function deposit(uint256 amount) payable public {
        require(msg.value == amount);
        // TODO do songthing then
    }

    function getBalance() public view returns (uint256) {
        return address(this).balance;
    }
}

Giải thích :

  • msg.sender đại diện cho địa chỉ tài khoản gọi đến contract
  • address.transfer(amount) chuyển số tiền bằng ether vào tài khoản được đại diện bởi biến address Đoạn code trên minh họa việc chuyển ether từ smart contract này sang tài khoản gọi đến hàm withdarw(). Tất nhiên , hợp đồng phải sở hữu một lượng ether đủ để trả phí thực hiện giao dịch . Nếu không hệ thống sẽ hủy bỏ giao dịch.

transfer() vs send()

Ngoài chức năng transfer() để chuyển ether, Solidity còn cung cấp chức năng send(), call() .Nhưng tôi ko khuyến khich sử dụng send() vì có thể sẽ hơi nguy hiểm khi sử dụng.

  1. Nếu transfer() gặp vấn đề, nó sẽ đưa ra ngoại lệ, điều này sẽ khiên dịch bị hủy bỏ. Điều này thường sẽ chỉ xảy ra nếu quá trình chuyển hết gas. Hủy bỏ giao dịch trong trường hợp này là tốt và an toàn vì có lẽ bạn cũng không muốn giao dịch hoàn thành với giả định sai là nó đã thực hiện chuyển ether.

  2. send() sẽ trả về true hoặc false tùy thuộc vào việc nó chuyển ether thành công hay thất bại, nhưng nó sẽ không bao giờ hủy bỏ. Nếu smart contract không kiểm tra gía trị trả về của send() hoặc không xử lý được chính xác lỗi thì smart contract có thể rơi vào trạng thái không nhất quán và không thể khôi phục. Do đó, tôi khuyên bạn hãy sử dụng transfer() thay vì send() để chuyển tiền ra khỏi smart contract

Solidity’s "Fallback Function"

Solidity có một cấu trúc được gọi là fallback function , nó cũng có tác dụng giúp các smart contract có thể nhận ether . Lưu ý là để viết hàm này chúng ta sẽ ko đề cập đến tên của chúng.

pragma solidity ^0.4.24;

contract Sandbox {
    function () public payable{
            // do nothing here
    }
}

Đây là cấu trúc thường được sử dụng , tuy nhiên cũng tiềm ẩn nhiều rủi ro hãy thận trọng khi sử dụng nó

Tổng kết

  • Ethereum smart contracts có thể nhận cũng như gửi ether
  • Hàm để kiểm tra số dư của contract address(this).balance
  • Để contract có thể nhận ether phải có hàm yêu cầu payable
  • Có thể xác nhận số lượng ether được gửi vào qua transaction message qua câu lệnh msg.value
  • Để chuyển ehter đi ta có thể sử dụng transfer(amout) hoặc có thể sử dụng send(amount) nhưng hãy cẩn thận check giá trị trả về
  • smart contract có thể chấp nhận nhận ether bằng fallback function
Registration Login
Sign in with social account
or
Lost your Password?
Registration Login
Sign in with social account
or
A password will be send on your post
Registration Login
Registration