帶你玩轉區塊鏈--實現Dapp衆籌項目-第二章-第二節【以太坊篇】

一、意義:

          在上一節課中,我們已經能基於以太坊智能合約做一些簡單的Dapp應用了,但在真正生成環境中,這些知識遠遠不夠。爲了更好的掌握這部分知識,在這一節中,我們通過一個新項目(衆籌)來加強和學習新的知識點。廢話不多說,我們言歸正傳。

項目簡介:       

       衆籌是指用團購+預購的形式,向網友募集項目資金的模式。衆籌利用互聯網SNS傳播的特性,讓小企業藝術家或個人對公衆展示他們的創意,爭取大家的關注和支持,進而獲得所需要的資金援助。在傳統衆籌項目中,資金難以監管、追溯。參與方是擁有很大風險,因爲項目方可以融資後拿錢跑路。通過前幾節課的學習,我們知道區塊鏈就是一個超級數據庫,不可修改,可追溯。所以我們考慮在技術上通過區塊鏈改進衆籌項目。

---------------------------------------------------------------------------------------------------------------------------------------

如果您改進了代碼或者想對照代碼學習,請訪問我的Github。

如果您有問題想要討論。請加我微信:laughing_jk(加我,請備註來源,謝謝)

衆籌項目源碼:https://github.com/lsy-zhaoshuaiji/FundingFactory

---------------------------------------------------------------------------------------------------------------------------------------

二、需求分析:

1.每個用戶都能參與項目和發佈項目

2.衆籌總金額等於基本籌金乘以份數,每份衆籌金一樣。

3.項目方可設置一個時間段和份數值,若在某個時間段衆籌份數小於某個值,則代表衆籌失敗,進行合約退款。

4.項目方提出一個花費請求,每個人都有投票的權利,投票後結果不可更改,不可逆。

5.項目方提出一個花費請求,1/2參與人投票贊成票,則代表通過協議。若少於1/2,則不可花費該資金。

6.花費請求通過後,可以手動向某個特點地址進行付款。

三、概要設計

由於該項目中,弱化了項目方的權利,且產生的數據具有可追溯性,不可修改性,所以我們需要在項目中引入以太坊智能合約。該項目採用(B/S架構),具體設計如下:

1.底層使用ETH智能合約實現該項目的數據存儲、 (數據庫模塊)

2.使用React實現前端與用戶的交互                        ( 前端模塊)

3.使用node.js/web3實現對智能合約的控制和交互 ( 後臺模塊)

四、詳細設計

由於我們設計的是衆籌平臺,在平臺中存在多個衆籌項目,一個項目對應着一個合約。所以平臺中可能存在多個智能合約。我們把控制多個智能合約的總合約叫做工廠合約(FundingFactorty)。把控制本身項目的合約叫做單例合約(Funding)。

4.1合約編寫

4.1.1、思維導圖如下圖:

 

4.1.2、單例模式能合約代碼

pragma solidity ^0.4.24;
import './fundingFactory.sol';

