26.众筹合约开发流程

本文详细介绍了众筹平台的开发流程,包括智能合约的环境配置、编写、部署,以及前端页面的构建和API调用。通过React创建项目,使用web3.js与智能合约交互,实现众筹功能。
摘要由CSDN通过智能技术生成

下面开始实现众筹平台的开发流程详解

第一部分 智能合约处理

1.环境配置

  1. 安装react 并创建项目
    注意:你首先要把npm (node)环境装好
    下载 react
npm install create -react-app  -g

创建react项目

create-react-app lottery-eth

测试是否安装成功,进入目录

npm run start
  1. 然后安装引用 web3
npm i  web3
  1. 安装 编译器 solc
npm i  solc
  1. 安装mocha测试框架
npm  i mocha
  1. 配置组件库
npm install --save semantic-ui-css
npm install --save semantic-ui-react
  1. 测试各个环境是否整合,开始开发…gogogogoo

  2. 下载本地版本巧克力

npm i ganache-cli - g

启动本地巧克力

ganache-cli -p 8545 

2.编写智能合约

众筹智能合约

pragma solidity^0.4.24;
contract FundingFactory {
   
    address public platformManager; //平台的管理员
    address[] fundingsAarry; //存储所有已经创建好的合约地址
    mapping(address => address[]) creatorFundingsArray; //找到项目方所创建的所有众筹项目:
    //mapping(address => address[]) supportFundingsArray; //找到所有自己参与过的合约项目
    SupporterFunding supporterFunding; //地址是零,一定要实例化
    constructor() {
   
        platformManager = msg.sender;
        supporterFunding = new SupporterFunding();//一定要实例化
    }
    //提过一个创建合约的方法
    function createFunding(string _projectName, uint256 _supportMoney, uint256 _targetMoney, uint256 _durationTime) {
   
        address funding = new Funding(_projectName, _supportMoney, _targetMoney,
            _durationTime, msg.sender, supporterFunding);
        fundingsAarry.push(funding);
        creatorFundingsArray[msg.sender].push(funding); //维护项目发起人的所有众筹集合
    }
    function getAllFundings() public view returns(address[]) {
   
        return fundingsAarry;
    }
    function getCreatorFundings() public view returns(address[]) {
   
        return creatorFundingsArray[msg.sender];
    }
    function getSupporterFundings() public view returns(address[]) {
   
        return supporterFunding.getFunding(msg.sender);
    }
}

