contract: ct_MMSVP6vD4LbkcWyr4qq2cidp8eheLnn8xLvmvw1M2tGydCpft

Contract source code
The code as it had been recorded in the contract create transaction. This is not being validated if it matches the bytecode.
include "List.aes"
include "Pair.aes"
namespace Worker =
  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)))




include "Set.aes"
include "List.aes"
include "Pair.aes"

contract interface Data =
  stateful entrypoint init : (address) => unit

contract interface Hive =
  stateful entrypoint init : (address, address, Data) => unit
  entrypoint leader : () => address
  stateful entrypoint enroll : (address, Worker.worker) => unit
  entrypoint member : (address) => bool
  stateful entrypoint remove : (address) => unit
  entrypoint get : (address) => Worker.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_hive : (Hive) => Data
  payable entrypoint receive_coins : () => unit 
  stateful entrypoint evacuate_coins : (int, address) => unit
  stateful entrypoint split_packages : (Worker.transfer_packs) => unit

contract interface Multisig =
  stateful entrypoint validate : ('a, list(address * signature), int) => unit

main contract HiveMan =
  type sig_list = list(address * signature)

  record personal_mining_package =
    {
      codes : map(Worker.package_code, int),
      hive : Hive // this is the hive to join once claimed the package
    }

  datatype event
    = PackageTypeAdded(Worker.package_code, int, int)
//    | PackageAdded(address, list(Worker.package_code * int))
    | NewEurekaAddress(address)
    | NewKYCValidatorAddress(address)
    | PackageRemoved(address)
    | HiveChartered(Hive)
    | Enrolled(address, Hive)
    | Removed(address, Hive)
    | Reassigned(address, Hive, Hive)
    | Locked(Hive)
    | Unlocked(Hive)
    | Withdraw(address, int)
    | Destroyed(Hive)
    | AdminAdded(address)
    | AdminRemoved(address)
    | SetLeader(Hive, address)

  record state =
    { 
      admins : Set.set(address),
      payable_validator : address,
      eureka : address,
      package_types : map(Worker.package_code, Worker.package),
      available_packages : map(address, personal_mining_package),
      hives : Set.set(Hive),
      pending_admin_approval : map(Worker.approvable_action, Hive),
      multisig_enabled : bool,
      multisig_ct : Multisig,
      master : address,
      eureka_can_grant_packages : bool
    }

  entrypoint init(master: address, eureka : address, payable_validator : address, multisig_ct : Multisig) =
    {admins = Set.from_list([Call.origin]),
     eureka = eureka,
     payable_validator = payable_validator,
     package_types = {},
     available_packages = {},
     hives = Set.new(),
     pending_admin_approval = {},
     multisig_ct = multisig_ct,
     multisig_enabled = false,
     master = master,
     eureka_can_grant_packages = true
     }

  // for Eureka
  entrypoint leader(hive : Hive) =
    assert_hive(hive)
    hive.leader()

  // for Eureka
  stateful entrypoint add_package_type(code : Worker.package_code, price : int, cap : int) : unit =
    assert_eureka()
    switch(Map.lookup(code, state.package_types))
      Some(_) => abort("Package code already created")
      None =>
        let p = Worker.new_package(price, cap)
        Chain.event(PackageTypeAdded(code, price, cap))
        put(state{package_types[code] = p})

  stateful entrypoint set_eureka(eureka : address, sigs : sig_list) =
    assert_consortium_vote(("SET_EUREKA", eureka), sigs, 30)
    Chain.event(NewEurekaAddress(eureka))
    put(state{eureka = eureka})

  stateful entrypoint set_eureka_can_grant_packages(val : bool, sigs : sig_list) =
    assert_consortium_vote(("SET_EUREKA_GRANT_PACKAGES", val), sigs, 51)
    put(state{eureka_can_grant_packages = val})

  entrypoint can_eureka_grant_packages() =
    state.eureka_can_grant_packages

  stateful entrypoint set_multisig_contract(m : Multisig, sigs : sig_list) =
    assert_consortium_vote(("SET_MULTISIG_CONTRACT", m), sigs, 51)
    put(state{multisig_ct = m})

  entrypoint multisig_contract() =
    state.multisig_ct

  stateful entrypoint set_master(m : address, sigs : sig_list) =
    assert_consortium_vote(("SET_MASTER", m), sigs, 51)
    put(state{master = m})

  stateful entrypoint set_multisig_enabled(val : bool, sigs : sig_list) =
    assert_consortium_vote(("SET_MULTISIG_ENABLED", val), sigs, 51)
    put(state{multisig_enabled = val})

  entrypoint multisig_enabled() =
    state.multisig_enabled
    
  stateful entrypoint set_payable_validator(payable_validator : address, sigs : sig_list) =
    assert_consortium_vote(("SET_PAYABLE_VALIDATOR", payable_validator), sigs, 30)
    Chain.event(NewKYCValidatorAddress(payable_validator))
    put(state{payable_validator = payable_validator})

  entrypoint operators() =
    (state.admins, state.payable_validator, state.eureka, state.master)

  // for Eureka
  stateful entrypoint add_package(codes : list(Worker.package_code * int), buyer : address, hive : Hive) : unit =
    assert_eureka()
    // assert all codes are known
    List.foreach(codes,
        (t) => switch(Map.lookup(Pair.fst(t), state.package_types))
                    Some(_) => ()
                    None => abort("Unknown packgage code"))
    let pending_packs =
      switch(Map.lookup(buyer, state.available_packages))
        Some(p) => p
        None => {hive = hive, codes = {}}
//    Chain.event(PackageAdded(buyer, codes))
    let packs =
      List.foldl(
          (acc, t) =>
            let ix = Pair.fst(t)
            acc{[ix = 0] @ c = c + Pair.snd(t)},
          pending_packs.codes,
          codes)
    put(state{available_packages[buyer] = {codes = packs, hive = hive}})

  // for Eureka
  stateful entrypoint remove_package(buyer : address) : unit =
    assert_eureka()
    Chain.event(PackageRemoved(buyer))
    put(state{available_packages = Map.delete(buyer, state.available_packages)})

  stateful entrypoint charter(template_hive_ct : Hive, leader : address, data_template_ct : Data) =
    assert_admin()
    let hive_ct : Hive = Chain.clone(ref = template_hive_ct, Contract.address, leader, data_template_ct)
    let data_ct : Data = Chain.clone(ref = data_template_ct, hive_ct.address)
    hive_ct.set_data_ct(data_ct)
    Chain.event(HiveChartered(hive_ct))
    put(state{hives = Set.insert(hive_ct, state.hives)})
    hive_ct

  // for Eureka
  entrypoint hive_addresses() =
    Set.to_list(state.hives)

  // for Eureka
  entrypoint hives_info() =
    List.map((hive) => (hive, hive.info()), Set.to_list(state.hives))

  // for Eureka
  entrypoint list_package_types() =
    state.package_types

  // for Eureka
  entrypoint lookup_packages(buyer : address) : personal_mining_package =
    switch(Map.lookup(buyer, state.available_packages))
      None => abort("No available package")
      Some(packages) => packages

  /* buy a package */
  stateful payable entrypoint enroll() =
    switch(Map.lookup(Call.origin, state.available_packages))
      None => abort("Unknown package")
      Some(package) =>
        let package_types =
          Map.to_list(List.foldl(
            (accum, tuple) =>
              let code = Pair.fst(tuple)
              let count = Pair.snd(tuple)
              switch(Map.lookup(code, state.package_types))
                None => abort("Unknown packgage code")
                Some(t) =>
                  let old_value =
                    switch(Map.lookup(code, accum))
                      Some((_, cnt)) => cnt
                      None => 0
                  accum{[code] = (t, old_value + count)},
            {},
            Map.to_list(package.codes)))
        let coins = Call.value
        let total_price = List.sum(List.map((t) => Pair.fst(Pair.snd(t)).price * Pair.snd(Pair.snd(t)), package_types))
        if(total_price < coins) abort("Too much GAJU")
        if(total_price > coins) abort("Insufficient GAJU")
        let worker = Worker.claim(package_types, Chain.block_height)
        Chain.event(Enrolled(Call.origin, package.hive))
        package.hive.enroll(Call.origin, worker)
        put(state{available_packages = Map.delete(Call.origin, state.available_packages)})
        package.hive

  stateful entrypoint grant_packages(codes : list(Worker.package_code * int), receiver : address, hive : Hive) =
    grant_packages_(codes, receiver, hive, Chain.block_height)

  stateful entrypoint grant_older_packages(codes : list(Worker.package_code * int), receiver : address, hive : Hive, start_height : int) =
    grant_packages_(codes, receiver, hive, start_height)

  /* this could be really computationally heavy function. Use only in dry-run
     context */
  // for Eureka
  entrypoint member(worker_address : address) =
    let res = List.find((hive : Hive) => hive.member(worker_address), Set.to_list(state.hives))
    switch(res)
      None => abort("Not member in any hive")
      Some(hive) =>
        hive

  /* this can be really computationally heavy function. Use only in dry-run
     context */
  // for Eureka
  entrypoint balances(worker_address : address) =
    let res = List.map((hive) => (hive, hive.balance(worker_address)), Set.to_list(state.hives))
    List.filter((kv) => Pair.snd(kv) > 0, res)

  entrypoint get_worker(worker_address : address, hive : Hive) =
    hive.get(worker_address)

  /* deletes a worker from a hive forever, there is no going back */
  // Currently the accumulated coins are left locked in the contract
  stateful entrypoint remove(worker : address, hive : Hive, sigs : sig_list) =
    assert_consortium_vote(("REMOVE_MINER", hive, worker), sigs, 30)
    assert_hive(hive)
    Chain.event(Removed(worker, hive))
    hive.remove(worker)

  /* Moves a worker from one hive to another */
  // Currently the accumulated coins are left in the contract. It is important
  // that this does not circumvent the KYC process. Another edge case is a
  // worker receiving more coins after they left the hive (rewards do have a
  // certain delay). Coins locked in previous contracts can be accessed via
  // the remote_payout entrypoint
  stateful entrypoint reassign(worker_addr : address, old_hive : Hive, new_hive : Hive) =
    assert_admin()
    assert_hive(old_hive)
    assert_hive(new_hive)
    // get the worker with its KYC state
    let worker = old_hive.get(worker_addr)
    old_hive.remove(worker_addr)
    // if the hive is locked, one can not join it
    Chain.event(Reassigned(worker_addr, old_hive, new_hive))
    new_hive.enroll(worker_addr, worker)

  stateful entrypoint lock(hive : Hive, sigs : sig_list) =
    Chain.event(Locked(hive))
    set_lock(hive, true, sigs)

  stateful entrypoint unlock(hive : Hive, sigs : sig_list) =
    Chain.event(Unlocked(hive))
    set_lock(hive, true, sigs)

  stateful entrypoint set_leader(hive : Hive, new_leader : address, sigs : sig_list) =
    assert_consortium_vote(("SET_LEADER", hive, new_leader), sigs, 51)
    Chain.event(SetLeader(hive, new_leader))
    hive.set_leader(new_leader)

  /* withdraws coins from the accumulated coins in the contract. Those could
     be either coins from sold packages OR withdrawn from hives */
  stateful entrypoint withdraw(amount : int, destination : address, sigs : sig_list) =
    assert_consortium_vote(("WITHDRAW", amount, destination), sigs, 51)
    Chain.event(Withdraw(destination, amount))
    Chain.spend(destination, amount)

  /* destroys a contract for good. It must be in an appropriate condition to
     be destroyed. Any reward received at the hive address after destruction
     will be unaccessable forever */
  stateful entrypoint destroy(hive: Hive, sigs: sig_list) =
    assert_consortium_vote(("DESTROY_POOL", hive), sigs, 51)
    destroy_(hive)

  stateful entrypoint add_admin(new_admin : address, sigs : sig_list) =
    assert_consortium_vote(("ADD_ADMIN", new_admin), sigs, 30)
    Chain.event(AdminAdded(new_admin))
    put(state{admins = Set.insert(new_admin, state.admins)})

  stateful entrypoint rm_admin(admin : address, sigs : sig_list) =
    assert_consortium_vote(("REMOVE_ADMIN", admin), sigs, 30)
    require(Set.size(state.admins) > 1, "There must be at least one admin left")
    Chain.event(AdminRemoved(admin))
    put(state{admins = Set.delete(admin, state.admins)})

  stateful entrypoint validate_payable(worker_addr : address, hive : Hive) =
    assert_payable_validator()
    assert_hive(hive)
    hive.make_payable(worker_addr)

  stateful entrypoint unvalidate_payable(worker_addr : address, hive : Hive) =
    assert_payable_validator()
    assert_hive(hive)
    hive.make_non_payable(worker_addr)

  stateful entrypoint remote_payout(old_hive : Hive, new_hive : Hive) =
    assert_hive(old_hive)
    assert_hive(new_hive)
    new_hive.assert_worker_is_payable(Call.origin)
    old_hive.force_payout(Call.origin)

/* this function is reserved only for an escape hatcher when a worker had lost
   access to their private keys. This function is intended for an admin to
   rename the whole account and exsisting balances stored in the contract and
   to contribute them to the new account pubkey */
  stateful entrypoint change_worker_address(old_addr : address, new_addr : address, hive : Hive, sigs : sig_list) =
    assert_consortium_vote(("RENAME", hive, old_addr, new_addr), sigs, 51)
    assert_hive(hive)
    hive.change_worker_address(old_addr, new_addr)

/* migrates all workers from old_hive and moves them with their balances to
   new_hive. Should be used in the case of migration from one contract to the
   other */
  stateful entrypoint migrate_data_between_hives(old_hive : Hive, new_hive : Hive, sigs : sig_list) =
    assert_consortium_vote(("MIGRATE_DATA_BETWEEN_POOL", old_hive, new_hive), sigs, 51) 
    assert_hive(old_hive)
    assert_hive(new_hive)
    let data_ct = old_hive.move_data_and_coins_to_new_hive(new_hive)
    new_hive.set_data_ct(data_ct)
    destroy_(old_hive)

  stateful entrypoint evacuate_hive_coins(hive : Hive, amount : int, safeheaven : address, sigs : sig_list) =
    assert_consortium_vote(("EVACUATE_COINS", hive, amount, safeheaven), sigs, 51) 
    assert_hive(hive)
    hive.evacuate_coins(amount, safeheaven)

  stateful entrypoint apply_to_admin(action : Worker.approvable_action, hive : Hive) =
    let worker_addr = action_worker(action)
    require(worker_addr == Call.origin, "Only the owner can apply")
    assert_hive(hive)
    require(hive.member(worker_addr), "Not a member in that hive")
    // maybe check if one has enough packages to split?
    put(state{pending_admin_approval[action] = hive})

  stateful entrypoint approve(a : Worker.approvable_action) =
    assert_admin()
    switch(Map.lookup(a, state.pending_admin_approval))
      None => abort("Unknown apply action")
      Some(hive) =>
        let worker_addr = action_worker(a)
        assert_hive(hive)
        require(hive.member(worker_addr), "Not a member in that hive") // maybe delegate this to the hive call?
        switch(a)
          Worker.Transfer(split) =>
            hive.split_packages(split)
        put(state{pending_admin_approval = Map.delete(a, state.pending_admin_approval)})

  stateful entrypoint decline(action : Worker.approvable_action) =
    assert_admin()
    put(state{pending_admin_approval = Map.delete(action, state.pending_admin_approval)})

  entrypoint pending_for_admin_approval() =
    state.pending_admin_approval

// private functions
  function assert_admin() =
    require(Set.member(Call.origin, state.admins), "Caller must be an admin")

  function assert_hive(hive : Hive)=
    require(Set.member(hive, state.hives), "Unknown hive") 

  function assert_eureka() =
    require(Call.origin == state.eureka, "This call is reserved for Eureka")
  
  function assert_payable_validator() =
    require(Call.origin == state.payable_validator, "This call is reserved for the payable validator")
  
  function map_keys(map) =
    List.map((kv) => Pair.fst(kv), Map.to_list(map))

  stateful function set_lock(hive : Hive, val : bool, sigs : sig_list) =
    assert_consortium_vote(("SET_LOCK", hive, val), sigs, 30)
    switch(Set.member(hive, state.hives))
      false => abort("Unknown hive")
      true =>
        hive.set_locked(val)

  function action_worker(a) =
    switch(a)
      Worker.Transfer(split) => split.worker

  function assert_consortium_vote(msg, sigs, threshold) =
    switch(state.multisig_enabled)
      false => require(Call.origin == state.master, "This call is reserved for master address")
      true => state.multisig_ct.validate(msg, sigs, threshold)

  stateful function destroy_(hive : Hive) =
    assert_hive(hive)
    require(hive.can_be_destroyed(), "The hive is not ready to be destroyed")
    Chain.event(Destroyed(hive))
    put(state{hives = Set.delete(hive, state.hives)})

  stateful function grant_packages_(codes : list(Worker.package_code * int), receiver : address, hive : Hive, start_height : int) =
    assert_eureka()
    assert_hive(hive)
    require(state.eureka_can_grant_packages, "Eureka package granting is disabled")
    let ps =
      List.map(
        (t) =>
          let (code, count) = t
          switch(Map.lookup(code, state.package_types))
            Some(p) => (code, (p, count))
            None => abort("Unknown packgage code"),
        codes)
    let worker = Worker.claim(ps, start_height)
    Chain.event(Enrolled(receiver, hive))
    hive.enroll(receiver, worker)
    hive