在手把手教你实现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
函数。
整体的调用关系可以如下图所示:
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
合约做一些简单的改造,添加一些重写的关键字,这部分并不复杂,我们直接贴代码:
// 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...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!