contract Findding{
    address public manager;
    string public projectName;
    uint256 public targetMoney;
    uint256 public supportMoney;
    uint256 public endTime;
    address [] public Investors;
    SupportFundingContract supportFundings;
    enum RequestStatus{
        Voting,Approving,Completed
    }  
    struct Request{
        string purpose;
        uint256 cost;
        address seller;
        uint256 approvedCount;
        RequestStatus status;
        mapping(address => bool) isVoteMap;
        
    }
    Request [] public allRequests;
    mapping(address=>bool) public isInverstorMap;
    constructor(string _projectName,uint256 _targetMoney,uint256 _supportMoney,uint256 _duration,address _creator,SupportFundingContract _supportFundings) public{
        manager=_creator;
        projectName=_projectName;
        targetMoney=_targetMoney;
        supportMoney=_supportMoney;
        endTime=block.timestamp+_duration;
        supportFundings=_supportFundings;
    }
    //"大黃蜂",10,5,3600
    //"sfsdfsd",5,"0xca35b7d915458ef540ade6068dfe2f44e8fa733c"
    
    modifier OnlyManager(){
        require(msg.sender==manager);
        _;
    }
    function getLastTime()public view returns(uint256){
        return endTime-block.timestamp;
    }
    function InverstorCount()public view returns(uint256){
        return Investors.length;
    }
    function getRequestCount()view public returns(uint256){
        return allRequests.length;
    }
    function Invers() payable public {
        require(supportMoney*10**18==msg.value);
        isInverstorMap[msg.sender]=true;
        Investors.push(msg.sender);
        supportFundings.setFunding(msg.sender,this);
    }
    function Refund() OnlyManager public{
        for (uint256 i=0;i<Investors.length;i++){
            Investors[i].transfer(supportMoney);
        }
        delete Investors;
    }
    function createRequest(string _purpose,uint256 _cost,address _seller)OnlyManager public{
        Request memory req=Request({
            purpose:_purpose,
            cost:_cost,
            seller:_seller,
            approvedCount:0,
            status:RequestStatus.Voting
        });
        allRequests.push(req);
    }
    function approveRequest(uint256 i)public {
        require(isInverstorMap[msg.sender]);
        Request storage req=allRequests[i];
        require(req.isVoteMap[msg.sender]==false);
        req.approvedCount++;
        req.isVoteMap[msg.sender]=true;
    }
    
    function getRequestIndex(uint256 i) public view returns(string,uint256,address,uint256,RequestStatus){
        /*
        string purpose;
        uint256 cost;
        address seller;
        uint256 approvedCount;
        RequestStatus status;
        */
        Request memory req=allRequests[i];
        return(req.purpose,req.cost,req.seller,req.approvedCount,req.status);
    }
    function getBalance() public view returns(uint256){
        return address(this).balance;
    }
    function finalizeRequest(uint256 i) OnlyManager public{
        Request storage req=allRequests[i];
        require(address(this).balance >= req.cost*10**18);
        require(req.approvedCount *2 >=Investors.length);
        req.seller.transfer(req.cost*10**18);
        req.status=RequestStatus.Completed;
    }
}

4.1.3、工廠模式智能合約代碼

pragma solidity ^0.4.24;
import './Test.sol';


contract FundingFactory{
    address public superManager;
    address [] allFundings;
    mapping(address=>address[]) public createFundings;
    // mapping(address=>address[]) public joinFundings;
    SupportFundingContract supportFundings= new SupportFundingContract();
    
    constructor()public{
        superManager=msg.sender;
    }
    
    function createFundingFactory(string _projectName,uint256 _targetMoney,uint256 _supportMoney,uint256 _duration) public{
        address funding=new Findding(_projectName, _targetMoney, _supportMoney, _duration,msg.sender,supportFundings);
        allFundings.push(funding);
        createFundings[msg.sender].push(funding);
    }
    
    function getAllFundings()public view returns(address []){
        return allFundings;
    }
    function getCreateFundings()public view returns(address[]){
        return createFundings[msg.sender];
    }
    function getSupportFundings()view public returns(address []){
        return supportFundings.getFunding(msg.sender);
    }
}

contract SupportFundingContract{
    mapping(address => address[]) joinFundings;
    function setFunding(address _support,address _funding) public {
        joinFundings[_support].push(_funding);
    }
    function getFunding(address _support)public view returns(address []){
        return joinFundings[_support];
    }
}

4.1.4、全局交互合約

在衆籌統計與自己相關的合約時,單例合約需要調用工廠合約的參與者 mapping(address => address [])字段,而在solidity中無法傳遞複雜參數。由於合約的本質就是地址,地址在solidity中是可以傳遞的,所以這時候我們需要在創建一個合約,來專門複雜添加/獲取與自己相關的合約。

contract SupportFundingContract{
    mapping(address => address[]) joinFundings;
    function setFunding(address _support,address _funding) public {
        joinFundings[_support].push(_funding);
    }
    function getFunding(address _support)public view returns(address []){
        return joinFundings[_support];
    }
}

4.2創建Dapp項目部署合約

4.2.1、準備工作

create-react-app dapp
cd lottery-react
npm install [email protected]
npm install web3
npm install [email protected]
npm i semantic-ui-react
npm i semantic-ui-css
 
