区块链项目实战 - 使用以太坊/智能合约solidity,全栈开发区块链借贷记账小应用,含完整源码

本文使用区块链平台以太坊+智能合约实现一个区块链记账的功能,具体为:

  • 借款人和贷款人以及数额被记录在区块链中。使用区块链地址来表示借款人或者贷款人。
  • 若一个借款人多次向一个贷款人借钱,更新所有的数额之和并记录在区块链中。
  • 智能合约保存所有用户的借贷信息,包括他们的区块链地址和数额
  • 只有借款人才能向智能合约中添加借款记录。
  • 若一个人既是借款人,也是贷款人,那么最终下图中的“Total Owed”只显示他总的欠款。因此,如果他借出去的钱比借来的钱多,那么这个字段为0,表示他不欠任何人钱。
  • 一个UI界面方便用户使用该应用。

除了智能合约部分的代码逻辑,还需要实现后台的UI和交互。这里使用JavaScript和html来实现。执行使用ganache在本地节点中来创建一个以太坊的测试环境。先看最终的html页面:
在这里插入图片描述

下面是执行环境安装和完整的源码的地址。

执行环境搭建

  • 下载安装node.js (使用到了web3.js)
  • 安装ganache-cli (用来模拟以太坊的本地环境)
  • 通过下面的链接进入remix 的IDE: https://remix.ethereum.org/
  • 编写智能合约,具体的智能合约见文末;
  • 在本地电脑中启动ganache-cli。在cmd中输入命令“ganache-cli”,回车即可。
  • 为了部署写好的智能合约,选择下图编号为1的选项,选择web3 Provider;点击Deploy按钮就可以将编译好的智能合约部署到本地的ganache-cli节点了。
    在这里插入图片描述
  • 点击上图编号3的图标复制智能合约的地址,(粘贴)作为代码script.js文件的contractAddress变量的值。
  • 使用浏览器打开index.html文件,即可看到第一张图效果。

需要注意的内容
这里的代码只是一个demo,目的是演示一个全栈的以太坊智能合约应用,因此没有优化性能。这里的性能主要指的是js代码跟本地节点交互的成本。其次,为了减少智能合约的存储和计算开销,这里把大部分逻辑和存储放到了本地的js代码中。在目前的以太坊的mainnet中,交易费是很贵的。相比之下,js代码和本地节点的交互反而是很便宜的。特别的,调用“只读”的智能合约函数是不需要交易费的,因为这个过程只是js代码和本地节点的交互,并没有往区块链中写入或者修改区块链的数据。因此,script.js中的函数“downloadAll()”是不需要手续费的。

完整的源码下载:
https://github.com/liangyihuai/LearnBlockchainByCoding

完整的智能合约代码:

pragma solidity 0.6.6;

contract Splitwise{
    struct CreditAcc{
        address creditor; //the person who lends money
        uint32 amount; //
    }
    
    //debtor address => creditor infor
    mapping (address => CreditAcc[]) creditAccMap;
    address[] users; //store all registered user's addresses.
    
    function getUsers() public view returns(address[] memory){
        return users;
    }
    
    //The debtor borrows money from the creditor
    function lookup(address debtor, address creditor) public view returns (uint32 ret){
        if(existCreditor(debtor, creditor)){
            CreditAcc[] memory ca = creditAccMap[debtor];
            for(uint i = 0; i < ca.length; i++){
                if(ca[i].creditor == creditor){
                    return ca[i].amount;
                }
            }
        }
        
        return 0;
    }
    
    function add_IOU(address creditor, uint32 amount)public {
        require(amount > 0);
        require(msg.sender != creditor);
        
        if(!existAnyCreditor(msg.sender)){
            CreditAcc[] storage creditAccArray;
            creditAccArray.push(CreditAcc(creditor, amount));
            creditAccMap[msg.sender] = creditAccArray;
        }else if(!existCreditor(msg.sender, creditor)){
            creditAccMap[msg.sender].push(CreditAcc(creditor, amount));
        }else {
            CreditAcc[] storage caArr = creditAccMap[msg.sender];
            for(uint i = 0; i < caArr.length; i++){
                if(caArr[i].creditor == creditor)
                    caArr[i].amount += amount;
            }
        }
        
        if(!existUser(creditor)) users.push(creditor);
        if(!existUser(msg.sender)) users.push(msg.sender);
    }
    
    //----------------------------------------------------------
    //helper functions
    //----------------------------------------------------------
    function existAnyCreditor(address debtor) private view returns(bool){
        if(creditAccMap[debtor].length == 0) return false;
        return true;
    }
    
    function existCreditor(address debtor, address creditor) private view returns(bool){
        if(!existAnyCreditor(debtor)) return false;
        CreditAcc[] memory caArr = creditAccMap[debtor];
        for(uint i = 0; i < caArr.length; i++){
            if(caArr[i].creditor == creditor)
                return true;
        }
        return false;
    }
    
    function existUser(address u)private view returns(bool){
        for(uint i = 0; i < users.length; i++){
            if(users[i] == u) return true;
        }        
        return false;
    }
}

猜你喜欢

转载自blog.csdn.net/liangyihuai/article/details/115913338
今日推荐