食品溯源合约 -- 智能合约实例

前提

Roles: 实现对用户地址的角色权限管控,添加、删除角色。

Producer: 生产商角色管控。

...

FoodInfoItem: 食品信息管控。生产商、中间商、超市添加食品信息。

Trace:食品溯源合约,主要负责对以上几个合约的统筹协

Roles

// 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) internal {   
        require(!has(role,account),"Roles:account already has role");
        role.bearer[account] = true;
    }

    function remove(Role storage role,address account) internal {
        require(!has(role,"Roles:account has no role ");
        role.bearer[account] = false;
    }

    function has(Role storage role,address account) internal  view returns(bool){
        require(account != address(0),"Roles: account cannot be zero address");
        return role.bearer[account];
    }

}

Producer

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);
    }
    
}

Retailer

// 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);
    }
    
}

Distributor

// 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);
    }
    
}

FoodInfoItem

// 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,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,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
        );
    }

}


Trace

// 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,uint8 quality
    ) public onlyDistributor returns (bool) {
        require(foods[traceNumber] != address(0),"Trace:traceNumber does not exist"); // id 对应食品合约没存在,代表没食品
        return
            FoodInfoItem(foods[traceNumber]).addTraceInfoByDistributor(traceName,msg.sender); // 调用对应的食品合约方法
    }

   // 超市调用,添加食品信息
    function addTraceInfoByRetailer(
        uint256 traceNumber,uint8 quality
    ) public onlyRetailer returns (bool) {
        require(foods[traceNumber] != address(0),"Trace:traceNumber does not exist");
        return
            FoodInfoItem(foods[traceNumber]).addTraceInfoByRetailer(traceName,msg.sender);
    }

    // 拿到所有食品信息
    function getTraceInfo(
        uint256 traceNumber
    ) public view returns (uint[] 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) {
        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;
    }

}

核心流程演示

1.创建Trace合约,赋予三个地址生产商、中间商、超市权限。

2.利用上述producer地址,调用newFood接口

结果成功,我就不演示了。

3.利用上述distributor地址,调用addTraceInfoByDistributor接口

4.利用上述retailer地址,调用addTraceInfoByRetailer接口