//如果報錯,就不要擔憂,只要package.json裏面有上述模塊,且能使用就行

在安裝後所需依賴後,

1.清理react工程,刪除src中除App.js/index.js以外的所有內容,並在src中創建display、eth、utils目錄

2.在display中創建ui.js 來編寫該項目的前端組件;

3.eth文件夾中創建FundingFactory.js與合約進行交互,

4.在utils創建initWeb3.js,獲取用戶metamask中傳來的web3對象。

4.2.2、創建01-compile.js、02-deploy.js

上節課程中,我們經常創建這兩個文件。我就多不解釋了。這兩個文件是用來編譯、部署合約的。但在此項目中由於出現了兩個合約,在node.js編譯中 會出現引用報錯。所以這裏建議兄弟們,將兩個合約寫在一個合約中,或者直接用remix部署到rosten測試網中後,用web3獲取合約對象。這裏,爲了方法調試代碼我們建議兄弟們先將兩個合約寫在一個合約中用node.js編譯,在編碼過程結束後再直接部署到rosten測試網中。

//01-compile.js
let fs=require('fs');
let solc=require('solc');

let data=fs.readFileSync('./contracts/FundingFactory.sol','utf-8');

let output=solc.compile(data,1);


module.exports = output['contracts'][':FundingFactory'];


//deploy.js
let {interface,bytecode}=require('./01-compile');

let Web3=require('web3');
let web3= new Web3();

web3.setProvider('http://127.0.0.1:8545');

let contract=new web3.eth.Contract(JSON.parse(interface));
let deploy=async ()=>{
    try {
        let accounts = await web3.eth.getAccounts();
        console.log('accounts :', accounts);
        let instance = await contract.deploy({
            data: bytecode,
        }).send({
            from: accounts[0],
            gas: '5000000',
        });
        console.log(instance.options.address);
        module.exports = instance
    } catch (e) {
        console.log(e)
    }
};

deploy();

4.2.3、編寫initWeb3.js/獲取用戶端web3

老版本的metamask(小狐狸)不需要授權、只需要用web3.eth.currentProvider

即可獲取web3對象。新版本中的metamask需要先授權,才能獲取web3對象、我們通過window.ethereum先判斷是否爲新版本

let Web3=require('web3');
let web3=new Web3();
let web3Provider;
if (window.ethereum) {
    web3Provider = window.ethereum;
    try {
        // 請求用戶授權
        window.ethereum.enable().then()
    } catch (error) {
        // 用戶不授權時
        console.error("User denied account access")
    }
} else if (window.web3) {   // 老版 MetaMask Legacy dapp browsers...
    web3Provider = window.web3.currentProvider;
}
web3.setProvider(web3Provider);//web3js就是你需要的web3實例

web3.eth.getAccounts(function (error, result) {
    if (!error)
        console.log(result,"")//授權成功後result能正常獲取到賬號了
});
module.exports =web3;

4.2.4、編寫FunningFactory.js/獲取合約實例

let web3= require('../utils/initWeb3');


let abi=[....]//填你自己的ABI
let address='0xE0C2A2f2d0697410D8399c22fff3BAC69F5A5B0E';
let contractInstance=new web3.eth.Contract(abi,address);
console.log(contractInstance.options.address,"oooooooooooooooooooooo");
module.exports=contractInstance;

4.3搭建項目框架、實現合約與前端交互

4.3.1創建createFunningTab組件,實現數據顯示

1.修改FundingFactory.js,實現工廠合約與單例合約對象,爲了顯示單例合約中的詳細信息。單例合約返回創建方法

let web3 = require('../utils/initWeb3');
let abi=....
let address='0xe8bf0428371d6ddfeeba85d2451edea443bb8edf';
let FactoryInstance=new web3.eth.Contract(abi,address);
console.log(FactoryInstance.options.address,"oooooooooooooooooooooo");
//單例合約
let FunningABI=....
let newFunningInstance=()=>{
  return new web3.eth.Contract(FunningABI);
};
module.exports={
    FactoryInstance,
    newFunningInstance,
};

  2. 在display文件夾中創建createFunningTab文件夾並創建createFunning.js,並在該文件中獲取單例合約,並調用單例合約方法獲取單例合約信息。

