本合約是一個(gè)比較完整的眾籌合約,含:新建眾籌項(xiàng)目,轉(zhuǎn)賬,打款,以及退款等功能!
編寫合約時(shí),可以直接在線上編寫和測試部署
聲明結(jié)構(gòu)體和變量
參與者只需記錄參與者的地址和捐贈的金額
struct funder {
address funderAddress; // 捐贈者地址
uint toMoney; // 捐贈money
}
發(fā)起者則需要較多的屬性,如:受益地址,目標(biāo)金額,是否募資完成等?。?!
另外,要通過funderMap(mapping)將捐贈者的id與捐贈者綁定在一起,從而得知是誰給受益人捐錢。
struct needer {
address payable neederAddress; // 受益人地址
uint goal; // 眾湊總數(shù)(目標(biāo))
uint amount; // 當(dāng)前募資金額
uint isFinish; // 募資是否完成
uint funderAccount; // 當(dāng)前捐贈者人數(shù)
mapping(uint => funder) funderMap; // 映射,將捐贈者的id與捐贈者綁定在一起,從而得知是誰給受益人捐錢
}
聲明發(fā)起眾湊的項(xiàng)目,并且通過neederMap(mapping)將受益人id與收益金額綁定在一起,從而可以更好的管理受益人
address payable owner; // 合約發(fā)起者地址
uint neederAmount; // 眾籌項(xiàng)目id
mapping (uint => needer) neederMap; // 通過mapping將受益人id與收益金額綁定在一起,從而可以更好的管理受益人
實(shí)例眾湊項(xiàng)目
create眾湊項(xiàng)目的時(shí)候,直接給定一個(gè)自增的序號當(dāng)作當(dāng)前眾湊項(xiàng)目的id。create項(xiàng)目時(shí),要根據(jù)前面聲明的needer結(jié)構(gòu)體實(shí)例,參數(shù)要一一對應(yīng)。
/*
* _neederAddress: 受益人地址(項(xiàng)目發(fā)起者)
* _goal: 眾籌目標(biāo)
*/
function NewNeeder(address payable _neederAddress, uint _goal) public {
owner = msg.sender;
neederAmount++;
neederMap[neederAmount] = needer(address(_neederAddress), _goal, 0, 0, 0);
}
捐贈者參與捐贈(轉(zhuǎn)賬)
捐贈可以根據(jù)眾湊項(xiàng)目id給該項(xiàng)目捐錢(轉(zhuǎn)賬),當(dāng)合約的方法發(fā)生轉(zhuǎn)賬時(shí)必須用到payable關(guān)鍵字。另外,要先校驗(yàn)捐贈者錢包余額夠不夠本次捐贈的余額,還有校驗(yàn)該項(xiàng)目是否已終止,判斷都有效的情況,此時(shí)會將本次捐贈的金額直接轉(zhuǎn)賬到當(dāng)前合約中,同時(shí)記錄捐贈人數(shù)和記錄捐贈者。
// 捐贈者給指定眾籌id打錢
/*
*_neederAmount: 眾籌項(xiàng)目id
*_address: 捐贈者地址
*/
function contribue(address _address, uint _neederAmount) public payable {
require(msg.value > 0);
needer storage _needer = neederMap[_neederAmount]; // 獲取眾籌項(xiàng)目
require(_needer.isFinish == 0); // 募資是否完成, 若完成則取消當(dāng)前捐款
_needer.amount += msg.value; // 捐贈金額
_needer.funderAccount++; // 捐贈者個(gè)數(shù)
_needer.funderMap[_needer.funderAccount] = funder(_address, msg.value); // 標(biāo)記捐贈者及捐贈金額
}
項(xiàng)目結(jié)束,轉(zhuǎn)賬給受益人(也是屬于轉(zhuǎn)賬)
結(jié)束項(xiàng)目的原因有多種,但是這里只是用捐贈完成的原因作為例子。捐贈完成后,可以由合約發(fā)起者(本合約中也是受益者)發(fā)起將合約的錢轉(zhuǎn)到自己的錢包地址中,這里同樣發(fā)生了交易,所以也要用到關(guān)鍵字payable。然而,我們發(fā)現(xiàn)該方法中有一個(gè)onlyOwner修飾詞,onlyOwner在下面會聲明,表示只能是合約發(fā)起者才能調(diào)用該方法。
// 捐贈是否完成,若完整,給受益人轉(zhuǎn)賬
/*
*_neederAmount: 眾籌項(xiàng)目id
*/
function Iscompelete(uint _neederAmount) public payable onlyOwner {
needer storage _needer = neederMap[_neederAmount]; // 獲取眾籌項(xiàng)目
require(_needer.amount >= _needer.goal);
_needer.neederAddress.transfer(_needer.amount);
_needer.isFinish = 1; // 若完成募資,則取消繼續(xù)募資
}
退錢(也是屬于轉(zhuǎn)賬)
當(dāng)捐款的完成后,由于合約沒有銷毀,捐贈者還是可以繼續(xù)捐贈的,因此會導(dǎo)致多出的錢仍在合約賬戶中,所以就有了該退款的方法。該方法是將合約上的錢根據(jù)捐贈者退回給捐贈者。
// 募資完成時(shí),退款給捐贈人
function returnBack(uint _neederAmount) public payable {
needer storage _needer = neederMap[_neederAmount]; // 獲取眾籌項(xiàng)目
require(_needer.funderMap[_needer.funderAccount].funderAddress == msg.sender);
uint returnMoney = _needer.funderMap[_needer.funderAccount].toMoney;
uint balance = address(this).balance;
balance -= returnMoney;
msg.sender.transfer(returnMoney);
}
查詢已募資金額(合約的錢)
// 查詢合約余額
function getBalance() public view returns(uint) {
return address(this).balance;
}
查詢募資狀態(tài)
// 查看募資狀態(tài)
function showData(uint _neederAmount) public view returns(uint, uint, uint, uint) {
return (neederMap[_neederAmount].goal, neederMap[_neederAmount].isFinish, neederMap[_neederAmount].amount, neederMap[_neederAmount].funderAccount);
}
聲明合約擁有者
modifier onlyOwner(){
require(msg.sender == owner);
_;
}
合約銷毀
function kill() public {
require(msg.sender == owner);
selfdestruct(owner);
}