當(dāng)前位置:首頁(yè) > 物聯(lián)網(wǎng) > 區(qū)塊鏈
[導(dǎo)讀] 此博客文章的目標(biāo)受眾主要是熟悉區(qū)塊鏈和智能合約的開(kāi)發(fā)人員。并非所有開(kāi)發(fā)人員都具有豐富的經(jīng)濟(jì)和金融背景。因此,我們建議您閱讀關(guān)于這些金融方面的博文。 定義“智能發(fā)票” 我們的目標(biāo)是

此博客文章的目標(biāo)受眾主要是熟悉區(qū)塊鏈和智能合約的開(kāi)發(fā)人員。并非所有開(kāi)發(fā)人員都具有豐富的經(jīng)濟(jì)和金融背景。因此,我們建議您閱讀關(guān)于這些金融方面的博文。

定義“智能發(fā)票”

我們的目標(biāo)是展示我們?nèi)绾问褂弥悄芎霞s來(lái)指定和執(zhí)行現(xiàn)實(shí)世界發(fā)票的支付,從而將錢(qián)從買(mǎi)方轉(zhuǎn)移到賣(mài)方。更具體地說(shuō),我們希望實(shí)現(xiàn)一個(gè)功能,以確保一旦買(mǎi)方接受發(fā)票,他就承諾在到截止日期進(jìn)行付款。

創(chuàng)建以太坊智能合約時(shí)會(huì)存在某些限制,這些限制會(huì)影響如何構(gòu)建滿(mǎn)足這些目標(biāo)的解決方案。

在以太坊上,不可能執(zhí)行“觸發(fā)器”,“事件驅(qū)動(dòng)編程”,“觀察者模式”和類(lèi)似的范例,在這些范例中,某些事情需要作為對(duì)其他事情的分離響應(yīng)發(fā)生。因此,我們無(wú)法實(shí)施在到期日自動(dòng)執(zhí)行付款轉(zhuǎn)帳的解決方案。相反,我們創(chuàng)建了一個(gè)流程,保證任何人都可以在達(dá)到截止日期后觸發(fā)付款執(zhí)行。

我們使用三個(gè)智能合約來(lái)結(jié)算真正的貿(mào)易發(fā)票,它們是:

智能發(fā)票

從設(shè)計(jì)的角度來(lái)看,智能發(fā)票合同需要盡可能簡(jiǎn)單。買(mǎi)方承諾支付,因此有必要審計(jì)和理解包括此類(lèi)承諾在內(nèi)的所有可能后果。

智能發(fā)票包含付款金額、截止日期、付款方和付款受益人。受益人可以由當(dāng)前受益人更改。所有其他字段都是靜態(tài)的,這對(duì)于買(mǎi)方來(lái)說(shuō)非常重要,以便了解他所承諾的內(nèi)容。

智能發(fā)票代幣

我們還要將付款標(biāo)記化。我們通過(guò)為智能發(fā)票創(chuàng)建一個(gè)erc20令牌來(lái)實(shí)現(xiàn)這一點(diǎn)。這使持有人有權(quán)在基礎(chǔ)發(fā)票結(jié)算后獲得部分付款。我們這樣做是為了說(shuō)明智能發(fā)票的使用案例,例如在結(jié)算前出售您的發(fā)票代幣以獲得提前付款。

錢(qián)包

買(mǎi)方和賣(mài)方都創(chuàng)建并控制他們自己的智能合約錢(qián)包。這個(gè)錢(qián)包可以保持價(jià)值,在我們的案例中是DA并I與智能發(fā)票發(fā)生交互。買(mǎi)方可以承諾通過(guò)他的錢(qián)包支付給定的智能發(fā)票。承諾意味著任何人都可以強(qiáng)制買(mǎi)方錢(qián)包在到截止日期支付發(fā)票。

端到端測(cè)試觀察

使用以太坊的最大挑戰(zhàn)之一是獲得對(duì)解決方案的高度信任。對(duì)于需要通過(guò)實(shí)施的大量資金的企業(yè)部門(mén)尤其如此。

在這個(gè)項(xiàng)目中,我們關(guān)注的是圍繞單元測(cè)試的工具和開(kāi)發(fā)。在本節(jié)中,我們使用端到端測(cè)試來(lái)解釋創(chuàng)建、標(biāo)記化和執(zhí)行發(fā)票付款過(guò)程中涉及的所有步驟。