import React from 'react';
import {Component}from 'react'
import {detailsPromise} from '../../eth/interaction'
import CardList from "../comm/comm";
class CreateFundingTab extends Component{

    state={
        createDetailInfo:[],
    };
    async componentWillMount(){
        let createDetailInfo=await detailsPromise();
        // detailInfo.then(details=>{
        //    console.log(details);
        // });
        console.table(createDetailInfo,"wwwwwwwwwwwwwwwwwww");
        this.setState({
            createDetailInfo,
        })
    }
    render(){
        return(
            <CardList detailInfo={this.state.createDetailInfo}/>
        )
    }
}
export default CreateFundingTab;

在eth文件夾創建interaction.js實現promise封裝:

let {FactoryInstance,newFunningInstance}=require('../eth/FundingFactory');
let detailsPromise=async (index)=>{
    let currentFunding=[];
    if (index === 1){
        currentFunding=await FactoryInstance.methods.getAllFundings().call();
    }else if (index === 2){
       currentFunding=await FactoryInstance.methods.getCreateFundings().call();
    }else {
        currentFunding=await FactoryInstance.methods.getSupportFundings().call();
    }
    let details=currentFunding.map(function (v) {
        return new Promise(async (resolve, reject) => {
            try {
                let Funding = newFunningInstance();
                Funding.options.address = v;
                let address=v;
                let manager = await Funding.methods.manager().call();
                let projectName = await Funding.methods.projectName().call();
                let targetMoney = await Funding.methods.targetMoney().call();
                let supportMoney = await Funding.methods.supportMoney().call();
                let endTime = await Funding.methods.endTime().call();
                let balance=await Funding.methods.getBalance().call();
                let InverstorCount=await Funding.methods.InverstorCount().call();
                let detail = {balance,InverstorCount,address,manager, projectName, targetMoney, supportMoney, endTime};
                resolve(detail)
            } catch (e) {
                reject(e)
            }
        });
    });
    let detailInfo=Promise.all(details);
    return detailInfo
};

export {
    detailsPromise,
}

在src/display/comm文件夾中的comm.js,進行前端渲染:

import React from 'react'
import { Card,List, Image,Progress } from 'semantic-ui-react'
const imageSrc = 'img/logo.png';

const CardList = (props) => {
   let details=props.detailInfo;
   let cards=details.map(detail=>{
       return <CardExample key={detail.address} detail1={detail} />
   });

  return (
      <Card.Group itemsPerRow={4}>
          {
              cards
          }
      </Card.Group>
  )
};
const CardExample = (props) => {
    let detail2=props.detail1;
    let {balance,InverstorCount,address,manager, projectName, targetMoney, supportMoney, endTime}=detail2;
    let percent=parseFloat(balance)/parseFloat(targetMoney)*100;
    return (
        <Card>
            <Image src={imageSrc} wrapped ui={false} />
            <Card.Content>
                <Card.Header>{projectName}</Card.Header>
                <Card.Meta>
                    <span className='date'>剩餘時間:{endTime}</span>
                    <Progress percent={percent} progress size='small'/>
                </Card.Meta>
                <Card.Description>
                    衆籌目標:{targetMoney} Wei
                </Card.Description>
            </Card.Content>
            <Card.Content extra>
                <List horizontal style={{display: 'flex', justifyContent: 'space-around'}}>
                    <List.Item>
                        <List.Content>
                            <List.Header>已籌</List.Header>
                            {balance} wei
                        </List.Content>
                    </List.Item>
                    <List.Item>
                        <List.Content>
                            <List.Header>已達</List.Header>
                            {percent}%
                        </List.Content>
                    </List.Item>
                    <List.Item>
                        <List.Content>
                            <List.Header>參與人數</List.Header>
                            {InverstorCount}
                        </List.Content>
                    </List.Item>
                </List>
            </Card.Content>

        </Card>
    )
};

export default CardList

4.3.2創建allFunningTab組件

        在display文件夾中創建allFunningTab文件夾並創建allFunning.js(代碼實現與上相同 ,只需將interactoin.js的index改爲1即可)

