一、 項(xiàng)目背景
中小微企業(yè)融資難、融資貴是長(zhǎng)久以來(lái)我國(guó)金融發(fā)展過(guò)程中需要解決的問(wèn)題。世界銀行、中小企業(yè)金融論壇、國(guó)際金融公司聯(lián)合發(fā)布的《中小微企業(yè)融資缺口:對(duì)新興市場(chǎng)微型、小型和中型企業(yè)融資不足與機(jī)遇的評(píng)估》報(bào)告中表示,中國(guó) 40%的中小微企業(yè)存在信貸困難,或是完全無(wú)法從正規(guī)金融體系獲得外部融資,或是從正規(guī)金融體系獲得的外部融資不能完全滿足融資需求,有 1.9 萬(wàn)億美元的融資缺口,接近 12 萬(wàn)億元人民幣。
比如以下場(chǎng)景。某知名車企(寶馬)消費(fèi)口碑好,金融機(jī)構(gòu)對(duì)其信用評(píng)級(jí)很高,認(rèn)為其有很大的風(fēng)險(xiǎn)承擔(dān)能力。某次交易中,該車企從輪胎公司購(gòu)買了一批輪胎,但由于資金暫時(shí)短缺向輪胎公司簽訂了1000 萬(wàn)的應(yīng)收賬款單據(jù),承諾一年后歸還。由于輪胎公司有寶馬的賬款單據(jù),金融機(jī)構(gòu)認(rèn)為其有額能力還款,于是愿意借款給輪胎公司,然而,這種信任關(guān)系并不會(huì)向下游傳遞。比如,輪胎公司因資金短缺,向輪轂公司簽訂了 500 萬(wàn)的應(yīng)收賬款單據(jù),但是當(dāng)輪轂公司需要貸款時(shí),金融機(jī)構(gòu)因不認(rèn)可輪胎公司的還款能力,需要對(duì)輪胎公司進(jìn)行詳細(xì)的信用分析,而這會(huì)增加很多的經(jīng)濟(jì)成本。很多時(shí)候,就是這個(gè)原因?qū)е铝诵∥⑵髽I(yè)的融資失敗。
但是,區(qū)塊鏈金融可以有效地解決上述問(wèn)題。將供應(yīng)鏈上的每一筆交易和應(yīng)收賬款單據(jù)上鏈,同時(shí)引入第三方可信機(jī)構(gòu)來(lái)確認(rèn)這些信息的交易,例如銀行,物流公司等,確保交易和單據(jù)的真實(shí)性。同 時(shí),支持應(yīng)收賬款的轉(zhuǎn)讓,融資,清算等,讓核心企業(yè)的信用可以傳遞到供應(yīng)鏈的下游企業(yè),減小中小企業(yè)的融資難度。
二、 方案設(shè)計(jì)
將供應(yīng)鏈上的每一筆交易和應(yīng)收賬款單據(jù)上鏈,同時(shí)引入第三方可信機(jī)構(gòu)來(lái)確認(rèn)這些信息的交易, 例如銀行,物流公司等,確保交易和單據(jù)的真實(shí)性。同時(shí),支持應(yīng)收賬款的轉(zhuǎn)讓,融資,清算等,讓核心企業(yè)的信用可以傳遞到供應(yīng)鏈的下游企業(yè),減小中小企業(yè)的融資難度。
【存儲(chǔ)設(shè)計(jì)】
將企業(yè)的收款單據(jù)存儲(chǔ)在通過(guò) FISCO BCOS 部署的四節(jié)點(diǎn)聯(lián)盟鏈上。由于我們要解決的問(wèn)題是供應(yīng)鏈上下游的信息不對(duì)等而導(dǎo)致的融資難問(wèn)題,我們只關(guān)注企業(yè)間的欠款信息,而忽略企業(yè)的余額,這也是本項(xiàng)目的設(shè)計(jì)思路。
當(dāng)兩個(gè)企業(yè)簽訂了應(yīng)收賬款單據(jù),將它們的公司信息、應(yīng)收數(shù)目上鏈,在必要時(shí),企業(yè)間的應(yīng)收賬款可以轉(zhuǎn)移到第三方,比如上例輪轂公司可以拿到寶馬的 500 萬(wàn)欠款證明。
【核心功能介紹】
本項(xiàng)目主要實(shí)現(xiàn)以下四個(gè)功能:
功能一:實(shí)現(xiàn)采購(gòu)商品—簽發(fā)應(yīng)收賬款交易上鏈。例如車企從輪胎公司購(gòu)買一批輪胎并簽訂應(yīng)收賬款單據(jù)。
功能二:實(shí)現(xiàn)應(yīng)收賬款的轉(zhuǎn)讓上鏈,輪胎公司從輪轂公司購(gòu)買一筆輪轂,便將于車企的應(yīng)收賬款單據(jù)部分轉(zhuǎn)讓給輪轂公司。輪轂公司可以利用這個(gè)新的單據(jù)去融資或者要求車企到期時(shí)歸還錢款。
功能三:利用應(yīng)收賬款向銀行融資上鏈,供應(yīng)鏈上所有可以利用應(yīng)收賬款單據(jù)向銀行申請(qǐng)融資。
功能四:應(yīng)收賬款支付結(jié)算上鏈,應(yīng)收賬款單據(jù)到期時(shí)核心企業(yè)向下游企業(yè)支付相應(yīng)的欠款。
核心功能主要體現(xiàn)在部署在區(qū)塊鏈上的智能合約。智能合約代碼如下:
package org.fisco.bcos.asset.client;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.fisco.bcos.asset.contract.Asset;
import org.fisco.bcos.asset.contract.Asset.RegisterEventEventResponse;
import org.fisco.bcos.asset.contract.Asset.TransferEventEventResponse;
import org.fisco.bcos.channel.client.Service;
import org.fisco.bcos.web3j.crypto.Credentials;
import org.fisco.bcos.web3j.crypto.Keys;
import org.fisco.bcos.web3j.protocol.Web3j;
import org.fisco.bcos.web3j.protocol.channel.ChannelEthereumService;
import org.fisco.bcos.web3j.protocol.core.methods.response.TransactionReceipt;
import org.fisco.bcos.web3j.tuples.generated.Tuple2;
import org.fisco.bcos.web3j.tx.gas.StaticGasProvider;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
public class AssetClient {
static Logger logger = LoggerFactory.getLogger(AssetClient.class);
private Web3j web3j;
private Credentials credentials;
public Web3j getWeb3j() {
return web3j;
}
public void setWeb3j(Web3j web3j) {
this.web3j = web3j;
}
public Credentials getCredentials() {
return credentials;
}
public void setCredentials(Credentials credentials) {
this.credentials = credentials;
}
public void recordAssetAddr(String address) throws FileNotFoundException, IOException {
Properties prop = new Properties();
prop.setProperty("address", address);
final Resource contractResource = new ClassPathResource("contract.properties");
FileOutputStream fileOutputStream = new FileOutputStream(contractResource.getFile());
prop.store(fileOutputStream, "contract address");
}
public String loadAssetAddr() throws Exception {
// load Asset contact address from contract.properties
Properties prop = new Properties();
final Resource contractResource = new ClassPathResource("contract.properties");
prop.load(contractResource.getInputStream());
String contractAddress = prop.getProperty("address");
if (contractAddress == null || contractAddress.trim().equals("")) {
throw new Exception(" load Asset contract address failed, please deploy it first. ");
}
logger.info(" load Asset address from contract.properties, address is {}", contractAddress);
return contractAddress;
}
public void initialize() throws Exception {
// init the Service
@SuppressWarnings("resource")
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
Service service = context.getBean(Service.class);
service.run();
ChannelEthereumService channelEthereumService = new ChannelEthereumService();
channelEthereumService.setChannelService(service);
Web3j web3j = Web3j.build(channelEthereumService, 1);
// init Credentials
Credentials credentials = Credentials.create(Keys.createEcKeyPair());
setCredentials(credentials);
setWeb3j(web3j);
logger.debug(" web3j is " + web3j + " ,credentials is " + credentials);
}
private static BigInteger gasPrice = new BigInteger("30000000");
private static BigInteger gasLimit = new BigInteger("30000000");
public void deployAssetAndRecordAddr() {
try {
Asset asset = Asset.deploy(web3j, credentials, new StaticGasProvider(gasPrice, gasLimit)).send();
System.out.println(" deploy Asset success, contract address is " + asset.getContractAddress());
recordAssetAddr(asset.getContractAddress());
} catch (Exception e) {
// TODO Auto-generated catch block
// e.printStackTrace();
System.out.println(" deploy Asset contract failed, error message is " + e.getMessage());
}
}
public void queryAssetAmount(String assetAccount) {
try {
String contractAddress = loadAssetAddr();
Asset asset = Asset.load(contractAddress, web3j, credentials, new StaticGasProvider(gasPrice, gasLimit));
Tuple2<BigInteger, BigInteger> result = asset.select(assetAccount).send();
if (result.getValue1().compareTo(new BigInteger("0")) == 0) {
System.out.printf(" asset account %s, value %s \n", assetAccount, result.getValue2());
} else {
System.out.printf(" %s asset account is not exist \n", assetAccount);
}
} catch (Exception e) {
// TODO Auto-generated catch block
// e.printStackTrace();
logger.error(" queryAssetAmount exception, error message is {}", e.getMessage());
System.out.printf(" query asset account failed, error message is %s\n", e.getMessage());
}
}
public void registerAssetAccount(String assetAccount, BigInteger amount) {
try {
String contractAddress = loadAssetAddr();
Asset asset = Asset.load(contractAddress, web3j, credentials, new StaticGasProvider(gasPrice, gasLimit));
TransactionReceipt receipt = asset.register(assetAccount, amount).send();
List<RegisterEventEventResponse> response = asset.getRegisterEventEvents(receipt);
if (!response.isEmpty()) {
if (response.get(0).ret.compareTo(new BigInteger("0")) == 0) {
System.out.printf(" register asset account success => asset: %s, value: %s \n", assetAccount,
amount);
} else {
System.out.printf(" register asset account failed, ret code is %s \n",
response.get(0).ret.toString());
}
} else {
System.out.println(" event log not found, maybe transaction not exec. ");
}
} catch (Exception e) {
// TODO Auto-generated catch block
// e.printStackTrace();
logger.error(" registerAssetAccount exception, error message is {}", e.getMessage());
System.out.printf(" register asset account failed, error message is %s\n", e.getMessage());
}
}
public void transferAsset(String fromAssetAccount, String toAssetAccount, BigInteger amount) {
try {
String contractAddress = loadAssetAddr();
Asset asset = Asset.load(contractAddress, web3j, credentials, new StaticGasProvider(gasPrice, gasLimit));
TransactionReceipt receipt = asset.transfer(fromAssetAccount, toAssetAccount, amount).send();
List<TransferEventEventResponse> response = asset.getTransferEventEvents(receipt);
if (!response.isEmpty()) {
if (response.get(0).ret.compareTo(new BigInteger("0")) == 0) {
System.out.printf(" transfer success => from_asset: %s, to_asset: %s, amount: %s \n",
fromAssetAccount, toAssetAccount, amount);
} else {
System.out.printf(" transfer asset account failed, ret code is %s \n",
response.get(0).ret.toString());
}
} else {
System.out.println(" event log not found, maybe transaction not exec. ");
}
} catch (Exception e) {
// TODO Auto-generated catch block
// e.printStackTrace();
logger.error(" registerAssetAccount exception, error message is {}", e.getMessage());
System.out.printf(" register asset account failed, error message is %s\n", e.getMessage());
}
}
public static void Usage() {
System.out.println(" Usage:");
System.out.println("\t java -cp conf/:lib/*:apps/* org.fisco.bcos.asset.client.AssetClient deploy");
System.out.println("\t java -cp conf/:lib/*:apps/* org.fisco.bcos.asset.client.AssetClient query account");
System.out.println(
"\t java -cp conf/:lib/*:apps/* org.fisco.bcos.asset.client.AssetClient register account value");
System.out.println(
"\t java -cp conf/:lib/*:apps/* org.fisco.bcos.asset.client.AssetClient transfer from_account to_account amount");
System.exit(0);
}
public static void main(String[] args) throws Exception {
if (args.length < 1) {
Usage();
}
AssetClient client = new AssetClient();
client.initialize();
switch (args[0]) {
case "deploy":
client.deployAssetAndRecordAddr();
break;
case "query":
if (args.length < 2) {
Usage();
}
client.queryAssetAmount(args[1]);
break;
case "register":
if (args.length < 3) {
Usage();
}
client.registerAssetAccount(args[1], new BigInteger(args[2]));
break;
case "transfer":
if (args.length < 4) {
Usage();
}
client.transferAsset(args[1], args[2], new BigInteger(args[3]));
break;
default: {
Usage();
}
}
System.exit(0);
}
}
三、 功能測(cè)試
首先在WeBase 平臺(tái)上測(cè)試智能合約。
首先,根據(jù)不同公司創(chuàng)建用戶,一共有:銀行(Bank)、汽車廠(CarCompany)、輪胎廠
(TyreCompany)、輪轂廠(HubCompany):
對(duì)編寫(xiě)好的合約進(jìn)行編譯、部署:
功能一:實(shí)現(xiàn)采購(gòu)商品—簽發(fā)應(yīng)收賬款交易上鏈。
(說(shuō)明:車企欠輪胎廠 1000 萬(wàn)元) 部署成功會(huì)顯示相關(guān)信息。
(說(shuō)明:輪胎廠欠輪轂廠 500 萬(wàn)元) 查看鏈上的交易信息:
說(shuō)明交易信息成功上鏈。功能一完成。
功能二:實(shí)現(xiàn)應(yīng)收賬款的轉(zhuǎn)讓上鏈。
(說(shuō)明:車企欠輪胎廠的部分金額,轉(zhuǎn)嫁到輪轂廠)
再次查看鏈上的交易信息:
現(xiàn)在車企欠輪胎廠和輪轂廠各 500 萬(wàn)元,說(shuō)明功能二實(shí)現(xiàn)。
功能三:利用應(yīng)收賬款向銀行融資上鏈。
(獲取輪轂廠的總債務(wù))
輪轂廠向銀行借貸:
說(shuō)明功能三實(shí)現(xiàn)。
功能四:應(yīng)收賬款支付結(jié)算上鏈。
(車企還輪胎廠 200 萬(wàn)元)
(車企還欠輪胎廠 300 萬(wàn)元)文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-799277.html
車企再還 300 萬(wàn)元給輪胎廠,則抹去鏈上該條交易信息。以上是智能合約的測(cè)試結(jié)果。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-799277.html
到了這里,關(guān)于基于Java實(shí)現(xiàn)的區(qū)塊鏈供應(yīng)鏈金融系統(tǒng)平臺(tái)設(shè)計(jì)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!