
Functions must be annotated as `stateful` in order to - Update the contract state (using `put`) - Call `Chain.spend` or other primitive functions that cost tokens - Call an Oracle or AENS function that requires a signature - Make a remote call with a non-zero value - Construct a lambda calling a stateful function It does not need to be stateful to - Read the contract state - Call another contract with value=0, even when the remote function is stateful
66 lines
2.1 KiB
Plaintext
66 lines
2.1 KiB
Plaintext
/*
|
|
* A simple crowd-funding example
|
|
*/
|
|
contract FundMe =
|
|
|
|
record spend_args = { recipient : address,
|
|
amount : int }
|
|
|
|
record state = { contributions : map(address, int),
|
|
total : int,
|
|
beneficiary : address,
|
|
deadline : int,
|
|
goal : int }
|
|
|
|
private function require(b : bool, err : string) =
|
|
if(!b) abort(err)
|
|
|
|
private stateful function spend(args : spend_args) =
|
|
Chain.spend(args.recipient, args.amount)
|
|
|
|
public function init(beneficiary, deadline, goal) : state =
|
|
{ contributions = {},
|
|
beneficiary = beneficiary,
|
|
deadline = deadline,
|
|
total = 0,
|
|
goal = goal }
|
|
|
|
private function is_contributor(addr) =
|
|
Map.member(addr, state.contributions)
|
|
|
|
public stateful function contribute() =
|
|
if(Chain.block_height >= state.deadline)
|
|
spend({ recipient = Call.caller, amount = Call.value }) // Refund money
|
|
false
|
|
else
|
|
let amount =
|
|
Map.lookup_default(Call.caller, state.contributions, 0) + Call.value
|
|
put(state{ contributions[Call.caller] = amount,
|
|
total @ tot = tot + Call.value })
|
|
true
|
|
|
|
public stateful function withdraw() =
|
|
if(Chain.block_height < state.deadline)
|
|
abort("Cannot withdraw before deadline")
|
|
if(Call.caller == state.beneficiary)
|
|
withdraw_beneficiary()
|
|
elif(is_contributor(Call.caller))
|
|
withdraw_contributor()
|
|
else
|
|
abort("Not a contributor or beneficiary")
|
|
|
|
private stateful function withdraw_beneficiary() =
|
|
require(state.total >= state.goal, "Project was not funded")
|
|
spend({recipient = state.beneficiary,
|
|
amount = Contract.balance })
|
|
put(state{ beneficiary = ak_11111111111111111111111111111111273Yts })
|
|
|
|
private stateful function withdraw_contributor() =
|
|
if(state.total >= state.goal)
|
|
abort("Project was funded")
|
|
let to = Call.caller
|
|
spend({recipient = to,
|
|
amount = state.contributions[to]})
|
|
put(state{ contributions @ c = Map.delete(to, c) })
|
|
|