4.3.3創建supportFunningTab組件

        在display文件夾中創建supportFunningTab文件夾並創建supportFunning.js(代碼實現與上相同 ,只需將interactoin.js的index改爲3即可)

4.3.3實現發起衆籌功能

創建createFundingForm.js

import React, {Component} from 'react';
import {Dimmer, Form, Label, Loader, Segment} from 'semantic-ui-react'
import {createFunding} from "../../eth/interaction";

class CreateFundingForm extends Component {
    state = {
        active: false,
        projectName: '',
        supportMoney: '',
        targetMoney: '',
        duration: '',
    }

    //表單數據數據變化時觸發
    handleChange = (e, {name, value}) => this.setState({[name]: value})
    handleCreate = async () => {
        let {active, projectName, targetMoney, supportMoney, duration} = this.state
        console.log('projectName:', projectName)
        console.log('targetMoney:', supportMoney)
        this.setState({active: true})

        try {
            let res = await createFunding(projectName, targetMoney, supportMoney, duration)
            alert(`創建合約成功!\n`)
            this.setState({active: false})

        } catch (e) {

            this.setState({active: false})
            console.log(e)
        }
    }

    render() {
        let {active, projectName, targetMoney, supportMoney, duration} = this.state

        return (
            <div>
                <Dimmer.Dimmable as={Segment} dimmed={active}>
                    <Dimmer active={active} inverted>
                        <Loader>Loading</Loader>
                    </Dimmer>
                    <Form onSubmit={this.handleCreate}>
                        <Form.Input required type='text' placeholder='項目名稱' name='projectName'
                                    value={projectName} label='項目名稱:'
                                    onChange={this.handleChange}/>

                        <Form.Input required type='text' placeholder='支持金額' name='supportMoney'
                                    value={supportMoney} label='支持金額:'
                                    labelPosition='left'
                                    onChange={this.handleChange}>
                            <Label basic>¥</Label>
                            <input/>
                        </Form.Input>

                        <Form.Input required type='text' placeholder='目標金額' name='targetMoney' value={targetMoney}
                                    label='目標金額:'
                                    labelPosition='left'
                                    onChange={this.handleChange}>
                            <Label basic>¥</Label>
                            <input/>
                        </Form.Input>
                        <Form.Input required type='text' placeholder='目標金額' name='duration' value={duration}
                                    label='衆籌時間:'
                                    labelPosition='left'
                                    onChange={this.handleChange}>
                            <Label basic>S</Label>
                            <input/>
                        </Form.Input>
                        <Form.Button primary content='創建衆籌'/>
                    </Form>
                </Dimmer.Dimmable>
            </div>
        )
    }
}

export default CreateFundingForm

修改interaction.js,與合約進行交互

let web3 = require('../utils/initWeb3');
let {FactoryInstance,newFunningInstance}=require('../eth/FundingFactory');
let detailsPromise=async (index)=>{
    let currentFunding=[];
    if (index === 1){
        currentFunding=await FactoryInstance.methods.getAllFundings().call();
    }else if (index === 2){
       currentFunding=await FactoryInstance.methods.getCreateFundings().call();
    }else {
        currentFunding=await FactoryInstance.methods.getSupportFundings().call();
    }
    let details=currentFunding.map(function (v) {
        return new Promise(async (resolve, reject) => {
            try {
                let Funding = newFunningInstance();
                Funding.options.address = v;
                let address=v;
                let manager = await Funding.methods.manager().call();
                let projectName = await Funding.methods.projectName().call();
                let targetMoney = await Funding.methods.targetMoney().call();
                let supportMoney = await Funding.methods.supportMoney().call();
                let endTime = await Funding.methods.endTime().call();
                let balance=await Funding.methods.getBalance().call();
                let InverstorCount=await Funding.methods.InverstorCount().call();
                let detail = {balance,InverstorCount,address,manager, projectName, targetMoney, supportMoney, endTime};
                resolve(detail)
            } catch (e) {
                reject(e)
            }
        });
    });
    let detailInfo=Promise.all(details);
    return detailInfo
};
let createFunding=(projectName, targetMoney, supportMoney, duration)=>{
  return new Promise(async (resolve, reject) => {
      // function createFundingFactory(string _projectName,uint256 _targetMoney,uint256 _supportMoney,uint256 _duration) public{
      try {
          let accounts = await web3.eth.getAccounts();
          let instance = await FactoryInstance.methods.createFundingFactory(projectName, targetMoney, supportMoney, duration).send({
              from: accounts[0],
          });
          resolve(instance)
      } catch (e) {
          reject(e)
      }
  })
};
export {
    detailsPromise,
    createFunding,
}

