├── README.md └── SupplyChain.sol /README.md: -------------------------------------------------------------------------------- 1 | # Contract-SupplyChain 2 | 3 | 基于Solidity语言的,适用于供应链溯源场景的智能合约示例 4 | 5 | # 场景描述 6 | 7 | 供应链溯源合约有以下几类参与方: 8 | 9 | - 商品厂商:保存于`mapping(address => User) producerMap` 10 | - 各级经销商:保存于`mapping(address => User) retailerMap` 11 | - 消费者:保存于`mapping(address => User) customerMap` 12 | 13 | 各类参与方均通过`newUser`方法进行上链登记。通过传递不同的Actor值来指定不同参与方。 14 | 15 | 厂商首先通过`newProduct`方法将出厂商品登记到区块链,随后商品分销到下一级经销商,接下来的环节,每一次商品的分销均在接收商品的经销商处调用`retailerInnerTransfer`方法将商品进行上链登记,最终商品在零售商处由消费者购买,调用`fromRetailerToCustomer`方法进行最终登记,完成整个出厂-多级分销-零售的流程。商品一旦由厂商登记上链,便可通过`getCommodity`查询到商品当前的分销信息,只有处于该分销路径上的参与方才允许查询。此外,通过`addWhiteList`可以为指定参与方添加顶级查询权限,被添加到WhiteList的参与方,即使不参与到某商品的分销路径中,也可查询到该商品的分销信息。 16 | 17 | -------------------------------------------------------------------------------- /SupplyChain.sol: -------------------------------------------------------------------------------- 1 | contract SupplyChain { 2 | enum Actor{ Others, Producer, Retailer, Customer} 3 | enum Commoditytype{ Wine, Jewelry, Shrimp, Others} 4 | enum Phase{ Supplier, Producer, Dealer, Retailer, Customer} 5 | 6 | struct User{ 7 | bytes32 ID; 8 | bytes32 name; 9 | Actor actor; 10 | } 11 | 12 | struct Commodity{ 13 | bytes32 commodityID; 14 | bytes32 commodityName; 15 | uint produceTime; 16 | bytes32 producerName; 17 | uint[] timestamps; 18 | bytes32[] retailerNames; 19 | uint sellTime; 20 | bytes32 customerName; 21 | bool isBinding; 22 | address owner; 23 | } 24 | 25 | mapping(address => User) producerMap; 26 | mapping(address => User) retailerMap; 27 | mapping(address => User) customerMap; 28 | mapping(bytes32 => Commodity) commodityMap; 29 | mapping(address => bool) whiteList; 30 | address owner; 31 | 32 | function SupplyChain(){ 33 | owner = msg.sender; 34 | whiteList[owner] = true; 35 | } 36 | 37 | function addWhiteList(address addr){ 38 | whiteList[addr] = true; 39 | } 40 | 41 | function newUser(bytes32 ID, bytes32 name,Actor actor) returns(bool, string){ 42 | User user; 43 | 44 | if(actor == Actor.Producer){ 45 | user = producerMap[msg.sender]; 46 | }else if(actor == Actor.Retailer){ 47 | user = retailerMap[msg.sender]; 48 | }else if(actor == Actor.Customer){ 49 | user = customerMap[msg.sender]; 50 | }else{ 51 | return (false,"the actor is not belong"); 52 | } 53 | 54 | if(user.ID != 0x0){ 55 | return (false, "this ID has been occupied!"); 56 | } 57 | user.ID = ID; 58 | user.name = name; 59 | user.actor = actor; 60 | return (true, "Success"); 61 | } 62 | 63 | // this interface just for producer 64 | function newProduct(bytes32 commodityID, bytes32 commodityName, 65 | uint timestamp) returns(bool,bytes32){ 66 | Commodity commodity = commodityMap[commodityID]; 67 | if(commodity.commodityID != 0x0) { 68 | return (false,"The commodityID already exist!"); 69 | } 70 | User user = producerMap[msg.sender]; 71 | if(user.ID == 0x0) { 72 | return (false,"The producer don't exist!"); 73 | } 74 | commodity.commodityID = commodityID; 75 | commodity.commodityName = commodityName; 76 | commodity.produceTime = timestamp; 77 | commodity.producerName = user.name; 78 | return (true,"Success,produce a new product"); 79 | } 80 | 81 | 82 | // this interface just for retailer 83 | function retailerInnerTransfer(bytes32 commodityID,uint timestamp) returns(bool, string){ 84 | Commodity commodity = commodityMap[commodityID]; 85 | if(commodity.commodityID == 0x0) { 86 | return (false,"The commodityID don't exist!"); 87 | } 88 | User user = retailerMap[msg.sender]; 89 | if(user.ID == 0x0) { 90 | return (false,"The retailer don't exist!"); 91 | } 92 | commodity.timestamps.push(timestamp); 93 | commodity.retailerNames.push( user.name ); 94 | return (true,"Success"); 95 | } 96 | 97 | function fromRetailerToCustomer(bytes32 commodityID,uint timestamp) returns(bool, string){ 98 | Commodity commodity = commodityMap[commodityID]; 99 | if(commodity.commodityID == 0x0) { 100 | return (false,"The commodityID don't exist!"); 101 | } 102 | commodity.sellTime = timestamp; 103 | return (true,"Success,Has been sold"); 104 | } 105 | 106 | // just for Supervision organization 107 | function getCommodityRecordsByWhiteList(bytes32 commodityID) returns(bool,string, 108 | bytes32 producerName,uint produceTime, bytes32[] retailerNames,uint[] retailerTimes 109 | , bytes32 customerName,uint sellTime){ 110 | if(!whiteList[msg.sender]){ 111 | return (false,"you has no access",producerName, produceTime, retailerNames, retailerTimes, customerName,commodity.sellTime); 112 | } 113 | Commodity commodity = commodityMap[commodityID]; 114 | if(commodity.commodityID == 0x0){ 115 | return (false,"The commodityID is not exist",producerName, produceTime, retailerNames, retailerTimes,customerName,commodity.sellTime); 116 | } 117 | return (true,"Success",commodity.producerName, commodity.produceTime, commodity.retailerNames, commodity.timestamps, commodity.customerName,commodity.sellTime); 118 | } 119 | 120 | 121 | function getCommodity(bytes32 commodityID,Actor actor) returns(bool,string, 122 | bytes32 producerName,uint produceTime,bytes32[] retailerNames,uint[] retailerTimes 123 | , bytes32 customerName,uint sellTime){ 124 | Commodity commodity = commodityMap[commodityID]; 125 | if(commodity.commodityID == 0x0){ 126 | return (false,"The commodityID is not exist",producerName,produceTime, 127 | retailerNames,retailerTimes,customerName,sellTime); 128 | } 129 | User user; 130 | if(actor == Actor.Producer){ 131 | user = producerMap[msg.sender]; 132 | }else if(actor == Actor.Retailer){ 133 | user = retailerMap[msg.sender]; 134 | }else if(actor == Actor.Customer){ 135 | user = customerMap[msg.sender]; 136 | }else{ 137 | return (false,"the actor is not belong",producerName,produceTime, 138 | retailerNames,retailerTimes,customerName,sellTime); 139 | } 140 | if(commodity.isBinding){ 141 | if(commodity.owner != msg.sender){ 142 | return (false,"warning,this commodity has been bound",producerName,produceTime, 143 | retailerNames,retailerTimes,customerName,sellTime); 144 | }else{ 145 | (false,"has already bind",commodity.producerName,commodity.retailerNames,commodity.customerName); 146 | } 147 | } 148 | if(commodity.sellTime > 0 ) { 149 | commodity.isBinding = true; 150 | commodity.owner = msg.sender; 151 | commodity.customerName = user.name; 152 | } 153 | return (true,"Success",commodity.producerName,commodity.produceTime,commodity.retailerNames,commodity.timestamps,commodity.customerName,commodity.sellTime); 154 | } 155 | } 156 | --------------------------------------------------------------------------------