sophia/test/contracts/fundme.aes
Ulf Norell 5aed8b3ef5 Check stateful annotations
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
2019-05-13 13:39:17 +02:00

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) })