Roles: 实现对用户地址的角色权限管控,添加、删除角色。
Producer: 生产商角色管控。
...
FoodInfoItem: 食品信息管控。生产商、中间商、超市添加食品信息。
Trace:食品溯源合约,主要负责对以上几个合约的统筹协作。
// SPDX-License-Identifier: MIT
pragma solidity >=0.4 <=0.9;
//角色库(管理所有角色地址)
// 1. 实现增加角色地址
// 2. 移除角色地址
// 3. 判断角色地址是否被授权
library Roles{
struct Role{
mapping (address =>bool) bearer;
}
// 在 Solidity 中,映射(mapping)不能在函数内部声明为局部变量,
// 也不能在当前版本(0.8.0)中作为库(library)的成员变量。
// 假如role 显示声明storage,那么算是合约中的状态变量,而且不能是memory
function add(Role storage role,address account) public {
require(!has(role,account),"Roles:account already has role");
role.bearer[account] = true;
}
function remove(Role storage role,address account) public {
require(!has(role,account),"Roles:account has no role ");
role.bearer[account] = false;
}
function has(Role storage role,address account) public view returns(bool){
require(account != address(0),"Roles: account cannot be zero address");
return role.bearer[account];
}
}
PS:这下面这三个都是代表角色,代码几乎一样的,看会这个,其他都会。
// SPDX-License-Identifier: MIT
pragma solidity >=0.4 <=0.9;
import "./Roles.sol";
/**
*@title Producer
*@dev
*/
contract Producer {
using Roles for Roles.Role;
event ProducerAdded(address indexed account);
event ProducerRemoved(address indexed account);
Roles.Role private _producers; // 使用这个相当于使用库
constructor(address producer){ // 初始化给账户添加权限
_addProducer(producer);
}
// 关于下面这几个函数为什么要拆分?提高代码可读性。
modifier onlyProducer(){
require(
isProducer(msg.sender),
"Producer:caller has no Producer role"
);
_;
}
// 用户是否拥有权限
function isProducer(address account) public view returns (bool) {
return _producers.has(account);
}
function addProducer(address account) public onlyProducer {
_addProducer(account); // 不是很理解,为什么设置只有生产者角色才能为地址添加生产者角色权限
}
function removeRroducer(address account) public {
_removeProducer(account);
}
function _addProducer(address account) internal {
_producers.add(account);
// 我们看向Roles的add()其实还有一个参数,但是我们 using for 了那个参数就相当于 _producers本身
emit ProducerAdded(account);
}
function _removeProducer(address account) internal {
_producers.remove(account);
emit ProducerRemoved(account);
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.4 <=0.9;
import "./Roles.sol";
// 超市
contract Retailer {
using Roles for Roles.Role;
event RetailerAdded(address indexed account);
event RetailerRemoved(address indexed account);
Roles.Role private _retailers; // 使用这个相当于使用库
constructor(address retailer){ // 初始化给账户添加权限
_addRetailer(retailer);
}
// 关于下面这几个函数为什么要拆分?提高代码可读性。
modifier onlyRetailer(){
require(
isRetailer(msg.sender),
"Retailer:caller has no Retailer role"
);
_;
}
// 用户是否拥有权限
function isRetailer(address account) public view returns (bool) {
return _retailers.has(account);
}
function addRetailer(address account) public onlyRetailer {
_addRetailer(account);
}
function removeRroducer(address account) public {
_removeRetailer(account);
}
function _addRetailer(address account) internal {
_retailers.add(account);
// 我们看向Roles的add()其实还有一个参数,但是我们 using for 了那个参数就相当于 _Retailers本身
emit RetailerAdded(account);
}
function _removeRetailer(address account) internal {
_retailers.remove(account);
emit RetailerRemoved(account);
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.4 <=0.9;
import "./Roles.sol";
// 中间商
contract Distributor {
using Roles for Roles.Role;
event DistributorAdded(address indexed account);
event DistributorRemoved(address indexed account);
Roles.Role private _distributors; // 使用这个相当于使用库
constructor(address distributor){ // 初始化给账户添加权限
_addDistributor(distributor);
}
// 关于下面这几个函数为什么要拆分?提高代码可读性。
modifier onlyDistributor(){
require(
isDistributor(msg.sender),
"Distributor:caller has no Distributor role"
);
_;
}
// 用户是否拥有权限
function isDistributor(address account) public view returns (bool) {
return _distributors.has(account);
}
function addDistributor(address account) public onlyDistributor {
_addDistributor(account);
}
function removeRroducer(address account) public {
_removeDistributor(account);
}
function _addDistributor(address account) internal {
_distributors.add(account);
// 我们看向Roles的add()其实还有一个参数,但是我们 using for 了那个参数就相当于 _Distributors本身
emit DistributorAdded(account);
}
function _removeDistributor(address account) internal {
_distributors.remove(account);
emit DistributorRemoved(account);
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.4 <=0.9;
pragma experimental ABIEncoderV2;
//食品信息管理合约
// 1. 保存食品基本信息:时间戳(流转过程中),用户名(流转过程中),用户地址信息(流转过程中),食品质量(流转过程中),食物名称,当前用户名称,质量,状态.
// 2. 对食品基本信息进行初始化
// 3. 实现两个方法:中间商添加食品信息;超市添加食品信息
// 4. 实现显示食品信息的方法
contract FoodInfoItem {
uint[] _timestamp; //保存食品流转过程中各个阶段的时间戳
string[] _traceName; //保存食品流转过程各个阶段的用户名
address[] _traceAddress; //保存食品流转过程各个阶段的用户地址信息(和用户一一对应)
uint8[] _traceQuality; //保存食品流转过程中各个阶段的质量
string _name; //食品名称
string _currentTraceName; //当前用户名称
uint8 _quality; //质量(0=优质 1=合格 2=不合格)
uint8 _status; //状态(0:生产 1:分销 2:出售)
address _owner;
// 初始化食品,创建者是生产商
constructor(string memory name,string memory traceName,uint8 quality,address producer) public {
_name = name;
_currentTraceName = traceName;
_quality = quality;
_owner = producer;
_status = 0;
// 不多说,看上面状态变量都能明白
_timestamp.push(block.timestamp);
_traceName.push(traceName);
_traceAddress.push(producer);
_traceQuality.push(quality);
}
// 中间商添加食品信息
function addTraceInfoByDistributor(
string memory traceName,
uint8 quality,
address distributor
) public returns(bool){
require(_status == 0, "FoddIndo: caller must be distributor");
_currentTraceName = traceName;
_quality = quality;
_status = 1;
_timestamp.push(block.timestamp);
_traceName.push(traceName);
_traceAddress.push(distributor);
_traceQuality.push(quality);
return true;
}
// 超市添加食品信息
function addTraceInfoByRetailer(
string memory traceName,
uint8 quality,
address retailer
)public returns(bool){
require(_status == 1, "FoddIndo: caller must be retailer");
_currentTraceName = traceName;
_quality = quality;
_status = 2;
_timestamp.push(block.timestamp);
_traceName.push(traceName);
_traceAddress.push(retailer);
_traceQuality.push(quality);
return true;
}
// 拿到食品流转的全部信息
function getTraceInfo() public view returns(uint[] memory,string[] memory,address[] memory,uint8[] memory){
return (
_timestamp,
_traceName,
_traceAddress,
_traceQuality
);
}
// 拿到生产商一开始添加食品信息
function getFood() public view returns(uint,string memory,address,uint8,string memory){
return (
_timestamp[0],
_traceName[0],
_traceAddress[0],
_traceQuality[0],
_name
);
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
pragma experimental ABIEncoderV2; // 开启实验性功能,包括对map,数组的编码和解码等
import "./FoodInfoItem.sol";
import "./Distributor.sol";
import "./Producer.sol";
import "./Retailer.sol";
//食品溯源合约(负责具体食品溯源信息的生成)
// 1.实现生产食品的方法(新建食品信息)
// 2.实现食品分销过程中增加溯源信息的接口
// 3.实现食品出售过程中增加溯源信息的接口
// 4.实现获取食品溯源信息接口
contract Trace is Distributor,Producer,Retailer {
mapping(uint256 => address) foods; //食品溯源id到 -> 具体食品溯源合约的映射表
uint[] foodList; // 食品溯源id数组
//构造函数初始化,一起把父类角色初始化
constructor(
address producer,
address distributor,
address retailer
) Producer(producer) Distributor(distributor) Retailer(retailer) {}
// 生产商调用,调用添加食品信息
function newFood(
string memory name,
uint256 traceNumber, // 溯源id
string memory traceName,
uint8 quality
) public onlyProducer returns (address) {
require(foods[traceNumber] == address(0), "Trace:traceNumber already exist"); // 检测溯源id对应食品合约是否已经存在,已存在id不能用。
FoodInfoItem food = new FoodInfoItem( // 初始化食品合约
name,
traceName,
quality,
msg.sender
);
foods[traceNumber] = address(food); // 往映射表添加地址
foodList.push(traceNumber); // 往食品溯源数组添加溯源id
return address(food);
}
// 中间商调用,添加食品信息
function addTraceInfoByDistributor(
uint256 traceNumber,
string memory traceName,
uint8 quality
) public onlyDistributor returns (bool) {
require(foods[traceNumber] != address(0), "Trace:traceNumber does not exist"); // id 对应食品合约没存在,代表没食品
return
FoodInfoItem(foods[traceNumber]).addTraceInfoByDistributor(traceName,quality,msg.sender); // 调用对应的食品合约方法
}
// 超市调用,添加食品信息
function addTraceInfoByRetailer(
uint256 traceNumber,
string memory traceName,
uint8 quality
) public onlyRetailer returns (bool) {
require(foods[traceNumber] != address(0), "Trace:traceNumber does not exist");
return
FoodInfoItem(foods[traceNumber]).addTraceInfoByRetailer(traceName,quality,msg.sender);
}
// 拿到所有食品信息
function getTraceInfo(
uint256 traceNumber
) public view returns (uint[] memory,string[] memory,address[] memory,uint8[] memory) {
require(foods[traceNumber] != address(0), "Trace:traceNumber does not exist");
return FoodInfoItem(foods[traceNumber]).getTraceInfo();
}
//拿到单条食品信息
function getFood(
uint256 traceNumber
) public view returns (uint,string memory,address,uint8,string memory) {
require(foods[traceNumber] != address(0), "Trace:traceNumber does not exist");
return FoodInfoItem(foods[traceNumber]).getFood();
}
// 拿到全部食品的溯源id数组
function getAllFood() public view returns (uint[] memory) {
return foodList;
}
}