contract SupporterFunding {
   
    mapping(address => address[]) supportFundingsArray; 找到所有自己参与过的合约项目
    //提供一个添加方法, //--> 在support时候调用
    function joinFunding(address addr, address funding) {
   
        supportFundingsArray[addr].push(funding);
    }
    //提供一个读取方法,
    function getFunding(address addr) public returns (address[]) {
   
        return supportFundingsArray[addr];
    }
}
//crow-funding
contract Funding {
   
    address public manager;
    // 1. 名字:众筹牙刷
    string public projectName;
    // 2. 需要每个投资人投多少钱:38元
    uint256 public supportMoney;
    // 3. 总共要集资多少钱:100000
    uint256 public targetMoney;
    // 4. 众筹截止时间:30天 //2592000s
    uint256 endTime;
    mapping(address=> bool) supporterExistMap;
    SupporterFunding supporterFunding;
    // constructor(string _projectName, uint256 _supportMoney, uint256 _targetMoney,
    // uint256 _durationTime, address _creator,  mapping(address => address[]) _supportFundingsArray) public {
   
    constructor(string _projectName, uint256 _supportMoney, uint256 _targetMoney,
        uint256 _durationTime, address _creator, SupporterFunding _supporterFunding) public {
   
        // manager = msg.sender;
        manager = _creator; //把项目发起人的地址传递过来,否则就是合约工厂的地址了
        projectName = _projectName;
        supportMoney = _supportMoney;
        targetMoney = _targetMoney;
        endTime = now + _durationTime;  //传递进来众筹持续的时间,单位为秒,now 加上这个值,就能算出项目截止时间
        supporterFunding = _supporterFunding;
    }
    address[] supporters; //记录投资人的地址集合
    //投资人投钱,记录投资的地址
    function support() public payable {
   
        require(msg.value == supportMoney); //wei
        supporters.push(msg.sender);
        //每次赞助之后,都使用一个map来记录投资人,便于后续快速检查
        supporterExistMap[msg.sender] = true;
        //supportFundingsArray[msgr]
        //对传递过来的SupportFunding的结构进行赋值
        supporterFunding.joinFunding(msg.sender, this);
    }
    //退款
    function refund() onlyManager public {
   
        for (uint256 i = 0; i< supporters.length; i ++) {
   
            supporters[i].transfer(supportMoney);
        }
        //delete supporters;
    }
    enum RequestStatus {
    Voting, Approved, Completed}
    //modifier
    struct Request {
   
        // 1. 要做什么:买电池
        string purpose;
        // 2. 卖家地址:0x1234xxx
        address seller;
        // 3. 多少钱:10元
        uint256 cost;
        // 4. 当前赞成的票数:10票
        uint256 approveCount;
        // 5. 有一个集合,记录投资人投票的状态:投过票,true,未投:false
        mapping(address => bool) voteStatus;  //每个地址智能support一次   //没有make(map[uint]string)
        //voteStatus[0x111] = true
        RequestStatus status;
    }
    //项目方可以创建多个请求,需要一个数组记录
    Request[] public requests;
    function createRequest(string _purpose, address _seller, uint256 _cost) onlyManager public {
   
        Request memory req = Request({
   purpose: _purpose, seller: _seller, cost: _cost, approveCount: 0, status : RequestStatus.Voting});
        requests.push(req);
    }
    //投资人批准:默认不投票:no,主动投票:yes
    function approveRequest(uint256 index) public {
   
        // 投资者调用approveRequest
        // 1. 找到这个请求
        // 限定:只有投资人才可以投票
        // 2. 检查自己没有投过票
        // 3. 投票
        // 4. 标志自己已经投过票了
        //bool flag = false;
        // Flag 来记录遍历数组的结果,
        // True表示:是投资人
        // False表示:非投资人,直接退出
        // require(supporterExistMap[msg.sender] == true);
        require(supporterExistMap[msg.sender]);
        Request storage req = requests[index];
        //检查,如果不是投票状态(Compete或者Approved),就不用投票了
        require(req.status == RequestStatus.Voting);
        //这种使用for遍历的方式一定要小心, 尽量不要使用,消耗gas非常多
        // for (uint i = 0 ; i < supporters.length; i++) {
   
        //     if (supporters[i] == msg.sender) {
   
        //         flag = true;
        //         break;
        //     }
        //     // break;
        // }
        // require(flag);
        require(req.voteStatus[msg.sender] ==  false);
        req.approveCount++;
        req.voteStatus[msg.sender] =  true;
    }
    //项目方可以花费这笔钱。
    function finalizeReqeust(uint256 index) onlyManager public {
   
        Request storage req = requests[index];
        // 1. 检查当前余额是否满足支付
        require(address(this).balance >= req.cost);
        // 2. 检查赞成人数是否过半
        require(req.approveCount *2  > supporters.length);
        // 3. 向卖家转账
        req.seller.transfer(req.cost);
        // 4. 改变这个request的状态为Completed
        req.status  = RequestStatus.Completed;
    }
    modifier onlyManager {
   
        require(msg.sender == manager);
        _;
    }
    function getBalance() public view returns(uint256) {
   
        return address(this).balance;
    }
    function getSupporters() public view returns(address[]) {
   
        return supporters;
    }
}


编写智能合约的步骤就略过了

3.准备目录结构

在这里插入图片描述

4.编写compile.js

这个文件的目的是为了编译sol文件,编译成二进制文件等

let solc = require('solc')
let fs = require('fs')
//.sol合约
let source =  fs.readFileSync('./contracts/fundingFactory.sol', 'utf-8')
// console.log('source :', source)
let output = solc.compile(source, 1)
 // console.log('output :', output)