4.3.3實現參與衆籌功能

修改allfundingTab

import React from 'react';
import {Component}from 'react'
import {detailsPromise,handleInvestFunc} from '../../eth/interaction'
import CardList from "../comm/comm";
import {Dimmer, Form, Label, Loader, Segment} from 'semantic-ui-react'
class AllFundingTab extends Component{

    state={
        active: false,
        allFundingTab:[],
        seletedFundingDetail: ''
    };
    async componentWillMount(){
        let allFundingTab=await detailsPromise(1);
        console.table(allFundingTab,"wwwwwwwwwwwwwwwwwww");
        this.setState({
            allFundingTab,
        })
    }
    onCardClick = (seletedFundingDetail) => {
        console.log("aaa :", seletedFundingDetail);
        this.setState({
            seletedFundingDetail
        })
    };
    handleInvest = async () => {
        let {balance,InverstorCount,address,manager, projectName, targetMoney, supportMoney, endTime} = this.state.seletedFundingDetail;
        //需要傳遞選中合約地址
        //創建合約實例,參與衆籌(send, 別忘了value轉錢)
        this.setState({active: true})

        try {
            let res = await handleInvestFunc(address, supportMoney)
            this.setState({active: false})
            console.log('1111111')

        } catch (e) {

            this.setState({active: false})
            console.log(e)
        }
    }

    render(){
        let {balance,InverstorCount,address,manager, projectName, targetMoney, supportMoney, endTime} = this.state.seletedFundingDetail;
        return(
            <div>
                <CardList detailInfo={this.state.allFundingTab} onCardClick={this.onCardClick} />
                <div>
                <h3>參與衆籌</h3>
                <Dimmer.Dimmable as={Segment} dimmed={this.state.active}>
                    <Dimmer active={this.state.active} inverted>
                        <Loader>支持中</Loader>
                    </Dimmer>
                    <Form onSubmit={this.handleInvest}>
                        <Form.Input type='text' value={projectName || ''} label='項目名稱:'/>
                        <Form.Input type='text' value={address || ''} label='項目地址:'/>
                        <Form.Input type='text' value={supportMoney || ''} label='支持金額:'
                                    labelPosition='left'>
                            <Label basic>¥</Label>
                            <input/>
                        </Form.Input>

                        <Form.Button primary content='參與衆籌'/>
                    </Form>
                </Dimmer.Dimmable>
                </div>
            </div>
        )
    }
}
export default AllFundingTab;

修改comm.js

import React from 'react'
import { Card,List, Image,Progress } from 'semantic-ui-react'
const imageSrc = 'img/logo.png';

const CardList = (props) => {
   let details=props.detailInfo;
   let onCardClick=props.onCardClick
   let cards=details.map(detail=>{
       return <CardExample key={detail.address} detail1={detail}  onCardClick={onCardClick} />
   });

  return (
      <Card.Group itemsPerRow={4}>
          {
              cards
          }
      </Card.Group>
  )
};

