一、意義:
在上一節課中,我們已經能基於以太坊智能合約做一些簡單的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的其他功能