more mass renaming
This commit is contained in:
@@ -0,0 +1,354 @@
|
||||
include "List.aes"
|
||||
include "Pair.aes"
|
||||
namespace Miner =
|
||||
type package_code = string
|
||||
|
||||
record package = {
|
||||
daily_cap : int,
|
||||
price : int}
|
||||
|
||||
record aggregated_package = {
|
||||
daily_cap : int,
|
||||
count : int}
|
||||
|
||||
record worker = {
|
||||
daily_cap : int,
|
||||
can_withdraw_payout : bool,
|
||||
packages : map(package_code, aggregated_package),
|
||||
joined_pool_tmst : int}
|
||||
|
||||
record transfer_packs =
|
||||
{
|
||||
worker : address,
|
||||
packages_to_move : list(string * int),
|
||||
new_address : address
|
||||
}
|
||||
|
||||
datatype approvable_action = Transfer(transfer_packs)
|
||||
|
||||
function new_package(price : int, cap : int) : package =
|
||||
{daily_cap = cap,
|
||||
price = price}
|
||||
|
||||
function claim(ps : list(package_code * (package * int)), joined_tmst : int) : worker =
|
||||
let daily_cap = daily_cap_from_packs_list(ps)
|
||||
let packs : map(package_code, aggregated_package) =
|
||||
List.foldl(
|
||||
(accum, t) =>
|
||||
let pack_id = Pair.fst(t)
|
||||
let (pack, cnt) = Pair.snd(t)
|
||||
let val =
|
||||
switch(Map.lookup(pack_id, accum))
|
||||
None => {daily_cap = pack.daily_cap, count = cnt}
|
||||
Some(v) => v{count = v.count + cnt}
|
||||
accum{[pack_id] = val},
|
||||
{},
|
||||
ps)
|
||||
{daily_cap = daily_cap,
|
||||
can_withdraw_payout = false,
|
||||
packages = packs,
|
||||
joined_pool_tmst = joined_tmst}
|
||||
|
||||
function split_packages(w : worker, split : transfer_packs) : worker * worker =
|
||||
let (packages_left, packages_collected) =
|
||||
List.foldl(
|
||||
(accum, p) =>
|
||||
let accum_left = Pair.fst(accum)
|
||||
let accum_collected = Pair.snd(accum)
|
||||
let code = Pair.fst(p)
|
||||
let count = Pair.snd(p)
|
||||
switch(Map.lookup(code, accum_left))
|
||||
None => abort("Does not own enough packages")
|
||||
Some(owned_packs) =>
|
||||
let left_packs = owned_packs.count - count
|
||||
require(left_packs > -1, "Does not own enough packages")
|
||||
(accum_left{[code] = owned_packs{count = left_packs}}, (code, owned_packs{count = count}) :: accum_collected),
|
||||
(w.packages, []),
|
||||
split.packages_to_move)
|
||||
let daily_cap_delta = List.sum(List.map((t) => Pair.snd(t).daily_cap * Pair.snd(t).count, packages_collected))
|
||||
let new_w = {daily_cap = daily_cap_delta,
|
||||
can_withdraw_payout = false,
|
||||
packages = Map.from_list(packages_collected),
|
||||
joined_pool_tmst = Chain.block_height}
|
||||
require(Map.size(new_w.packages) == List.length(packages_collected), "Do not split counts of the same package code")
|
||||
(w{daily_cap = w.daily_cap - daily_cap_delta, packages = packages_left}, new_w)
|
||||
|
||||
function merge_workers(w1 : worker, w2: worker) =
|
||||
let packages =
|
||||
List.foldl(
|
||||
(accum, t) =>
|
||||
let code = Pair.fst(t)
|
||||
let aggr_pack = Pair.snd(t)
|
||||
let updated_pack =
|
||||
switch(Map.lookup(code, accum))
|
||||
None => aggr_pack
|
||||
Some(p) => p{count = p.count + aggr_pack.count}
|
||||
accum{[code] = updated_pack},
|
||||
w1.packages,
|
||||
Map.to_list(w2.packages))
|
||||
// if one of them is allowed to withdraw, so is the resulting new account
|
||||
let oldest_tmst =
|
||||
switch(w1.joined_pool_tmst < w2.joined_pool_tmst)
|
||||
true => w1.joined_pool_tmst
|
||||
false => w2.joined_pool_tmst
|
||||
let can_withdraw_payout = w1.can_withdraw_payout || w2.can_withdraw_payout
|
||||
let daily_cap = daily_cap_from_packages(packages)
|
||||
{daily_cap = daily_cap,
|
||||
can_withdraw_payout = can_withdraw_payout,
|
||||
packages = packages,
|
||||
joined_pool_tmst = oldest_tmst}
|
||||
|
||||
function daily_cap_from_packs_list(ps : list(package_code * (package * int))) =
|
||||
List.sum(List.map((t) => Pair.fst(Pair.snd(t)).daily_cap * Pair.snd(Pair.snd(t)), ps))
|
||||
|
||||
function daily_cap_from_packages(ps : map(package_code, aggregated_package)) =
|
||||
List.sum(List.map((t) => Pair.snd(t).daily_cap * Pair.snd(t).count, Map.to_list(ps)))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
contract interface Data =
|
||||
stateful entrypoint set_pool : (address) => unit
|
||||
stateful entrypoint add : (address, Miner.worker) => unit
|
||||
stateful entrypoint remove : (address) => unit
|
||||
payable stateful entrypoint give_rewards : (list(address * int)) => unit
|
||||
entrypoint balance : (address) => int
|
||||
entrypoint assert_is_payable : (address) => unit
|
||||
stateful entrypoint payout : () => unit
|
||||
stateful entrypoint payout_without_payable_check : (address) => unit
|
||||
entrypoint all_balances : () => list(address * int)
|
||||
entrypoint all_daily_caps : () => list(address * int)
|
||||
entrypoint all : () => list(address)
|
||||
entrypoint all_detailed : () => map(address, Miner.worker)
|
||||
entrypoint member : (address) => bool
|
||||
entrypoint get : (address) => Miner.worker
|
||||
stateful entrypoint rename : (address, address) => unit
|
||||
stateful entrypoint make_payable : (address) => unit
|
||||
stateful entrypoint make_non_payable : (address) => unit
|
||||
stateful entrypoint split_packages : (Miner.transfer_packs) => unit
|
||||
entrypoint all_balances_and_daily_caps : () => list(address * int * int)
|
||||
|
||||
contract interface Pool =
|
||||
entrypoint leader : () => address
|
||||
stateful entrypoint enroll : (address, Miner.worker) => unit
|
||||
entrypoint member : (address) => bool
|
||||
stateful entrypoint remove : (address) => unit
|
||||
entrypoint get : (address) => Miner.worker
|
||||
stateful entrypoint set_locked : (bool) => unit
|
||||
stateful entrypoint set_leader : (address) => unit
|
||||
entrypoint can_be_destroyed : () => bool
|
||||
entrypoint info : () => address * string * address * string * string * string * string * list(string)
|
||||
stateful entrypoint make_payable : (address) => unit
|
||||
stateful entrypoint make_non_payable : (address) => unit
|
||||
entrypoint assert_worker_is_payable : (address) => unit
|
||||
stateful entrypoint force_payout : (address) => unit
|
||||
stateful entrypoint change_worker_address : (address, address) => unit
|
||||
entrypoint balance : (address) => int
|
||||
stateful entrypoint set_data_ct : (Data) => unit
|
||||
stateful entrypoint move_data_and_coins_to_new_pool : (Pool) => Data
|
||||
payable entrypoint receive_coins : () => unit
|
||||
stateful entrypoint evacuate_coins : (int, address) => unit
|
||||
stateful entrypoint split_packages : (Miner.transfer_packs) => unit
|
||||
|
||||
|
||||
include "Set.aes"
|
||||
include "List.aes"
|
||||
include "Pair.aes"
|
||||
|
||||
main contract PoolInstance:Pool =
|
||||
datatype pool_status = OPEN | LOCKED | MIGRATED
|
||||
|
||||
datatype event
|
||||
= Enroll(address)
|
||||
| Remove(address)
|
||||
|
||||
record state =
|
||||
{
|
||||
status : pool_status,
|
||||
leader : address,
|
||||
main_contract : address,
|
||||
connect_addresses : Set.set(string), // IP addresses and ports
|
||||
leader_name : string,
|
||||
leader_url: string,
|
||||
leader_avatar_url : string,
|
||||
leader_description : string,
|
||||
data_ct : Data
|
||||
}
|
||||
|
||||
entrypoint init(main_contract : address, leader : address, data_ct : Data) =
|
||||
{status = OPEN,
|
||||
leader = leader,
|
||||
main_contract = main_contract,
|
||||
connect_addresses = Set.new(),
|
||||
leader_name = "",
|
||||
leader_url = "",
|
||||
leader_avatar_url = "",
|
||||
leader_description = "",
|
||||
data_ct = data_ct}
|
||||
|
||||
entrypoint status() =
|
||||
switch(state.status)
|
||||
OPEN => "open"
|
||||
LOCKED => "locked"
|
||||
MIGRATED => "migrated"
|
||||
|
||||
entrypoint info() =
|
||||
(Contract.address, status(), state.leader, state.leader_name, state.leader_url, state.leader_avatar_url, state.leader_description, Set.to_list(state.connect_addresses))
|
||||
|
||||
entrypoint data_contract() =
|
||||
state.data_ct
|
||||
|
||||
entrypoint main_contract() =
|
||||
state.main_contract
|
||||
|
||||
entrypoint can_be_destroyed() : bool =
|
||||
(empty() && state.status == LOCKED && Contract.balance == 0) || state.status == MIGRATED
|
||||
|
||||
entrypoint leader() =
|
||||
state.leader
|
||||
|
||||
entrypoint miners() =
|
||||
state.data_ct.all()
|
||||
|
||||
entrypoint miners_detailed() =
|
||||
state.data_ct.all_detailed()
|
||||
|
||||
entrypoint miner_balances() : list(address * int) =
|
||||
state.data_ct.all_balances()
|
||||
|
||||
entrypoint miner_daily_caps() : list(address * int) =
|
||||
state.data_ct.all_daily_caps()
|
||||
|
||||
entrypoint miner_balances_and_caps() : list(address * int * int) =
|
||||
state.data_ct.all_balances_and_daily_caps()
|
||||
|
||||
entrypoint empty() : bool =
|
||||
List.is_empty(miners())
|
||||
|
||||
stateful entrypoint enroll(worker_address : address, worker : Miner.worker) =
|
||||
assert_caller_is_main_contract()
|
||||
require(state.status == OPEN, "Pool is locked, can not join it")
|
||||
Chain.event(Enroll(worker_address))
|
||||
add_worker(worker_address, worker)
|
||||
|
||||
entrypoint member(worker_address : address) : bool =
|
||||
state.data_ct.member(worker_address)
|
||||
|
||||
|
||||
/* deletes a worker from the pool if present. Currently the accumulated coins remain in
|
||||
pool. */
|
||||
stateful entrypoint remove(worker_address : address) =
|
||||
assert_caller_is_main_contract()
|
||||
Chain.event(Remove(worker_address))
|
||||
state.data_ct.remove(worker_address)
|
||||
|
||||
entrypoint get(worker_address : address) =
|
||||
state.data_ct.get(worker_address)
|
||||
|
||||
// this can overwrite a MIGRATED state
|
||||
stateful entrypoint set_locked(val : bool) =
|
||||
assert_caller_is_main_contract()
|
||||
let s =
|
||||
switch(val)
|
||||
true => LOCKED
|
||||
false => OPEN
|
||||
put(state{status = s})
|
||||
|
||||
stateful entrypoint set_leader(new_leader : address) =
|
||||
assert_caller_is_main_contract()
|
||||
put(state{leader = new_leader})
|
||||
|
||||
stateful entrypoint add_connect_address(conn_address : string) =
|
||||
assert_leader()
|
||||
put(state{connect_addresses = Set.insert(conn_address, state.connect_addresses)})
|
||||
|
||||
stateful entrypoint rm_connect_address(conn_address : string) =
|
||||
assert_leader()
|
||||
put(state{connect_addresses = Set.delete(conn_address, state.connect_addresses)})
|
||||
|
||||
stateful entrypoint set_name(name : string) =
|
||||
assert_leader()
|
||||
put(state{leader_name = name})
|
||||
|
||||
stateful entrypoint set_url(url : string) =
|
||||
assert_leader()
|
||||
put(state{leader_url = url})
|
||||
|
||||
stateful entrypoint set_avatar_url(avatar_url : string) =
|
||||
assert_leader()
|
||||
put(state{leader_avatar_url = avatar_url})
|
||||
|
||||
stateful entrypoint set_description(description : string) =
|
||||
assert_leader()
|
||||
put(state{leader_description = description})
|
||||
|
||||
/* NB: does not take into account one's daily limits! */
|
||||
stateful entrypoint simply_reward_work(amounts : list(address * int), _ : string) =
|
||||
assert_leader()
|
||||
let total_reward = List.sum(List.map((t) => Pair.snd(t), amounts))
|
||||
require(Contract.balance >= total_reward, "Not enough GAJU for that reward")
|
||||
state.data_ct.give_rewards(amounts, value = total_reward)
|
||||
|
||||
payable entrypoint receive_coins() =
|
||||
()
|
||||
|
||||
// for Eureka
|
||||
entrypoint balance(addr : address) =
|
||||
state.data_ct.balance(addr)
|
||||
|
||||
entrypoint daily_cap(addr : address) =
|
||||
let worker = get(addr)
|
||||
worker.daily_cap
|
||||
|
||||
stateful entrypoint payout() : unit =
|
||||
state.data_ct.payout()
|
||||
|
||||
stateful entrypoint force_payout(worker_addr : address) =
|
||||
assert_caller_is_main_contract()
|
||||
state.data_ct.payout_without_payable_check(worker_addr)
|
||||
|
||||
stateful entrypoint change_worker_address(old_addr : address, new_addr : address) =
|
||||
assert_caller_is_main_contract()
|
||||
state.data_ct.rename(old_addr, new_addr)
|
||||
|
||||
stateful entrypoint evacuate_coins(amount : int, safeheaven : address) =
|
||||
assert_caller_is_main_contract()
|
||||
Chain.spend(safeheaven, amount)
|
||||
|
||||
stateful entrypoint make_payable(worker_address : address) =
|
||||
assert_caller_is_main_contract()
|
||||
state.data_ct.make_payable(worker_address)
|
||||
|
||||
stateful entrypoint make_non_payable(worker_address : address) =
|
||||
assert_caller_is_main_contract()
|
||||
state.data_ct.make_non_payable(worker_address)
|
||||
|
||||
stateful entrypoint set_data_ct(data_ct : Data) =
|
||||
assert_caller_is_main_contract()
|
||||
put(state{data_ct = data_ct})
|
||||
|
||||
stateful entrypoint move_data_and_coins_to_new_pool(new_pool : Pool) =
|
||||
assert_caller_is_main_contract()
|
||||
state.data_ct.set_pool(new_pool.address)
|
||||
new_pool.receive_coins(value = Contract.balance)
|
||||
put(state{status = MIGRATED})
|
||||
state.data_ct
|
||||
|
||||
entrypoint assert_worker_is_payable(worker_address : address) =
|
||||
state.data_ct.assert_is_payable(worker_address)
|
||||
|
||||
stateful entrypoint split_packages(split : Miner.transfer_packs) =
|
||||
assert_caller_is_main_contract()
|
||||
state.data_ct.split_packages(split)
|
||||
|
||||
// private functions
|
||||
function assert_caller_is_main_contract() =
|
||||
require(Call.caller == state.main_contract, "Call it through the main pool contract")
|
||||
|
||||
function assert_leader() =
|
||||
require(Call.origin == state.leader, "Must be called by the leader")
|
||||
|
||||
stateful function add_worker(worker_address, worker) =
|
||||
state.data_ct.add(worker_address, worker)
|
||||
|
||||
Reference in New Issue
Block a user