const CardExample = (props) => {
    let detail2=props.detail1;
    let {balance,InverstorCount,address,manager, projectName, targetMoney, supportMoney, endTime}=detail2;
    let percent=parseFloat(balance)/parseFloat(targetMoney)*100;
    return (
        <Card onClick={()=>props.onCardClick(detail2)}>
            <Image src={imageSrc} wrapped ui={false} />
            <Card.Content>
                <Card.Header>{projectName}</Card.Header>
                <Card.Meta>
                    <span className='date'>剩餘時間:{endTime}</span>
                    <Progress percent={percent} progress size='small'/>
                </Card.Meta>
                <Card.Description>
                    衆籌目標:{targetMoney} Wei
                </Card.Description>
            </Card.Content>
            <Card.Content extra>
                <List horizontal style={{display: 'flex', justifyContent: 'space-around'}}>
                    <List.Item>
                        <List.Content>
                            <List.Header>已籌</List.Header>
                            {balance} wei
                        </List.Content>
                    </List.Item>
                    <List.Item>
                        <List.Content>
                            <List.Header>已達</List.Header>
                            {percent}%
                        </List.Content>
                    </List.Item>
                    <List.Item>
                        <List.Content>
                            <List.Header>參與人數</List.Header>
                            {InverstorCount}
                        </List.Content>
                    </List.Item>
                </List>
            </Card.Content>

        </Card>
    )
};

export default CardList

修改interaction.js

let web3 = require('../utils/initWeb3');
let {FactoryInstance,newFunningInstance}=require('../eth/FundingFactory');
let detailsPromise=async (index)=>{
    let currentFunding=[];
    if (index === 1){
        currentFunding=await FactoryInstance.methods.getAllFundings().call();
    }else if (index === 2){
        console.log("uuuuuuuuuuuuuuuuuuuuuuuuuu")
        currentFunding=await FactoryInstance.methods.getCreateFundings().call();
        console.log("currentFunding:",currentFunding)
    }else if (index === 3){
        currentFunding=await FactoryInstance.methods.getSupportFundings().call();
    }
    let details=currentFunding.map(function (v) {
        return new Promise(async (resolve, reject) => {
            try {
                let Funding = newFunningInstance();
                Funding.options.address = v;
                let address=v;
                let manager = await Funding.methods.manager().call();
                let projectName = await Funding.methods.projectName().call();
                let targetMoney = await Funding.methods.targetMoney().call();
                let supportMoney = await Funding.methods.supportMoney().call();
                let endTime = await Funding.methods.endTime().call();
                let balance=await Funding.methods.getBalance().call();
                let InverstorCount=await Funding.methods.InverstorCount().call();
                let detail = {balance,InverstorCount,address,manager, projectName, targetMoney, supportMoney, endTime};
                resolve(detail)
            } catch (e) {
                reject(e)
            }
        });
    });
    let detailInfo=Promise.all(details);
    return detailInfo
};
let createFunding=(projectName, targetMoney, supportMoney, duration)=>{
  return new Promise(async (resolve, reject) => {
      // function createFundingFactory(string _projectName,uint256 _targetMoney,uint256 _supportMoney,uint256 _duration) public{
      try {
          let accounts = await web3.eth.getAccounts();
          let instance = await FactoryInstance.methods.createFundingFactory(projectName, targetMoney, supportMoney, duration).send({
              from: accounts[0],
          });
          resolve(instance)
      } catch (e) {
          reject(e)
      }
  })
};
let handleInvestFunc = (address, supportMoney) => {
    return new Promise(async (resolve, reject) => {
        try { //創建合約實例
            let fundingInstance = newFunningInstance()
            //填充地址
            fundingInstance.options.address = address

            let accounts = await web3.eth.getAccounts()

            let res = await fundingInstance.methods.Invers().send({
                    from: accounts[0],
                    value: supportMoney,
                }
            )
            resolve(res)
        } catch (e) {
            reject(e)
        }
    })
}
export {
    detailsPromise,
    createFunding,
    handleInvestFunc,
}

在solidity中使用了msg.sender就要使用from字段,不然會顯示報錯

4.3.4實現發起項目和項目投票

由於該功能依然是是react和合約的交互,所以在這裏就不放代碼了,如果有需要代碼的童鞋請去github上下載,

實現邏輯:1.在前端創建表單,2.通過表單傳遞函數到interaction中,3.在interaction中實現與合約的交互

五、項目總結

            該項目主要目的是實現工廠模式和單例模式的交互,在此部分中,我們需要謹記工廠模式的合約是可以直接獲取的,而單例合約的address需要傳遞後調用。其餘的便是react的知識,通過該項目我們更加熟悉了合約部分,接下來我們繼續研究ETH的其他功能

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章