手把手教你实现BigBank智能合约

  • Louis
  • 发布于 2024-07-06 10:29
  • 阅读 1451

在手把手教你实现Bank智能合约这篇文章中,我们认真拆解了需求,罗列了相关的知识点,已经实现了基于权限控制的存款和取款逻辑。这篇文章,我们会提升难度,不仅仅要实现功能,还要思考怎么合理的去设计一个合约。

相关背景

手把手教你实现Bank智能合约这篇文章中,我们认真拆解了需求,罗列了相关的知识点,已经实现了基于权限控制的存款和取款逻辑。这篇文章,我们会提升难度,不仅仅要实现功能,还要思考怎么合理的去设计一个合约。

新的需求如下:

1、新的BigBank合约要继承Bank合约;

2、BigBank合约支持转移自己的管理员权限到其他的指定账户;

3、需要编写一个Ownable合约,将BigBank合约的管理员权限转移给Ownable合约,转移之后,只有Ownable合约才可以调用BigBank合约的 withdraw()方法。

4、新的管理员调用withdraw()方法,可以成功从BigBank合约中把钱取走。

5、需要实现对存款前三名用户的排序。

合约基础架构搭建

继承的好处

题目的要求中涉及到了继承的知识点,我在Solidity中的继承这篇文章中介绍过,Solidity是一种面向对象的编程语言,它支持合约之间的继承。继承允许一个合约获取另一个合约的所有非私有属性和函数,这样就可以重复使用代码,降低重复工作量。

接口的相关概念

接口可以理解为一种约束,我们可以通过接口定义标准,通过接口定义一组函数签名,为智能合约提供标准化的接口。这对于创建可互操作的合约系统非常有用。

从抽象角度理解,接口允许你抽象出合约的功能,而不需要关心具体实现。这有助于提高代码的可读性和可维护性。

从多态的角度理解,通过接口,允许不同的合约实现相同的接口,但有不同的具体实现。

在类型检查层面,编译器可以使用接口进行类型检查,确保合约正确实现了所有必要的函数,实现过接口的朋友们都理解,如果继承了一个接口却没有实现它的全部函数,编译器就会报错,大大提高了代码的规范和安全性。

回顾了上面两个基础的概念,我们规划下整体合约的设计:

合约整体设计:

1、我们需要在上层抽象出一个接口,这个接口就叫做IBank,它的作用是抽象出Bank合约的能力,包括存款、取款、事件、还有一些可见的状态变量的定义。

2、我们在手把手教你实现Bank智能合约这篇文章中实现的Bank合约是需要继承IBank接口的,只需要稍加改造即可实现(包含对于函数的重写)

3、BigBank 合约是我们要新创建的合约,这个合约需要继承Bank合约,从这里就可以看出继承的好处了,根据题目要求,我们仅仅需要重写deposit方法,添加一些自己的方法即可,一些其他的公用部分都可以通过继承获得。

4、Ownable这个合约我们也需要新创建,BigBank合约可以将管理员权限交给它,用于只能通过Ownable合约去调用withdraw函数。

整体的调用关系可以如下图所示:

Xnip2024-07-06_09-52-26.png

IBank接口实现

IBank这个接口实现很简单,我们只需要将Bank合约的相关功能抽象出来即可:

// Define IBank interface
interface IBank {
    // Event definitions
    event Withdrawal(address indexed to, uint256 amount);
    event Deposit(address indexed from, uint256 amount);

    // Function definitions to be implemented
    // Getter function for public state variable
    function owner() external view returns (address);

    // Deposit function
    function deposit() external payable;

    // Withdraw function
    function withdraw(uint256 amount) external;

    // Get balance for a specific address
    function getBalance(address addr) external view returns (uint256);

    // Get top depositors
    function getTopDepositors() external view returns (address[] memory);
}

这个接口提供了一个标准化的结构。它定义了基本的存款、取款功能,以及一些辅助功能如查询余额和获取top存款人。通过使用这个接口,可以确保任何实现它的合约都会包含这些基本功能,从而提高代码的一致性和可互操作性。

修改Bank合约的实现

接下来,我们需要对Bank合约做一些简单的改造,添加一些重写的关键字,这部分并不复杂,我们直接贴代码:


// OriginalBank contract implementing IBank interface
contract OriginalBank is IBank {
    address public owner;
    mapping(address => uint256) private balances;
    address[] public topDepositors;

    // Constructor to set the contract owner
    constructor() {
        owner = msg.sender;
    }

    // Modifier to restrict function access to owner only
    modifier onlyOwner() {
        require(msg.sender == owner, "Only owner can call this function");
        _;
    }

    // Fallback function to handle direct ETH transfers
    receive() external payable {
        deposit();
    }

    // Deposit function to add funds to the contract
    function deposit() public payable virtual override {
        balances[msg.sender] += msg.value;
        updateTopDepositors(msg.sender);
        emit Deposit(msg.sender, msg.value);
    }

    // Withdraw function to transfer funds to the owner
    function withdraw(uint256 amount) public override onlyOwner {
        uint256 balance = address(this).balance;
        require(balance > 0, "Contract balance is zero");
        require(amount <= balance, "Insufficient contract balance");
        payable(owner).transfer(amount);
        emit Withdrawal(owner, amount);
    }

    // Internal function to update the list...

剩余50%的内容订阅专栏后可查看

点赞 2
收藏 2
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

1 条评论

请先 登录 后评论
Louis
Louis
web3 developer,技术交流或者有工作机会可加VX: magicalLouis