├── README.md ├── contract └── Supplychain.sol ├── img ├── Alice.png ├── BaomaSign.png ├── BaomaSign2.png ├── IssueReceipt.png ├── IssueReceiptEvent.png ├── LunGuReceipt.png ├── LunTaiAfterTransfer.png ├── Transfer.png ├── addBank.png ├── chaoedaikuan.png ├── daikuan.png ├── pay.png ├── paysome.png └── 架构.png ├── report.md └── webfront ├── .gitignore ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── public ├── favicon.ico └── index.html └── src ├── App.vue ├── assets └── logo.png ├── components ├── HelloWorld.vue └── index.vue ├── main.js ├── router └── index.js └── views └── Login.vue /README.md: -------------------------------------------------------------------------------- 1 | # FISCO-Supplychain 2 | 基于FISCO-BCOS区块链系统的供应链金融平台 3 | -------------------------------------------------------------------------------- /contract/Supplychain.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.22 <0.6.0; 2 | // pragma solidity ^0.5.11; 3 | pragma experimental ABIEncoderV2; 4 | contract Supplychain{ 5 | struct Company{ 6 | string name; 7 | address ad; 8 | uint creditRating; 9 | } 10 | 11 | struct Receipt{ 12 | uint id; 13 | address owner; 14 | address client; 15 | uint amount; 16 | uint start; 17 | uint ddl; 18 | // uint rank; 19 | bool usedLoan; 20 | string description; 21 | } 22 | 23 | //等待签署的应收款单据 24 | mapping(uint => Receipt) public pending; 25 | 26 | Company[] companys; 27 | Company[] public banks; 28 | 29 | //公司到应收帐款的映射 30 | mapping(address => Receipt[]) public receipts; 31 | 32 | //应收款单据编号 1,2,3,... 33 | uint rid; 34 | 35 | event ReceiptIssued(address owner, string desc); 36 | event ReceiptSigned(address who, string desc); 37 | event Transfered(address fromadd, address toadd,uint amount,string desc); 38 | event Loaned(address who, uint amount,string desc); 39 | event pay(address fromadd,address toadd,uint amount, string desc); 40 | 41 | constructor() public { 42 | rid = 1; 43 | } 44 | 45 | 46 | 47 | function AddBank(string _name,address _ad)public returns(bool){ 48 | banks.push(Company(_name,_ad,0)); 49 | return true; 50 | } 51 | 52 | //公司发起应收款单据 53 | function IssueReceipt(address owner, address client, uint amount,uint ddl) public returns(uint id_){ 54 | require(msg.sender==owner); 55 | pending[rid] = Receipt(rid,msg.sender,client,amount,0,now+ddl,false,""); 56 | id_ = rid; 57 | rid++; 58 | emit ReceiptIssued(owner,"receipt Issued"); 59 | } 60 | 61 | //客户签署应收款单据 62 | function SignReceipt(uint _id)public returns(bool){ 63 | Receipt r = pending[_id]; 64 | //签署人必须是该单据的client 65 | require(r.client == msg.sender,"your don't have permission to sign this receipt."); 66 | //单据未到期 67 | require(now < r.ddl); 68 | receipts[r.owner].push(Receipt(r.id, r.owner, r.client,r.amount,now,r.ddl,false,"")); 69 | emit ReceiptIssued(msg.sender,"receipt signed"); 70 | return true; 71 | } 72 | 73 | // function AddReceipt(address owner, address client, uint amount)public returns(uint id_){ 74 | // receipts[owner].push(Receipt(rid,owner,client,amount,now,now+1000000,false,"")); 75 | // id_ = rid; 76 | // rid++; 77 | // } 78 | 79 | function TransferTo(uint receiptid, address to, uint amount) public returns(uint id_){ 80 | Receipt storage senderReceipt; 81 | for (uint i = 0; i < receipts[msg.sender].length;i++) 82 | { 83 | if (receipts[msg.sender][i].id==receiptid) 84 | { 85 | senderReceipt = receipts[msg.sender][i]; 86 | break; 87 | } 88 | require(i != receipts[msg.sender].length - 1,"no such receipt id."); 89 | } 90 | 91 | require(senderReceipt.amount >= amount && amount > 0); 92 | //转移账款 93 | senderReceipt.amount -=amount; 94 | receipts[to].push(Receipt(rid,to, senderReceipt.client, amount, now,senderReceipt.ddl,false,"")); 95 | id_ = rid; 96 | rid++; 97 | Transfered(msg.sender, to, amount,"transfer successfully"); 98 | } 99 | 100 | function MakeLoan(address loanTo, uint loanAmount, uint receiptid) public returns(bool){ 101 | //放贷款必须是银行 102 | uint cnt = 0; 103 | uint i; 104 | for ( i = 0; i < banks.length; i++) 105 | { 106 | if (banks[i].ad == msg.sender) 107 | { 108 | cnt++; 109 | } 110 | } 111 | require(cnt == 1); 112 | 113 | //找到应收款单据 114 | Receipt storage r; 115 | for (i = 0; i < receipts[loanTo].length;i++) 116 | { 117 | if (receipts[loanTo][i].id==receiptid) 118 | { 119 | r = receipts[loanTo][i]; 120 | break; 121 | } 122 | require(i != receipts[msg.sender].length - 1,"no such receipt id."); 123 | } 124 | 125 | //false 说明该单据已经被用来贷款了 126 | require(r.usedLoan==false,"the receipt has been used for loan"); 127 | require(r.amount >=loanAmount); 128 | r.usedLoan = true; 129 | Loaned(loanTo,loanAmount,"loaned successfully."); 130 | return true; 131 | } 132 | 133 | function PayForReceipt(address owner, uint amount,uint receiptid) public returns(bool){ 134 | Receipt storage r; 135 | uint i; 136 | for (i = 0; i < receipts[owner].length;i++) 137 | { 138 | if (receipts[owner][i].id==receiptid) 139 | { 140 | r = receipts[owner][i]; 141 | break; 142 | } 143 | require(i != receipts[msg.sender].length - 1,"no such receipt id."); 144 | } 145 | 146 | require(r.client == msg.sender,"sender doesn't match receipt's client"); 147 | require(r.amount >= amount,"payment exceeds receipt'amount"); 148 | r.amount -= amount; 149 | if(r.amount > 0) 150 | return true; 151 | for(;i(2019年秋季学期) 2 | 3 | [项目github仓库](https://github.com/HiXinJ/FISCO-Supplychain) 4 | 5 | 课程名称:区块链原理与技术 6 | 7 | 任课教师: 郑子彬 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
年级2017级专业(方向)软件工程
学号17309084姓名王鑫基
电话13395832381Email912940196@qq.com
开始日期2019-11-15完成日期2019-12-
36 | 37 | 38 | 39 | 40 | ## 一、项目背景 41 | 供应链金融案例 42 | 某车企(宝马)因为其造车技术特别牛,消费者口碑好,所以其在同行业中占据绝对优势 地位。因此,在金融机构(银行)对该车企的信用评级将很高,认为他有很大的风险承担的能力。在某次交易中,该车企从轮胎公司购买了一批轮胎,但由于资金暂时短缺向轮胎公司签订了1000万的应收账款单据,承诺1年后归还轮胎公司1000万。这个过程可以拉上金融机构例如银行来对这笔交易作见证,确认这笔交易的真实性。在接下里的几个月里,轮胎公司因为资金短缺需要融资,这个时候它可以凭借跟某车企签订的应收账款单据向金融结构借款,金融机构认可该车企(核心企业)的还款能力,因此愿意借款给轮胎公司。但是,这样的信任关系并不会往下游传递。在某个交易中,轮胎公司从轮毂公司购买了一批轮毂,但由于租金暂时短缺向轮胎公司签订了500万的应收账款单据,承诺1年后归还轮胎公司500万。当轮毂公司想利用这个应收账款单据向金融机构借款融资的时候,金融机构因为不认可轮胎公司的还款能力,需要对轮胎公司进行详细的信用分析以评估其还款能力同时验证应收账款单据的真实性,才能决定是否借款给轮毂公司。这个过程将增加很多经济成本,而这个问题主要是由于该车企的信用无法在整个供应链中传递以及交易信息不透明化所导致的。 43 | 44 | 案例中的问题分析 45 | 1. 小微企业融资难融资贵问题突出 46 | 传统的供应链金融实践通常只能服务到核心企业的直接上下游,供应链条上末端的小微企业较难触达,小微融资难融资贵问题突出。 47 | 2. 金融机构操作风险与成本较高 48 | 金融机构在贸易背景核实、可靠质权、回款控制等方面操作与风险成本均较高,而贸易链条中的企业或平台又难以自证,金融机构开展供应链金融业务的成本、风险和收益较难平衡。 49 | 3. 核心企业参与意愿不足 50 | 金融机构开展供应链金融业务通常仅从金融风险与收益去切入,与企业自身供应链管理优化结合太少,甚至某些方面还形成打扰,造成核心企业参与意愿度低,业务较难开展。 51 | 52 | ## 二、方案设计 53 | ### 1. 解决方案概述 54 | 55 | 针对多级信任难以往下游传递问题,利用区块链打通多级企业之间与金融机构的信息孤岛,企业与金融机构信息安全共享,使得供应链交易信息透明化,依托核心企业信用传递,降低小微企业融资难度。该方案围绕整个供应链企业及银行的金融机构,打造全新供应链金融生态体系,促进多方企业互利共生,促进整个生态良性发展。 56 | 57 | 方案架构简图 58 | ![img](img/架构.png) 59 | 60 | ### 2. 存储设计 61 | address类型为fisco-bcos的账户地址。 62 | 63 | Company 64 | - ad为主键 65 | - 公司名称name 66 | - 信用等级creditRating 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 |
name:stirngad:addresscreditRating:uint
75 | 76 | Receipt 77 | Receipt是应收单据结构,以id为主键 78 | 单据开票公司owner, 79 | 客户client, 80 | 应收款金额amount, 81 | 开票日期start 82 | 到期还款时间:ddl 83 | 是否被用作于向金融机构贷款的信用凭证:usedLoan, 84 | 其它备注、描述:description。 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 |
id:uintowner:addressclient:addressamount:uintstart:uintddl:uintusedLoan:booldescription:string
99 | 100 | ### 3. 数据流图 101 | 102 | ### 4. 核心功能介绍 103 | 104 | #### 发起和签署应收帐款 105 | 106 | ```go 107 | //等待签署的应收款单据 108 | mapping(uint => Receipt) public pending; 109 | //公司到应收帐款的映射 110 | mapping(address => Receipt[]) public receipts; 111 | ``` 112 | pending是单号到收据的映射,存放等待签署到应收款单据。 113 | 收款方发起一个应收款单据,合约会生成一个单号,并将应收款单据放入pending,付款方根据单号签署应收款单据,此时单据正式生效,然后放入receipts中。 114 | 115 | receipts单据收款方地址到Receipt[]的映射。给出一个收款方企业地址,可以方便的找到该企业所有的应收帐款。 116 | ```go 117 | //公司发起应收款单据 118 | function IssueReceipt(address owner, address client, uint amount,uint ddl) public returns(uint id_){ 119 | require(msg.sender==owner); 120 | pending[rid] = Receipt(rid,msg.sender,client,amount,0,now+ddl,false,""); 121 | id_ = rid; 122 | rid++; 123 | emit ReceiptIssued(owner,"receipt Issued"); 124 | } 125 | 126 | //客户签署应收款单据 127 | function SignReceipt(uint _id)public returns(bool){ 128 | Receipt r = pending[_id]; 129 | //签署人必须是该单据的client 130 | require(r.client == msg.sender,"your don't have permission to sign this receipt."); 131 | //单据未到期 132 | require(now < r.ddl); 133 | receipts[r.owner].push(Receipt(r.id, r.owner, r.client,r.amount,now,r.ddl,false,"")); 134 | emit ReceiptIssued(msg.sender,"receipt signed"); 135 | return true; 136 | } 137 | ``` 138 | 139 | #### 应收帐款转移 140 | 有应收帐款的企业可以向其他企业转移部分应收帐款。 141 | ```go 142 | function TransferTo(uint receiptid, address to, uint amount) public returns(uint id_){ 143 | Receipt storage senderReceipt; 144 | for (uint i = 0; i < receipts[msg.sender].length;i++) 145 | { 146 | if (receipts[msg.sender][i].id==receiptid) 147 | { 148 | senderReceipt = receipts[msg.sender][i]; 149 | break; 150 | } 151 | require(i != receipts[msg.sender].length - 1,"no such receipt id."); 152 | } 153 | 154 | require(senderReceipt.amount >= amount && amount > 0); 155 | //转移账款 156 | senderReceipt.amount -=amount; 157 | receipts[to].push(Receipt(rid,to, senderReceipt.client, amount, now,senderReceipt.ddl,false,"")); 158 | id_ = rid; 159 | rid++; 160 | Transfered(msg.sender, to, amount,"transfer successfully"); 161 | } 162 | ``` 163 | 164 | #### 利用应收帐款融资 165 | 在企业向银行申请贷款后,银行可以调用该函数检查企业的应收帐款,如何符合要求则发放贷款。该函数交易上链后记录了企业(loanTo)利用应收帐款(receiptid)贷款这一事实。 166 | ```go 167 | function MakeLoan(address loanTo, uint loanAmount, uint receiptid) public returns(bool){ 168 | //放贷款必须是银行 169 | uint cnt = 0; 170 | uint i; 171 | for ( i = 0; i < banks.length; i++) 172 | { 173 | if (banks[i].ad == msg.sender) 174 | { 175 | cnt++; 176 | } 177 | } 178 | require(cnt == 1); 179 | 180 | //找到应收款单据 181 | Receipt storage r; 182 | for (i = 0; i < receipts[loanTo].length;i++) 183 | { 184 | if (receipts[loanTo][i].id==receiptid) 185 | { 186 | r = receipts[loanTo][i]; 187 | break; 188 | } 189 | require(i != receipts[msg.sender].length - 1,"no such receipt id."); 190 | } 191 | 192 | //false 说明该单据已经被用来贷款了 193 | require(r.usedLoan==false,"the receipt has been used for loan"); 194 | require(r.amount >=loanAmount); 195 | r.usedLoan = true; 196 | Loaned(loanTo,loanAmount,"loaned successfully."); 197 | return true; 198 | } 199 | ``` 200 | 201 | #### 结算应收帐款 202 | 上游企业根据单号,向下游企业支付amount的金额,如何完全结算,该应收款单据会从receipts中删除。 203 | 由于该单据从创建、签署到结算到过程都记录在区块链上,所以从合约都状态变量receitps中删除单据并不影响这一记录。 204 | 205 | ```go 206 | function PayForReceipt(address owner, uint amount,uint receiptid) public returns(bool){ 207 | Receipt storage r; 208 | uint i; 209 | for (i = 0; i < receipts[owner].length;i++) 210 | { 211 | if (receipts[owner][i].id==receiptid) 212 | { 213 | r = receipts[owner][i]; 214 | break; 215 | } 216 | require(i != receipts[msg.sender].length - 1,"no such receipt id."); 217 | } 218 | 219 | require(r.client == msg.sender,"sender doesn't match receipt's client"); 220 | require(r.amount >= amount,"payment exceeds receipt'amount"); 221 | r.amount -= amount; 222 | if(r.amount > 0) 223 | return true; 224 | for(;i 1%", 41 | "last 2 versions" 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /webfront/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HiXinJ/FISCO-Supplychain/c31152576451bf591bc88975518638630737271f/webfront/public/favicon.ico -------------------------------------------------------------------------------- /webfront/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | webfront 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /webfront/src/App.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 24 | 25 | 35 | -------------------------------------------------------------------------------- /webfront/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HiXinJ/FISCO-Supplychain/c31152576451bf591bc88975518638630737271f/webfront/src/assets/logo.png -------------------------------------------------------------------------------- /webfront/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 44 | 45 | 46 | 62 | -------------------------------------------------------------------------------- /webfront/src/components/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 29 | 73 | -------------------------------------------------------------------------------- /webfront/src/main.js: -------------------------------------------------------------------------------- 1 | // import Vue from 'vue' 2 | // import App from './App.vue' 3 | 4 | // Vue.config.productionTip = false 5 | 6 | // new Vue({ 7 | // render: h => h(App), 8 | // }).$mount('#app') 9 | 10 | import Vue from 'vue' 11 | import App from './App' 12 | // import router from './router' 13 | import ElementUI from 'element-ui' 14 | import 'element-ui/lib/theme-chalk/index.css' 15 | Vue.use(ElementUI) 16 | Vue.config.productionTip = false 17 | new Vue({ 18 | render: h => h(App), 19 | 20 | }).$mount('#app') -------------------------------------------------------------------------------- /webfront/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import index from '@/components/index' 4 | // import Login from '@/views/Login' 5 | 6 | Vue.use(Router) 7 | 8 | export default new Router({ 9 | routes: [ 10 | { 11 | path: '/', 12 | name: 'index', 13 | component: index 14 | }, 15 | ], 16 | // mode: 'hash' 17 | }) 18 | -------------------------------------------------------------------------------- /webfront/src/views/Login.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 76 | 77 | --------------------------------------------------------------------------------