用于開(kāi)發(fā)的技術(shù)堆棧由:node.js、typescript、solidity和truffle框架組成。以下代碼段是端到端測(cè)試的一部分。我們還使用一個(gè)簡(jiǎn)單的cli在mainnet上執(zhí)行了一個(gè)引導(dǎo)。在此過(guò)程中我們結(jié)算了一張真實(shí)的發(fā)票,并在下面的步驟中為我們的polit添加了Etherscan鏈接。

1.買(mǎi)方和賣(mài)方應(yīng)各自擁有一個(gè)含有以太坊的帳戶(hù)。

const buyerBalance = await web3.eth.getBalance(buyer);

assert(

new BigNumber(buyerBalance).isGreaterThanOrEqualTo(

web3.utils.toWei(‘10’, ‘ether’),

),

);

const sellerBalance = await web3.eth.getBalance(seller);

assert(

new BigNumber(sellerBalance).isGreaterThanOrEqualTo(

web3.uTIls.toWei(‘10’, ‘ether’),

),

);

第一步是檢查買(mǎi)方和賣(mài)方是否在其賬戶(hù)中都有以太幣。他們都必須支付在以太坊區(qū)塊鏈交易所含的gas費(fèi)用。

2.買(mǎi)方在其賬戶(hù)中存有DAI(而不是在錢(qián)包中)。

const daiDecimals = await mockDAITokenInstance.decimals();

// give buyer 1000 DAI

const daiAmount = new BigNumber(10).pow(daiDecimals).TImes(1000);

await mockDAITokenInstance.setBalance(buyer, daiAmount.toString(10));

const smartContractBalance = await mockDAITokenInstance.balanceOf

(buyer);

assert.equal(smartContractBalance.toString(10), daiAmount.toString(10));

assert.notExists(buyerWalleTInstance);

我們可以使用任何符合ERC20標(biāo)準(zhǔn)的加密貨幣來(lái)完成這個(gè)項(xiàng)目,但我們選擇了DAI。首先,我們要求使用“穩(wěn)定幣”,因?yàn)槿魏纹髽I(yè)都不會(huì)接受加密貨幣匯率風(fēng)險(xiǎn)。其次,我們與Maker建立了合作伙伴關(guān)系。

在此步驟中,我們將DAI添加到買(mǎi)方的帳戶(hù)中。我們使用‘BigNumber’依賴(lài)關(guān)系來(lái)轉(zhuǎn)換所需格式的和(10到18倍1000的冪)。

3.買(mǎi)家創(chuàng)建錢(qián)包

assert.notExists(buyerWalleTInstance);

buyerWalletInstance = await SmartInvoiceWallet.new(

buyer,

mockDAITokenInstance.address,

{ from: buyer },

);

const buyerWalletAssetTokenAddress = await buyerWalletInstance.

assetToken();

assert.equal(buyerWalletAssetTokenAddress, mockDAITokenInstance.

address);

買(mǎi)方錢(qián)包可以持有DAI代幣并與智能發(fā)票進(jìn)行交互。

4.賣(mài)方創(chuàng)建錢(qián)包

assert.notExists(sellerWalletInstance);

sellerWalletInstance = await SmartInvoiceWallet.new(

seller,

mockDAITokenInstance.address,

{ from: seller },

);

const sellerWalletAssetTokenAddress = await sellerWalletInstance.

assetToken();

assert.equal(sellerWalletAssetTokenAddress, mockDAITokenInstance.

address);

5.賣(mài)方為買(mǎi)方創(chuàng)建一張貿(mào)易發(fā)票。

mockInvoice = {

id: ‘xxx-xx–xxxx-xxxx–xxxxxxxx’, // “random” uuid

amount: 70.5,

dueDate: currentTimeStamp() + 60 * 60, // 1h starting from

current time

};

assert.exists(mockInvoice);

通常貿(mào)易轉(zhuǎn)移平臺(tái)上會(huì)創(chuàng)建發(fā)票。發(fā)票ID將用作智能發(fā)票標(biāo)識(shí)符(以便買(mǎi)方知道應(yīng)向誰(shuí)付款)。為了我們的項(xiàng)目,我們創(chuàng)建了一個(gè)對(duì)象并添加了所需的屬性。

在試點(diǎn)中,我們使用了真正的貿(mào)易發(fā)票。

6.賣(mài)方為貿(mào)易轉(zhuǎn)移發(fā)票創(chuàng)建智能發(fā)票和代幣。

