智能合约练习
一、solidity初学者经典示例代码:
1.存储和检索数据:
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; // 声明 Solidity 编译器版本
// 定义一个名为 SimpleStorage 的合约
contract SimpleStorage {
// 声明一个公共状态变量 data,用于存储一个 256 位的无符号整数
uint256 public data;
// 定义一个公共函数 setData,接受一个无符号整数参数 _data
function setData(uint256 _data) public {
// 将传入的参数 _data 存储到状态变量 data 中
data = _data;
}
// 定义一个公共视图函数 getData,返回一个无符号整数
function getData() public view returns (uint256) {
// 返回当前存储在状态变量 data 中的值
return data;
}
}
该合约的主要功能是允许用户存储一个无符号整数并检索该整数。通过调用 setData
函数,用户可以更新存储的数据,而通过调用 getData
函数,用户可以查看当前存储的值。这是一个简单的存储合约,常用于学习 Solidity 和以太坊的基本概念
2.条件控制:
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; // 声明 Solidity 编译器版本
// 定义一个名为 ConditionExample 的合约
contract ConditionExample {
// 定义一个公共纯函数 checkEven,接受一个无符号整数参数 _number
function checkEven(uint256 _number) public pure returns (bool) {
// 使用条件语句检查 _number 是否为偶数
if (_number % 2 == 0) {
// 如果 _number 是偶数,返回 true
return true;
} else {
// 如果 _number 不是偶数,返回 false
return false;
}
}
}
该合约提供了一个简单的功能,用于检查一个数字是否为偶数。通过调用 checkEven
函数,用户可以传入一个无符号整数,合约将返回一个布尔值,指示该数字的偶数性。这是一个基本的示例,展示了如何在 Solidity 中使用条件语句和函数。
3.数组操作:
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; // 声明 Solidity 编译器版本
// 定义一个名为 ArrayExample 的合约
contract ArrayExample {
// 声明一个公共状态变量 numbers,用于存储一个无符号整数数组
uint256[] public numbers;
// 定义一个公共函数 addNumber,接受一个无符号整数参数 _number
function addNumber(uint256 _number) public {
// 将 _number 添加到 numbers 数组中
numbers.push(_number);
}
// 定义一个公共视图函数 getNumber,接受一个无符号整数参数 _index
function getNumber(uint256 _index) public view returns (uint256) {
// 检查索引 _index 是否有效
require(_index < numbers.length, "Invalid index.");
// 返回 numbers 数组中索引为 _index 的值
return numbers[_index];
}
// 定义一个公共视图函数 getLength,返回一个无符号整数
function getLength() public view returns (uint256) {
// 返回 numbers 数组的长度
return numbers.length;
}
}
该合约展示了如何在 Solidity 中使用数组。用户可以通过 addNumber
函数将数字添加到数组中,使用 getNumber
函数根据索引访问数组元素,使用 getLength
函数获取数组的当前长度。这是一个基本的合约,适合学习 Solidity 中数组的操作。
4.循环遍历:
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; // 声明 Solidity 编译器版本
// 定义一个名为 LoopExample 的合约
contract LoopExample {
// 声明一个公共状态变量 numbers,用于存储一个无符号整数数组
uint256[] public numbers;
// 定义一个公共函数 addNumbers,接受一个无符号整数数组参数 _numbers
function addNumbers(uint256[] memory _numbers) public {
// 使用 for 循环遍历传入的 _numbers 数组
for (uint256 i = 0; i < _numbers.length; i++) {
// 将 _numbers 中的每个元素添加到 numbers 数组中
numbers.push(_numbers[i]);
}
}
// 定义一个公共视图函数 sumNumbers,返回一个无符号整数
function sumNumbers() public view returns (uint256) {
// 初始化 sum 变量为 0,用于计算总和
uint256 sum = 0;
// 使用 for 循环遍历 numbers 数组
for (uint256 i = 0; i < numbers.length; i++) {
// 将 numbers 中的每个元素加到 sum 中
sum += numbers[i];
}
// 返回总和
return sum;
}
}
该合约通过 addNumbers
函数提供了批量添加数字的功能,通过 sumNumbers
函数提供了计算数组元素总和的功能。合约展示了如何使用数组和循环在 Solidity 中进行简单的数据处理。这些功能适合学习如何在 Solidity 中处理数组操作和循环结构。
二、solidity进阶版经典示例代码
1.智能合约间的通信:
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; // 声明使用的 Solidity 编译器版本
// 定义一个名为 MessageContract 的合约
contract MessageContract {
// 声明一个公共状态变量 message,用于存储消息
string public message;
// 定义一个公共函数 setMessage,接受一个字符串参数 _message
function setMessage(string memory _message) public {
// 将传入的 _message 赋值给状态变量 message
message = _message;
}
}
// 定义一个名为 CallerContract 的合约
contract CallerContract {
// 声明一个公共状态变量 messageContract,类型为 MessageContract
MessageContract public messageContract;
// 构造函数,接受一个 MessageContract 类型的参数 _messageContract
constructor(MessageContract _messageContract) {
// 将传入的合约地址赋值给状态变量 messageContract
messageContract = _messageContract;
}
// 定义一个公共函数 setMessage,接受一个字符串参数 _message
function setMessage(string memory _message) public {
// 调用 MessageContract 的 setMessage 函数,设置消息
messageContract.setMessage(_message);
}
}
MessageContract 合约提供了一个简单的功能,用于存储和更新一条消息。CallerContract
合约则充当一个中介,允许外部用户通过它来设置 MessageContract
中的消息。这种设计展示了如何在 Solidity 中进行合约之间的交互
2.继承和接口:
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; // 指定合约使用的 Solidity 版本
// 定义一个名为 Token 的接口
interface Token {
// 定义转账函数 transfer,接收目标地址和转账金额
function transfer(address _to, uint256 _value) external returns (bool);
}
// 定义一个名为 MyToken 的合约,继承自 Token 接口
contract MyToken is Token {
// 声明一个公共映射 balances,用于存储每个地址的余额
mapping(address => uint256) public balances;
// 实现 transfer 函数,覆盖接口中的 transfer 函数
function transfer(address _to, uint256 _value) public override returns (bool) {
// 检查发送者的余额是否足够
require(balances[msg.sender] >= _value, "Insufficient balance.");
// 扣除发送者的余额
balances[msg.sender] -= _value;
// 增加接收者的余额
balances[_to] += _value;
// 返回成功标志
return true;
}
}
Token
接口定义了一个代币转账的基本功能。MyToken
合约实现了该接口,并提供了代币转账的具体逻辑。此合约的设计体现了 Solidity 中接口和合约之间的关系,以及如何通过状态变量管理每个地址的余额。
3.事件和日志:
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; // 指定合约使用的 Solidity 版本
// 定义合约 EventExample
contract EventExample {
// 定义事件 LogAddition,带有 sender 地址和两个输入参数及其结果
event LogAddition(address indexed _sender, uint256 _a, uint256 _b, uint256 _result);
// 定义一个公共函数 addNumbers,接收两个无符号整数作为参数
function addNumbers(uint256 _a, uint256 _b) public returns (uint256) {
// 计算两个数的和
uint256 result = _a + _b;
// 触发 LogAddition 事件,记录发送者地址、输入参数和结果
emit LogAddition(msg.sender, _a, _b, result);
// 返回计算结果
return result;
}
}
该合约提供了一个简单的加法功能,并通过事件记录了每次加法操作的详细信息,包括发送者的地址和加法的输入输出。事件在以太坊智能合约中用于记录和追踪操作,这些信息在区块链上是不可变的,便于后续查询和审计。
三、solidity高阶版经典示例代码
1.多重签名钱包合约:
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; // 指定 Solidity 版本
contract MultiSigWallet {
address[] public owners; // 钱包所有者数组
uint public numConfirmationsRequired; // 执行交易所需的确认数量
struct Transaction {
address to; // 接收资金的地址
uint value; // 发送的金额
bool executed; // 交易是否已执行
mapping(address => bool) isConfirmed; // 所有者的确认状态映射
uint numConfirmations; // 收到的确认数量
}
Transaction[] public transactions; // 交易数组
modifier onlyOwner() {
require(isOwner(msg.sender), "Only owners can call this function.");
_; // 继续执行
}
constructor(address[] memory _owners, uint _numConfirmationsRequired) {
require(_owners.length > 0, "At least one owner is required.");
require(_numConfirmationsRequired > 0 && _numConfirmationsRequired <= _owners.length, "Invalid number of required confirmations.");
owners = _owners; // 设置所有者
numConfirmationsRequired = _numConfirmationsRequired; // 设置所需确认数量
}
function isOwner(address _address) public view returns (bool) {
for (uint i = 0; i < owners.length; i++) {
if (owners[i] == _address) {
return true; // 地址是所有者
}
}
return false; // 地址不是所有者
}
function submitTransaction(address _to, uint _value) public onlyOwner {
uint transactionId = transactions.length; // 获取当前交易 ID
transactions.push(Transaction({
to: _to,
value: _value,
executed: false,
numConfirmations: 0
}));
confirmTransaction(transactionId); // 自动确认提交的交易
}
function confirmTransaction(uint _transactionId) public onlyOwner {
require(_transactionId < transactions.length, "Invalid transaction ID.");
require(!transactions[_transactionId].executed, "Transaction has already been executed.");
require(!transactions[_transactionId].isConfirmed[msg.sender], "Transaction has already been confirmed by this owner.");
transactions[_transactionId].isConfirmed[msg.sender] = true; // 标记为发送者已确认
transactions[_transactionId].numConfirmations++; // 增加确认计数
// 如果满足所需确认数量,则执行交易
if (transactions[_transactionId].numConfirmations >= numConfirmationsRequired) {
executeTransaction(_transactionId);
}
}
function executeTransaction(uint _transactionId) public onlyOwner {
require(_transactionId < transactions.length, "Invalid transaction ID.");
require(!transactions[_transactionId].executed, "Transaction has already been executed.");
Transaction storage transaction = transactions[_transactionId];
transaction.executed = true; // 标记交易为已执行
(bool success, ) = transaction.to.call{value: transaction.value}(""); // 执行交易
require(success, "Transaction execution failed."); // 确保交易成功
}
}
这个多重签名钱包合约提供了一种稳健的资金管理机制,要求多个所有者批准交易才能执行。可以通过增加撤销确认或添加/删除所有者等功能进一步增强安全性和灵活性。
2.众筹合约:
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; // 指定使用的 Solidity 版本
contract Crowdfunding {
struct Project {
address owner; // 项目拥有者的地址
string name; // 项目名称
uint goalAmount; // 项目的筹款目标
uint amountRaised; // 已筹集的总金额
bool closed; // 指示项目是否关闭接受捐款
mapping(address => uint) contributions; // 每个地址的捐款记录
}
Project[] public projects; // 存储所有项目的数组
// 创建新众筹项目的函数
function createProject(string memory _name, uint _goalAmount) public {
projects.push(Project({
owner: msg.sender, // 将调用函数的地址设置为项目拥有者
name: _name, // 项目名称
goalAmount: _goalAmount, // 筹款目标
amountRaised: 0, // 初始筹集金额为零
closed: false // 项目默认开放接受捐款
}));
}
// 向项目捐款的函数
function contribute(uint _projectId) public payable {
require(_projectId < projects.length, "Invalid project ID."); // 确保项目存在
require(msg.value > 0, "Contribution amount must be greater than zero."); // 确保捐款金额大于零
require(!projects[_projectId].closed, "Project is closed for contributions."); // 确保项目未关闭
projects[_projectId].contributions[msg.sender] += msg.value; // 记录捐款
projects[_projectId].amountRaised += msg.value; // 更新已筹集的总金额
}
// 关闭项目的函数
function closeProject(uint _projectId) public {
require(_projectId < projects.length, "Invalid project ID."); // 确保项目存在
require(msg.sender == projects[_projectId].owner, "Only project owner can close the project."); // 只有拥有者才能关闭项目
projects[_projectId].closed = true; // 将项目标记为已关闭
}
// 提取项目资金的函数
function withdrawFunds(uint _projectId) public {
require(_projectId < projects.length, "Invalid project ID."); // 确保项目存在
require(msg.sender == projects[_projectId].owner, "Only project owner can withdraw funds."); // 只有拥有者才能提取资金
require(projects[_projectId].amountRaised >= projects[_projectId].goalAmount, "Goal amount has not been reached yet."); // 确保已达成筹款目标
uint amountToWithdraw = projects[_projectId].amountRaised; // 要提取的金额
projects[_projectId].amountRaised = 0; // 将已筹集金额重置为零
payable(msg.sender).transfer(amountToWithdraw); // 将资金转移给拥有者
}
}
所提供的众筹合约作为一个基本框架,用于在以太坊区块链上管理众筹项目。通过上述改进和考虑,可以增强合约的安全性、可用性和功能性
希望该篇文章可以帮助到正在学习solidity的朋友哦。