module.exports = output['contracts'][':FundingFactory']

5.编写deploy.js

这个文件的目的是为了把编译后的文件部署到本地的区块链即巧克力,返回abi和合约地址

let Web3 = require('web3')
let {
   interface, bytecode} = require('./compile')
let web3 = new Web3()
web3.setProvider(new Web3.providers.HttpProvider('http://localhost:8545'))
deploy = async () => {
   
    try {
   
        //获取部署账户
        accounts = await web3.eth.getAccounts()
        contractInstance = await new web3.eth.Contract(JSON.parse(interface)).deploy(
            {
   
                data: bytecode
                // arguments: ['']// 构造函数如果没有参数,就一定不要传
            }
        ).send({
   
            from: accounts[0],
            gas: '5000000' //1000000太少了,无法完成部署,1千万又超过了区块的容量
        })
        console.log('address :', contractInstance.options.address)
    } catch (e) {
   
        console.log(e)
    }
}
deploy()

6.部署智能合约

首先要开启本地巧克力服务器

ganache-cli -p 8545 

编译sol文件,产生二进制编码格式文件

node compile.js

部署智能合约文件,返回abi和合约地址

node deploy.js

7.整合文件目录

联系第二部分

第二部分 前端页面和调用api处理

这里主要是前端页面通过web3.js调用api,用的是react框架

1.显示目录结构

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.compile.js ,deploy.js

在这里插入图片描述

let solc = require('solc')
let fs = require('fs')

//.sol合约
let source =  fs.readFileSync('./contracts/fundingFactory.sol', 'utf-8')
// console.log('source :', source)

let output = solc.compile(source, 1)
// console.log('output :', output)

module.exports = output['contracts'][':FundingFactory']
let Web3 = require('web3')
let {
   interface, bytecode} = require('./compile')
let web3 = new Web3()
web3.setProvider(new Web3.providers.HttpProvider('http://localhost:8545'))
deploy = async () => {
   
    try {
   
        //获取部署账户
        accounts = await web3.eth.getAccounts()
        contractInstance = await new web3.eth.Contract(JSON.parse(interface)).deploy(
            {
   
                data: bytecode
                // arguments: ['']// 构造函数如果没有参数,就一定不要传
            }
        ).send({
   
            from: accounts[0],
            gas: '5000000' //1000000太少了,无法完成部署,1千万又超过了区块的容量
        })
        console.log('address :', contractInstance.options.address)
    } catch (e) {
   
        console.log(e)
    }
}
deploy()

3.src中文件 App.js,index.js

在这里插入图片描述

App.js

import React, {
    Component } from 'react';
import web3 from './utils/getWeb3'
import {
   fundingFactoryContract} from './eth/contracts'
import TabExampleBasic from "./display/centerTab";
class App extends Component {
   
    constructor() {
   
        super()
        this.state= {
   
            platformManager : '',
            currentAccount : '',
        }
    }
    async componentDidMount() {
   
        let accounts = await  web3.eth.getAccounts()
        let platformManager = await fundingFactoryContract.methods.platformManager().call({
   
            from : accounts[0]
        })
        this.setState({
   
            currentAccount : accounts[0],
            platformManager,
        })
    }
  render() {
   
        let {
   platformManager, currentAccount, allFundings} = this.state
    return (
      <div className="App">
          <p>平台管理员地址: {
   platformManager}</p>
          <p>当前账户地址: {
   currentAccount}</p>
          <p>当前所有合约地址: {
   allFundings}</p>
          <TabExampleBasic/>
      </div>
    );
  }
}
export default App;

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import 'semantic-ui-css/semantic.min.css'
ReactDOM.render(<App />, document.getElementById('root'));

3.src中文件夹中display中文件

在这里插入图片描述
点击进去目录结构
在这里插入图片描述

CardList.js

import React from 'react'
import {
    Card, Image, Icon, Progress, List } from 'semantic-ui-react'
<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值