assert.exists(sellerWalletInstance);

assert.exists(mockInvoice);

assert.notExists(smartInvoiceTokenInstance);

assert.notExists(smartInvoiceInstance);

const daiDecimals = await mockDAITokenInstance.decimals();

const amount = new BigNumber(10)

.pow(daiDecimals)

.times(mockInvoice.amount);

smartInvoiceTokenInstance = await SmartInvoiceToken.new(

amount,

mockInvoice.dueDate,

mockDAITokenInstance.address,

sellerWalletInstance.address,

buyerWalletInstance.address,

mockInvoice.id,

{ from: seller },

);

const smartInvoiceAddress = await smartInvoiceTokenInstance.

smartInvoice();

// at is mistyped, and does returns a promise

smartInvoiceInstance = await SmartInvoice.at(smartInvoiceAddress);

assert.exists(smartInvoiceInstance);

assert.exists(smartInvoiceAddress);

這是賣(mài)方創(chuàng)建智能合同實(shí)例的步驟,該實(shí)例“wrap”有關(guān)自執(zhí)行發(fā)票的所有必要信息。

現(xiàn)在我們創(chuàng)建了一個(gè)智能發(fā)票。我們只需要買(mǎi)方承諾(在他核實(shí)了細(xì)節(jié)之后)。

7.買(mǎi)方承諾支付智能發(fā)票。

const amountToCommit = await smartInvoiceInstance.amount();

const dueDateToCommit = await smartInvoiceInstance.dueDate();

const invoiceIdToCommit = await smartInvoiceInstance.referenceHash();

const daiDecimals = await mockDAITokenInstance.decimals();

const mockInvoiceAmount = new BigNumber(10)

.pow(daiDecimals)

.times(mockInvoice.amount);

// check if commitment value is correct

assert.equal(

amountToCommit.valueOf(),mockInvoiceAmount.valueOf(),

);

assert.equal(dueDateToCommit.toNumber(), mockInvoice.dueDate);

assert.equal(invoiceIdToCommit, mockInvoice.id);

await buyerWalletInstance.commit(

smartInvoiceInstance.address, {from: buyer,}

);

買(mǎi)方驗(yàn)證智能發(fā)票中的承諾金額是否與在貿(mào)易轉(zhuǎn)移平臺(tái)上創(chuàng)建的初始發(fā)票上確定的金額相同。之后,他承諾在執(zhí)行之日支付。

8.賣(mài)方擁有所有發(fā)票代幣并確認(rèn)買(mǎi)方已承諾支付。

const validCommit = await buyerWalletInstance.hasValidCommit(

smartInvoiceInstance.address,{ from: seller },

);

assert.equal(validCommit, true);

const daiDecimals = await mockDAITokenInstance.decimals();

const mockInvoiceAmount = new BigNumber(10)

.pow(daiDecimals)

.times(mockInvoice.amount);

const sellerTokenBalance = await sellerWalletInstance.

invoiceTokenBalance(

smartInvoiceTokenInstance.address, {from: seller}

);

assert.equal(

sellerTokenBalance.valueOf(),mockInvoiceAmount.valueOf(),

);

現(xiàn)在是賣(mài)家的行動(dòng)時(shí)間。他首先檢查買(mǎi)方是否兌現(xiàn)承諾。至于我們現(xiàn)在關(guān)注的是,我們等到截止日期,然后賣(mài)方將觸發(fā)智能發(fā)票執(zhí)行。

9.截止日期到期

const initialBlock = await web3.eth.getBlock(‘latest’);

const timeToAdvance = 60 * 60;

const latestBlock: Block = await advanceTimeAndBlock(timeToAdvance);

assert.notEqual(initialBlock.hash, latestBlock.hash);

// assert if block time increased as expected

assert(

new BigNumber(initialBlock.timestamp)

.plus(timeToAdvance)

.isLessThanOrEqualTo(latestBlock.timestamp)

);

即使在整個(gè)這一步驟中沒(méi)有任何代理實(shí)際上采取任何行動(dòng),我們認(rèn)為如何測(cè)試時(shí)間是否實(shí)際按預(yù)期進(jìn)行測(cè)試將是非常有趣的。

10.買(mǎi)方將DAI轉(zhuǎn)移到自己的錢(qián)包中

const invoiceAmount = await smartInvoiceInstance.amount();