原文地址:https://blog.csdn.net/Qhx20040819/article/details/132122475

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读903次。文章主要介绍了收益聚合器Beefy协议在币安智能链测试网网上的编译测试部署流程,以Pancake上的USDC-BUSD最新Curve版流动池的农场质押为例,详细介绍了完整的操作流程。_怎么在bsc网络上部署应用
文章浏览阅读952次。比特币的主要思路是,构建一个无中心、去信任的分布式记账系统。交易签名只能保证交易不是他人伪造的,却不能阻止交易的发起者自己进行多重交易,即交易的发起者将一个比特币同时转账给两个人,也就是所谓的双花。比特币应用的区块链场景也叫做公链,因为这个区块链对所有人都是公开的。除此之外,还有一种区块链应用场景,被称作联盟链。区块链的出现,使得低成本,去信任的跨组织合作成为可能,将重构组织间的关系,这个关系既包括企业间的关系,也包括政府和企业间的关系,还有政府部门间的关系。
文章浏览阅读2.5k次。虚拟人从最初的不温不火,到现在步入“出生高峰期”,元宇宙可以说是功不可没。此前,量子位发布了《虚拟数字人深度产业报告》,报告显示,到2030年我国虚拟数字人整体市场规模将达到2700亿元。其中,“身份型虚拟人”市场规模预计达到1750亿元,占主导地位,而“服务型虚拟人”总规模也将超过950亿元。得益于AI、VR/AR 等技术的发展,虚拟人的应用场景正在从传统的虚拟偶像等娱乐行业迈向更多元化的领域。_最喜欢的虚拟角色
文章浏览阅读1.3k次,点赞25次,收藏13次。通过调查和分析用户需求、兴趣和行为,你可以更好地定位你的目标受众,并在市场中找到你的定位。在设计你的Web3.0项目时,注重用户界面的友好性、交互流畅性和功能的创新性,以提供独特的用户体验。通过与有影响力的人或组织进行合作,推广你的Web3.0项目。通过与他们分享你的项目并抓住他们的推荐,可以迅速获得更多的关注度。通过优化你的网站和内容,将有助于提高你的排名,并增加有机流量。通过提供奖励激励计划,如空投、奖励机制等,激励用户参与你的Web3.0项目。的人或组织合作,可以增加你的项目的曝光度。
文章浏览阅读1.7k次。这个智能合约安全系列提供了一个广泛的列表,列出了在 Solidity 智能合约中容易反复出现的问题和漏洞。Solidity 中的安全问题可以归结为智能合约的行为方式不符合它们的意图。我们不可能对所有可能出错的事情做一个全面的列表。然而,正如传统的软件工程有常见的漏洞主题,如 SQL 注入、缓冲区超限和跨网站脚本,智能合约中也有反复出现的。_solidity安全漏洞
文章浏览阅读1.3k次。本文描述了比特币核心的编译与交互方法_编译比特币
文章浏览阅读884次。四水归堂,是中国建筑艺术中的一种独特形式。这种形式下,由四面房屋围出一个天井,房屋内侧坡向天井内倾斜,下雨时雨水会从东西南北四方流入天井,从而起到收集水源,防涝护屋的作用,寓意水聚天心,天人合一。在科技产业当中,很多时候我们需要学习古人的智慧与意蕴,尝试打通各个生态,聚四方之力为我所用,这样才能为最终用户带来最大化价值。随着数字化、智能化的发展,算力成为生产力的根基。在这一大背景下,算力需要贯通软..._超聚变csdn
文章浏览阅读1k次,点赞24次,收藏19次。云计算和区块链是当代科技领域两个备受关注的核心技术。本文将深入探讨云计算和区块链的发展历程,详细剖析其起初阶段的奠基、面临的问题、业务内容、当前研究方向、用到的技术、实际应用场景、未来发展趋势,并提供相关链接供读者深入了解。
文章浏览阅读1.5k次。融入对等网络的奥妙,了解集中式、全分布式和混合式对等网络的差异,以及区块链网络的结构与协议,让你跃入区块链的连结网络。揭开密码学的神秘面纱,探寻对称密码学、非对称密码学、哈希函数、数字签名等关键技术,让你了解信息安全的核心。解码共识算法的精髓,从理论到实践,从PoW、PoS到PBFT,让你深入了解区块链如何达成共识。探索智能合约的世界,从定义到生命周期,从执行引擎到开发与部署,带你进入无限可能的合约领域。了解令人惊叹的区块链世界,从概念到价值,从发展历程到政策法规,一篇章串联出区块链的精髓。
文章浏览阅读777次。8 月份,加密货币市场经历了明显的波动,比特币价格波动幅度较大。与此同时,NFT 市场出现大幅下跌,引发了人们对这一新兴行业未来发展趋势的担忧
文章浏览阅读8.8k次,点赞53次,收藏37次。近二十年来,我国信息科技发展日益成熟,出现的网络完全问题也是“百花齐放”。而元宇宙作为5G技术、AR/VR技术、云计算以及区块链等技术的组合体,其安全性指定会被人们所广泛关注。根据前面所讲,元宇宙融合了虚拟世界和现实世界,通过数据将现实世界的各种元素映射到数字化的虚拟世界中。所以没有数据,就等于没有元宇宙的一切;没有信息安全,元宇宙的社会生产、生活就不能正常有序地进行。所以足以可见数据安全、信息安全对元宇宙发展起到的重要作用!!_元宇宙 安全计算
文章浏览阅读1.4k次。最早使用历史 1991年采用 时间戳 追溯 数字文档,之后 2009年后创始人**中本聪** (satoshi nakamoto )日裔美国人,在设计比特币数字货币中将此理念写入应用程序中_web3.0学习
文章浏览阅读1.7k次。DeFi收益来源全面概述_drfi收益
文章浏览阅读941次,点赞17次,收藏21次。号外:教链内参1.28《从BTC现货ETF的近期数据看到的》隔夜BTC经历现货ETF通过后的情绪冷静,一度破位40k后又逐渐修复至42k上方。请珍惜42k的BTC吧。也许到下个周期,我们将不再有机会见到这个高度的BTC了。下面,让我们重温,42k的BTC,在过去四年穿越牛熊的过程中,带给我们的启迪吧。需要提醒的是,历史文字,自有历史局限性,回顾,也须带着批判性的目光阅读和审视。2021年2月8日,...
文章浏览阅读1.2k次,点赞23次,收藏21次。其实一开始我也是这么想的,但根据PoW算法机制,如果你的计算量不够大,是无法控制区块链的走向的,也就是说,即使你投入了大量的成本用于完成任务,也不能保证自己成功。例如,你持有100个币,总共持有了30天,那么,此时你的币龄就为3000,这个时候,如果你发现了一个PoS区块,那么你的币龄就会被减去一定的值,每减少365个币龄,将会从区块中获得0.05个币的利息(可理解为年利率5%),那么在这个案例中,利息=3000×5%/365=0.41个币。前面说过,谁的算力强,谁最先解决问题的概率就越大。
文章浏览阅读1.9k次。这里主要实现的部分继续下去,对 Blockchain 这个对象有一些修改,如果使用 TS 的话可能要修改对应的 interface,但是如果是 JS 的话就无所谓了。需要安装的依赖有:express现在的 express 已经不内置 body-parser,需要作为单独的依赖下载request不下载会报错,是使用 request-promise 所需要的依赖和已经 deprecated 了,具体 reference 可以参考。_js区块链
文章浏览阅读1k次,点赞19次,收藏19次。作者:Zach Pandl Grayscale编译:象牙山首席村民 碳链价值以太坊在2023年取得了丰厚的回报。但表现不如比特币以及其他一些智能合约公链代币。我们认为,这反映了今年比特币特有的积极因素以及以太坊链上活动的缓慢复苏。尽管以太坊的涨幅低于比特币,但从绝对值和风险调整值来看,今年以太坊的表现优于传统资产类别。以太坊不断增长的L2生态系统的发展可能会吸引新用户,并在2024年支撑以太币的...
文章浏览阅读908次,点赞20次,收藏20次。通证是以数字形式存在,代表的是一种权利、一种固有和内在的价值。徐教授告诉我:多年的职业经历,多年的为易货贸易的思考,认识到在处理贸易和经济领域的关系时,应以提高人民生活水平、保证社会成员充分就业、保证就业成员实际收入和有效需求的大幅稳定增长、实现世界资源的充分利用以及扩大货物的生产和交换为目的,期望通过达成互惠互利安排,实行公开、公平、公正的“三公原则”,开展国家与国家、企业与企业之间的易货贸易,规避因信用问题引起的各类风险,消除国际贸易中的歧视待遇,促进全球国家的经济发展,从而为实现上述目标做出贡献。
文章浏览阅读2.5k次。由于webase文档原因,查找起来比较局限,有时候想找一个api却又忘了在哪个模块的目录下,需要一步一步单独点,而利用文档自带的检索功能又因为查找文档全部信息,显得十分缓慢,所以整理了有关WeBASE的api列表但不可否认,现在只有列表,没有对应的页面跳转,文章目的也只是为了多了解webase的接口_webase私钥管理里获取
文章浏览阅读1.4k次,点赞28次,收藏21次。基于​openzeppelin来构建我们的NFT,并用一个例子来手把手的说明如何在opensea快速发布自己的NFT智能合约(ERC721)。