下面给大家分享一些solidity的一些必备知识点
一,智能合约转账时可以用到功能:receive和fallback。两者都接收以太币由于它们主要用于处理外部消息和事件,因此它们都不能直接从内部函数调用所以需要external来修饰。
(1)receive函数只在接收到以太币时运行。当我们向Funder合约发送以太币时,receive函数将被执行。
receive() external payable { }
(2)fallback函数在接收到任何类型的消息时都会执行。即使不是以太币,只要您向Funder合约发送任何类型的消息,fallback函数就会被执行。
fallback() external payable { }
二,调用加密算法,将字符装换成为32为的哈希值
function generateRandom(string memory _str)public pure returns(bytes32){
return keccak256(abi.encodePacked(_str));
}
最后我们来写第一个合约
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
contract mulutiSigWallet{
// 事件一:往多钱包里面存钱
event Deposit(address indexed sender, uint amout);
// 事件二:提交交易txID = transaction ID 交易的序号
event Submit(uint indexed txID);
// 事件三:当有人提交交易时,允许交易
event Approve(address indexed owner, uint indexed txID);
// 事件四,撤销交易
event Revoke(address indexed owner, uint txID);
// 事件五:执行交易
event Excute(uint indexed txID);
// 建立一个修饰符,检测该方法的地址是否是钱包所有人之一
modifier OnlyOwner(){
require(isOwner[msg.sender], "you are not one of the owner");
_;
}
// 输入的交易序列号不能超过交易的总数
modifier txExists(uint _txID){
require(_txID < transactions.length);
_;
}
// 建立一个函数修饰符 ,用于检查该交易是否已经被调用该函数同意了
modifier notApproved(uint _txID){
require(!approved[_txID][msg.sender], "you have already approved this transacthion");
_;
}
// 建立一个函数修饰符,用于检查该笔交易是否已经执行了
modifier notExecuted(uint _txID){
require(!transactions[_txID].executed, "this tx has already excuted");
_;
}
// 定义一个交易的结构体
struct Transaction{
address to;
uint value;
bytes data;
bool executed;//交易是否执行
}
// 往该多签钱包存钱用户的地址
address sender ;
// 多签钱包的所以着的列
address[] public owners;
// 定义一个mapping方法,判断这个地址是不是多签钱包所有者
mapping(address => bool) public isOwner;
// 定义一个数,这个变量代表需要多少人以上完成一笔交易
uint public required;
// 定义一个所有元素类型为Transaction的列表,
Transaction[] public transactions;
// 建立一个多重mapping方法,交易的序号->address->bool
mapping(uint => mapping(address => bool)) public approved;
// 创建一个构造函数,输入一个所有者地址和最小需要多少人同意才能执行一笔交易
constructor(address[] memory _owner, uint _required){
// 加一个修饰符,限制owner必须有地址
require(_owner.length > 0, "owners can not be zero");
// 加一个修饰符,限制最小同意的人数,必须大于0且小于钱包的所以者数量
require(_required > 0 && _required < _owner.length, "invalid required numbers");
// 检查每个地址有没有重复读取
for(uint i; i <= _owner.length; i++){
address owner = owners[i];
// 建立一个修饰符,保证每个输入的地址不为0x0000...00
require(owner != address(0), "0x0000...00 not vaild owners!");
// 保证没有重复的值
require(!isOwner[owner], "the address is already be the owner");
// 读取过的地址标记一下
isOwner[owner] = true;
// 往owner里面插入owner这个地址
owners.push(owner);
// required人数就是我们输入的_reqired
required = _required;
}
}
// 建立一个receive功能,让我们的合约可以收款,每当有地址往里面转以太坊的时候,就排除一个Deposit事件
receive() external payable {
emit Deposit(msg.sender, msg.value);
}
// 建立一个function:submitu用于提交一笔交易
function submit(address _to, uint _value, bytes calldata _data) external payable OnlyOwner{
transactions.push(Transaction({
to:_to,
value:_value,
data:_data,
executed:false
}));
emit Submit(transactions.length - 1);
}
// 用于同意某笔交易
function approve(uint _txID)
external
OnlyOwner
txExists(_txID)
notApproved(_txID)
notExecuted(_txID)
{
approved[_txID][msg.sender] = true;
emit Approve(msg.sender, _txID);
}
// 统计有多少人
function _getthenumberconfirm(uint _txID) public view returns (uint count){
for(uint i = 0; i < owners.length; i++){
if(approved[_txID][owners[i]]){
count++;
}
}
}
function executedTransaction(uint _txID)
public
OnlyOwner
txExists(_txID)
notExecuted(_txID)
{
// 这里再复习一下storage需要修改链上的数据的封装类型,
// memory用于,我只拿去链上的数据,不做修改
Transaction storage transaction = transactions[_txID];
require(_getthenumberconfirm(_txID) > required, "not enough people agree this transaction");
transaction.executed = true;
// 转账
(bool success,) = payable (transaction.to).call{value:transaction.value}(
transaction.data
);
require(success, "tx failed");
// 上面也可以用下面这个代替转账
// payable(transaction.to).transfer(transaction.value);
emit Excute(_txID);
}
// 用于撤销已提交的事务
function revokeTransaction(uint _txID) public OnlyOwner txExists(_txID) notExecuted(_txID){
require(approved[_txID][msg.sender] == true, "not approved!");
approved[_txID][msg.sender] = false;
emit Revoke(msg.sender, _txID);
}
}