await mockDAITokenInstance.transfer(

buyerWalletInstance.address,

invoiceAmount,

{from: buyer,},

);

const buyerWalletBalance = await buyerWalletInstance.balance();

assert(

new BigNumber(buyerWalletBalance).isGreaterThanOrEqualTo

(invoiceAmount)

);

通常,在到截止日期期,買(mǎi)方應(yīng)該已經(jīng)將DAI轉(zhuǎn)移到自己的錢(qián)包中。以防買(mǎi)方?jīng)]有足夠的錢(qián)支付,在付款的時(shí)候,超出了這個(gè)項(xiàng)目資金的范圍。

11.賣(mài)方觸發(fā)支付智能發(fā)票

const canSettle = await buyerWalletInstance

.canSettleSmartInvoice(smartInvoiceInstance.address);

assert.equal(true, canSettle);

// smart invoice is triggered by seller

await buyerWalletInstance.settle(

smartInvoiceInstance.address, {from: seller,}

);

const smartInvoiceTokenInstanceBalance = await mockDAITokenInstance

.balanceOf(smartInvoiceTokenInstance.address,);

const smartInvoiceAmount = await smartInvoiceInstance.amount();

assert.equal(

smartInvoiceTokenInstanceBalance.toString(10),

smartInvoiceAmount.toString(10),

);

是時(shí)候賣(mài)家結(jié)算智能發(fā)票了。 我們檢查智能發(fā)票狀態(tài)是否設(shè)置為“已提交”。這是真的,因?yàn)槲覀兛吹劫I(mǎi)方承諾在步驟7付款。此時(shí)賣(mài)方觸發(fā)智能發(fā)票。

由于每個(gè)代幣代表正好1 DAI,我們將令牌余額與發(fā)票金額進(jìn)行比較,以查看它們是否匹配。

12.賣(mài)方以交換DAI的方式兌換發(fā)票代幣

const canRedeem = await smartInvoiceTokenInstance.canRedeem();

assert.equal(true, canRedeem);

const sellerWalletBalanceBefore = await sellerWalletInstance.balance

({from: seller});

await sellerWalletInstance

.redeem(smartInvoiceTokenInstance.address, {from: seller,});

const sellerWalletBalanceAfter = await sellerWalletInstance

.balance({ from: seller });

const daiDecimals = await mockDAITokenInstance.decimals();

const daiInvoiceAmount = new BigNumber(10)

.pow(daiDecimals)

.times(mockInvoice.amount);

assert.equal(

daiInvoiceAmount.toString(10),

new BigNumber(sellerWalletBalanceAfter).minus(

sellerWalletBalanceBefore).toString(10)

);

現(xiàn)在賣(mài)方已經(jīng)結(jié)算了智能發(fā)票,他可以贖回買(mǎi)方欠他的DAI金額。

13.賣(mài)方將DAI從錢(qián)包轉(zhuǎn)移到自己的賬戶(hù)

const sellerBalanceBefore = await mockDAITokenInstance

.balanceOf(seller, { from: seller });

const daiDecimals = await mockDAITokenInstance.decimals();

const daiInvoiceAmount = new BigNumber(10)

.pow(daiDecimals)

.times(mockInvoice.amount);

await sellerWalletInstance

.transfer(seller, daiInvoiceAmount, {from: seller});

const sellerBalanceAfter = await mockDAITokenInstance

.balanceOf(seller, { from: seller });

assert.equal(

daiInvoiceAmount.toString(10),

new BigNumber(sellerBalanceAfter).minus(sellerBalanceBefore)。

toString(10)

);

我們現(xiàn)在有了一個(gè)完整的流程,兩個(gè)代理在他們之間建立智能發(fā)票。如果供應(yīng)商希望從他的錢(qián)包中取出DAI,他可以這樣做。我們已經(jīng)包含了這個(gè)測(cè)試步驟,這樣我們就可以正確地從頭到尾地跟蹤資金。

最后的想法

這個(gè)試點(diǎn)是關(guān)于想象智能發(fā)票在以太坊世界中的運(yùn)作方式。 顯然,這個(gè)項(xiàng)目并不支持大量的發(fā)票發(fā)送,而是為了說(shuō)明智能合約和區(qū)塊鏈如何適應(yīng)B2B領(lǐng)域。

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專(zhuān)欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車(chē)的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車(chē)技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車(chē)工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車(chē)。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車(chē) 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶(hù)希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱(chēng),數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱(chēng)"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