117 lines
4.8 KiB
Plaintext
117 lines
4.8 KiB
Plaintext
/*
|
|
* Aegora Base Contract
|
|
*
|
|
* Author: Craig Everett <ceverett@tsuriai.jp>
|
|
* Copyright: Tsuriai Corporation (2022)
|
|
* License: GPLv3
|
|
* Version: 1
|
|
*
|
|
* This is the base contract for the market.
|
|
* It is responsible for:
|
|
* - A library of valid contracts by type (sales offers, auctions, etc.)
|
|
* - Managing the authorized key list of market masters
|
|
* - Providing a single known endpoint to discover deployed, active contracts
|
|
* - Managing the lifecycle of a contract
|
|
*
|
|
* Lifecycle of a sales offer:
|
|
* 1. The seller calls AegoraBase.post_sale() to create his SalesOffer
|
|
* 2. Sale proceeds
|
|
* IF it is succesful, the contract calls AegoraBase.close()
|
|
* IF it is revoked by seller, the contract calls AegoraBase.close()
|
|
* IF it times out or is killed by the maester, one calls AegoraBase.kill()
|
|
*
|
|
* Calls to this contract can come from one of five sources:
|
|
* 1. The Maester (essentially the administrator)
|
|
* - init(template : SalesOffer // Posts the initial contract
|
|
* maester : address // with a reference to a template
|
|
* tsuriai : address)
|
|
* - update_template(contract : SalesOffer) // Update the template address
|
|
* - epstein(id : bool) // Force a contract to close
|
|
* 2. Sellers
|
|
* - post_sale(id : int, price : int) // Create a new sale contract clone
|
|
* 3. The Aegora site (or anyone really, but mainly useful for the site backend)
|
|
* - lookup(id) // Looks up a sale contract's address
|
|
* - template() // Looks up the current sales contract template
|
|
* 4. A sales contract
|
|
* - close(id : int) // A closing sale contract may call to remove itself from the active index
|
|
* 5. The Tsuriai master Key
|
|
* - update_maester(key : address) // Change the Maester key for operational reasons
|
|
*/
|
|
|
|
@compiler == 7.0.1
|
|
|
|
payable contract interface SalesOffer =
|
|
entrypoint init : (address, address, address, int, address, int, int) => void
|
|
payable entrypoint do_a_backflip : () => bool
|
|
|
|
|
|
contract AegoraBase =
|
|
record state =
|
|
{contracts : map(int, SalesOffer),
|
|
template : SalesOffer,
|
|
maester : address,
|
|
tsuriai : address}
|
|
|
|
stateful entrypoint init(template : SalesOffer,
|
|
maester : address,
|
|
tsuriai : address) : state =
|
|
{contracts = {},
|
|
template = template,
|
|
maester = maester,
|
|
tsuriai = tsuriai}
|
|
|
|
public entrypoint template() : SalesOffer =
|
|
state.template
|
|
|
|
public stateful entrypoint update_template(source : SalesOffer) : unit =
|
|
require(Call.caller == state.maester, "Nuh, uh uh! You didn't say the magic word!")
|
|
put(state{template = source})
|
|
|
|
public entrypoint lookup(id: int) : SalesOffer =
|
|
switch(Map.lookup(id, state.contracts))
|
|
Some(target) =>
|
|
target
|
|
None =>
|
|
abort("Bad ID!")
|
|
|
|
public stateful entrypoint post_sale(agent : address, portion : int, seller : address, id: int, price: int) : SalesOffer =
|
|
require(price > 0, "You cannot pay someone to buy things, Mr. Keynes.")
|
|
require(!Map.member(id, state.contracts), "People don't think it be like it is, but it do.")
|
|
switch(Chain.clone(ref = state.template,
|
|
protected = true,
|
|
state.tsuriai,
|
|
Contract.address,
|
|
agent,
|
|
portion,
|
|
seller,
|
|
id,
|
|
price))
|
|
Some(posted) =>
|
|
put(state{contracts = state.contracts{[id] = posted}})
|
|
posted
|
|
None =>
|
|
abort("Bad sale!")
|
|
|
|
public stateful entrypoint close(id: int) : bool =
|
|
switch(Map.lookup(id, state.contracts))
|
|
Some(target) =>
|
|
require(target.address == Call.caller, "Bad caller")
|
|
put(state{contracts = Map.delete(id, state.contracts)})
|
|
true
|
|
None =>
|
|
false
|
|
|
|
public stateful entrypoint update_maester(key: address) : unit =
|
|
require(Call.caller == state.tsuriai, "Nuh, uh uh! You didn't say the magic word!")
|
|
put(state{maester = key})
|
|
|
|
public stateful entrypoint epstein(id: int) : bool =
|
|
require(Call.caller == state.maester, "C'mon, man! You only got the husband and son!")
|
|
switch(Map.lookup(id, state.contracts))
|
|
Some(target) =>
|
|
put(state{contracts = Map.delete(id, state.contracts)})
|
|
target.do_a_backflip()
|
|
true
|
|
None =>
|
|
false
|