奇了,結婚也能寫成區塊鏈智慧合約
阿新 • • 發佈:2018-12-13
在下面的文章中,我將深入介紹“智慧婚禮合約”的技術實施細節。 請記住,這是一個原型,因此產品功能可能並不齊全。
如果您對整體想法和概念感興趣,可以在這裡閱讀更多相關資訊。
介紹
該專案基本上是使用Truffle Framework(Truffle,Ganache)、Web3和MetaMask完成。這是與以太坊進行通訊的簡單Web前端構建的。
實現
一般的想法是建立一個婚姻合同的數字版本,參考過去的西方書面紙質結婚合同(中國似乎不流行),包含所有必要的功能,如管理資金和資產。 然而,我們希望這款產品不僅僅優先處理數字等價物,合同同樣也能處理資金,也能動態管理資產(這聽起來很花哨,但它很直接)。
現在讓我們來看看一些程式碼。
合約部署
首先要做的是將新婚夫妻的錢包地址作為建構函式引數新增到合同中。 因為這些地址無法更改,所以這是最好的方法。
因此,書面合同是手工簽署的,並儲存為PDF上傳到IPFS(去中心化儲存系統)。 該檔案可以在這裡找到:
【解讀】:IPFS除非自己部署IPFS節點, 否則不能保證資料不丟失。因為IPFS是不帶有激勵性質的去中心化儲存系統。如果要保證檔案不丟失,可以採用PP.IO(https://pp.io ),這是保證高可靠性的去中心化儲存系統,相容AWS S3的介面,並且能做到12個9地(99.9999999999%)保證檔案不會丟失(具體原理可見《How decentralized storage is able to ensure that data is not lost》)。
在以太坊上儲存資料需要花費很多。 基於他們的黃紙儲存256位元組需要20k的Gas。 我們假設PDF有100 kB:
100kB/256 bit = ~390 (256-bit words)
390 (256-bit words) * 20k (Gas) * 10 Gwei (gas price) = 0.078 ETH
想象一下,一個小檔案儲存就要支付10美元以上。 如果你想上傳一個更大的檔案,這可能很容易花費數百甚至數千美元。 我們只需要將檔案的哈西上鍊(儲存在區塊鏈上),而不是將整個檔案儲存在以太坊上。
簽名合約
成功部署合同並上傳IPFS雜湊後,智慧婚禮合約處於未簽名狀態。
const SmartWeddingContract = artifacts.require("./contracts/SmartWeddingContract.sol"); const husbandAddress = require("../config.js").husbandAddress; const wifeAddress= require("../config.js").wifeAddress; module.exports = function(deployer) { deployer.deploy(SmartWeddingContract, husbandAddress, wifeAddress); };
上傳可寫合約 您可能會問,既然我們的最終目標是建立一個優秀的數字合同版本,為什麼我們還要上傳一份書面合同。 原因是我們希望它能在法律背景下工作。 而現在,如果與一份簡單的舊書面法律檔案沒有任何聯絡,這在奧地利是不行的。
modifier isSigned() { require(signed == true, "Contract has not been signed by both spouses yet!"); _; }
夫妻雙方必須首先使用私鑰對其進行簽名,以便呼叫更多功能。 這是由於isSigned修飾符在呼叫之前檢查合同的狀態。
function signContract() external onlySpouse { require(isSameString(writtenContractIpfsHash, ""), "Written contract ipfs hash has been proposed yet!"); require(hasSigned[msg.sender] == false, "Spouse has already signed the contract!"); // Sender簽名 hasSigned[msg.sender] = true; emit Signed(now, msg.sender); // 檢查夫妻雙方是否都已經簽名 if (hasSigned[husbandAddress] && hasSigned[wifeAddress]) { signed = true; emit ContractSigned(now); } }
signContract函式只能由夫妻呼叫。 “神奇”部分是最後的multisig。 if-clause 檢查丈夫和妻子是否簽署了合同。 如果是,則全域性簽名狀態更改為true。
資產 資產,例如:汽車,房子、股票甚至是婚姻合約管理的主要內容,應宣告以下問題:- 誰擁有什麼?
- 離婚後會發生什麼?
function proposeAsset(string _data, uint _husbandAllocation, uint _wifeAllocation) external onlySpouse isSigned isNotDivorced { require(isSameString(_data, ""), "No asset data provided!"); require(_husbandAllocation >= 0, "Husband allocation invalid!"); require(_wifeAllocation >= 0, "Wife allocation invalid!"); require((_husbandAllocation + _wifeAllocation) == 100, "Total allocation must be equal to 100%!"); // 新增新資產 Asset memory newAsset = Asset({ data: _data, husbandAllocation: _husbandAllocation, wifeAllocation: _wifeAllocation, added: false, removed: false }); uint newAssetId = assets.push(newAsset); emit AssetProposed(now, _data, msg.sender); // 對映到儲存物件(否則無法訪問對映) Asset storage asset = assets[newAssetId - 1]; // Sender立刻批准 asset.hasApprovedAdd[msg.sender] = true; emit AssetAddApproved(now, _data, msg.sender); }
批准一個資產 在簽訂合約時,資產以相同的方式批准(使用multisig)。只有配偶雙方同意才能新增資產。
function approveAsset(uint _assetId) external onlySpouse isSigned isNotDivorced { require(_assetId > 0 && _assetId <= assets.length, "Invalid asset id!"); Asset storage asset = assets[_assetId - 1]; require(asset.added == false, "Asset has already been added!"); require(asset.removed == false, "Asset has already been removed!"); require(asset.hasApprovedAdd[msg.sender] == false, "Asset has already approved by sender!"); // Sender批准 asset.hasApprovedAdd[msg.sender] = true; emit AssetAddApproved(now, asset.data, msg.sender); // 檢查夫妻雙方是否都已批准 if (asset.hasApprovedAdd[husbandAddress] && asset.hasApprovedAdd[wifeAddress]) { asset.added = true; emit AssetAdded(now, asset.data); } }
刪除一個資產 同樣,雙方必須都同意才能刪除資產。
function removeAsset(uint _assetId) external onlySpouse isSigned isNotDivorced { require(_assetId > 0 && _assetId <= assets.length, "Invalid asset id!"); Asset storage asset = assets[_assetId - 1]; require(asset.added, "Asset has not been added yet!"); require(asset.removed == false, "Asset has already been removed!"); require(asset.hasApprovedRemove[msg.sender] == false, "Removing the asset has already been approved by the sender!"); // 批准 Sender 刪除 asset.hasApprovedRemove[msg.sender] = true; emit AssetRemoveApproved(now, asset.data, msg.sender); // 檢查夫妻雙方是否都批准移除資產 if (asset.hasApprovedRemove[husbandAddress] && asset.hasApprovedRemove[wifeAddress]) { asset.removed = true; emit AssetRemoved(now, asset.data); } }
合約作為儲蓄賬戶 智慧婚禮合約也可以用作儲蓄賬戶。 它可以充當普通的以太坊錢包,這意味著它可以接收ETH。 並且通過支付功能,妻子和丈夫都可以通過這個錢包地址傳送到另一個地址(例如,支付食物或假期,購買其他資產......)來花費這些ETH。
function() external payable isSigned isNotDivorced { emit FundsReceived(now, msg.sender, msg.value); }
這是預設功能。 重要的關鍵詞是可支付。 它使智慧合約能夠獲得資金(ETH)。
function pay(address _to, uint _amount) external onlySpouse isSigned isNotDivorced { require(_to != address(0), "Sending funds to address zero is prohibited!"); require(_amount <= address(this).balance, "Not enough balance available!"); // 將資金髮送到目的地地址 _to.transfer(_amount); emit FundsSent(now, _to, _amount); }
付費功能僅獲取目的地地址和要傳送的金額。
離婚 也許最重要的功能是離婚後會發生的事情,這也是婚姻合同存在的原因之一。 離婚功能只能由配偶呼叫。和以前一樣,必須雙發都同意離婚。一旦雙方同意,合同狀態就會改變。 剩餘的資金(ETH)被分成兩半併發送給每一方。function divorce() external onlySpouse isSigned isNotDivorced { require(hasDivorced[msg.sender] == false, "Sender has already approved to divorce!"); // Sender批准 hasDivorced[msg.sender] = true; emit DivorceApproved(now, msg.sender); // 檢查夫妻雙方是否都同意離婚 if (hasDivorced[husbandAddress] && hasDivorced[wifeAddress]) { divorced = true; emit Divorced(now); // 獲取合約的餘額 uint balance = address(this).balance; // 將餘額分成兩半 if (balance != 0) { uint balancePerSpouse = balance / 2; // 轉賬給原丈夫方 husbandAddress.transfer(balancePerSpouse); emit FundsSent(now, husbandAddress, balancePerSpouse); // 轉賬給原妻子方 wifeAddress.transfer(balancePerSpouse); emit FundsSent(now, wifeAddress, balancePerSpouse); } } }
在將合同狀態更改為離婚後,任何人都無法再與合同互動。 這是由於isNotDivorced修飾符在起作用。它被新增到所有關鍵功能中,以確保以後不能更改任何內容。
modifier isNotDivorced() { require(divorced == false, "Can not be called after spouses agreed to divorce!"); _; }事件 DApp使用了許多事件。幾乎在每種情況下都會發出它們,以便為前端應用程式建立正確的日誌。 每個事件還有一個時間戳變數。它僅顯示一個大致的時間。事件在web前端執行的時間。Web3也支援這一點,所以沒有必要記錄每個事件的時間戳,但是: Web3需要為每個事件非同步查詢遠端以太坊節點(這看起來相當愚蠢) 但它是免費的(在Solidity事件中儲存資料不需要任何費用)
event WrittenContractProposed(uint timestamp, string ipfsHash, address wallet);
event Signed(uint timestamp, address wallet);
event ContractSigned(uint timestamp);
event AssetProposed(uint timestamp, string asset, address wallet);
event AssetAddApproved(uint timestamp, string asset, address wallet);
event AssetAdded(uint timestamp, string asset);
event AssetRemoveApproved(uint timestamp, string asset, address wallet);
event AssetRemoved(uint timestamp, string asset);
event DivorceApproved(uint timestamp, address wallet);
event Divorced(uint timestamp);
event FundsSent(uint timestamp, address wallet, uint amount);
event FundsReceived(uint timestamp, address wallet, uint amount);
智慧婚禮合同部署在以太坊Ropsten測試網和以太坊主網上。
GitHub
完整的原始碼可在以下位置獲得: https://github.
com/block42-blockchain-company/smart-wedding-contract
文章作者:Wayne Wong
轉載請註明出處
如果有關於PPIO的交流,可以通過下面的方式聯絡我:
加我微信,注意備註來源
wechat:omnigeeker