目录
一、项目背景 1
1.1 供应链+金融场景 1
1.2 功能需求分析 2
二、方案设计 2
2.1 存储设计 2
我们使用一个列表来保存所有的债权凭证 3
2.2 基本功能 3
企业注册(该方法仅限部署该合约的认证机构调用) 4
2.3 核心功能 9
2.4 前端实现 13
2.5后端实现 16
实现智能合约方法调用接口:使用前端传过来的方法名作为索引调用方法 17
2.6编译部署 18
三、功能测试 21
3.1 功能一 22
3.2 功能二 25
3.3 功能三 29
3.4 功能四 33
四、界面展示 37
一、项目背景
1.1 供应链+金融场景
供应链(Supply Chain)是指生产及流通过程中,涉及将产品或服务提供给最终用户活动的上游与下游企业所形成的网链结构。
金融机构对不同企业的的信用评级不同,核心企业有很大的风险承担的能力,故信用评级会高于一般企业。在供应链场景中,核心企业由于资金暂时短缺向下流普通公司签订了应收账款单据,约定某个时间后还款,这个过程可以由金融机构来作见证,从而确认这笔交易的真实性。在这段时间内,若掌握核心企业”欠条”的普通企业资金短缺需要融资,它可以凭借跟核心企业签订的应收账款单据向金融结构借款,但这样的信任关系并不会往下游传递。
这种不信任关系一直沿着下游的普通企业传播,需要金融机构不断往上验证真实性,导致这个过程增加很多经济成本。导致这个问题的根本原因是核心企业的信用无法在整个供应链中传递以及交易信息不透明化所导致的。
如果我们结合区块链技术,将供应链上的每一笔交易和应收账款单据上链,同时引入第三方可信机构来确认这些信息的交易,例如银行,物流公司等,确保交易和单据的真实性,同时支持应收账款的转让,融资,清算等,就可以让核心企业的信用可以传递到供应链的下游企业,减小中小企业的融资难度。
本项目针对这样一个应用场景,基于已有的开源区块链系统FISCO-BCOS,以联盟链为主,开发基于区块链或区块链智能合约的供应链金融平台, 实现供应链应收账款资产的溯源、流转。
1.2 功能需求分析
基本功能:
1.核心企业、普通企业、金融企业的注册。
2.通过账户查询余额、查询收款单据和欠款单据和查看历史交易记录。
核心功能:
1.实现采购商品—签发应收账款交易上链。例如车企从轮胎公司购买一批轮胎并签订应收账款单据。
2.实现应收账款的转让上链,本文转载自http://www.biyezuopin.vip/onews.asp?id=16716轮胎公司从轮毂公司购买一笔轮毂,便将于车企的应收账款单据部分转让给轮毂公司。轮毂公司可以利用这个新的单据去融资或者要求车企到期时归还钱款。
3.利用应收账款向银行融资上链,供应链上所有可以利用应收账款单据向银行申请融资。
4.应收账款支付结算上链,应收账款单据到期时核心企业向下游企业支付相应的欠款。
const Configuration = require('./nodejs-sdk/packages/api').Configuration;const Web3jService = require('./nodejs-sdk/packages/api').Web3jService;const createContractClass = require('./nodejs-sdk/packages/api/compile/contractClass').createContractClass;let config = new Configuration('config.json');let web3j = new Web3jService(config);const fs = require('fs');// 加载智能合约console.log('Loading contract from compiled file ...');let compiled = JSON.parse(fs.readFileSync('compiled/SupplyChain.json'))let contract = createContractClass(compiled.name, compiled.abi, compiled.bin, config.encryptType).newInstance();console.log('Loading deployed contract address from deployed file ...');let contractAddr = JSON.parse(fs.readFileSync('deployed/SupplyChain.json'))['contractAddress'];contract.$load(web3j, contractAddr);console.log('Done.');// 准备HTTP服务const express = require('express');const bodyParser = require('body-parser');const port = 9000;var app = express();app.use(bodyParser.json({ limit: '10mb'}));app.use(express.static('web', {index: '/index.html'})); // 网页根目录function getReqData(req) {if (req.body && Object.keys(req.body).length) {return req.body;}if (req.query && Object.keys(req.query).length) {return req.query;}if (req.params && Object.keys(req.params).length) {return req.params;}return {};}// 合约方法调用接口参数如下// account: 字符串,调用合约的账户名,必须是config.json中已有的账户// method: 字符串,想要调用的合约方法名字// parameters: 列表,合约方法调用参数// 返回一个JSON对象字符串// ok: 布尔值,调用是否成功// msg: 字符串,如果调用成功,则设为'succeed',否则为错误信息// data: 列表,合约方法调用的返回值app.all('/contractMethod', async (req, res) => {let reqData = getReqData(req);console.log(`call 'contractMethod' from ip ${req.ip}, params: ${JSON.stringify(reqData)}`);if (typeof(reqData.account) != 'string' || typeof(reqData.method) != 'string' ||!Array.isArray(reqData.parameters)) { // 检查接口参数类型console.log('failed at parameter type checking.');res.json({ok: false, msg: 'Bad iterface call.', data: []});return;}// 进行合约方法调用try {contract.$by(reqData.account);let retval = await contract[reqData.method](...reqData.parameters);console.log(`retval: ${JSON.stringify(retval)}`);res.json({ok: true, msg: 'succeed', data: retval});} catch (err) { // 出错let errString = err.toString();console.log(errString);res.json({ok: false, msg: errString, data: []});}});var server = app.listen(port);console.log(`server started at port ${port}.`)