Skip to content

Commit

Permalink
feat: initial commit and test structure
Browse files Browse the repository at this point in the history
  • Loading branch information
thepiwo committed Nov 19, 2024
0 parents commit 10c2536
Show file tree
Hide file tree
Showing 14 changed files with 3,336 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Compile and Test Contracts

on: [push]

jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js 22.x
uses: actions/setup-node@v4
with:
node-version: 22.x
- run: npm install -g @aeternity/aeproject
- run: npm ci
- run: aeproject env
- run: aeproject test
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
.idea
generated/**.aes.js
1 change: 1 addition & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
26 changes: 26 additions & 0 deletions contracts/DelegatedStaking.aes
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
include "./HCElection.aes"
include "./StakingValidator.aes"
include "./MainStaking.aes"

payable contract DelegatedStaking =

record state =
{ staking_validator : option(StakingValidator)
, main_staking : MainStaking
, stakes : map(address, int) }

stateful entrypoint init(main_staking : MainStaking) =
{ staking_validator = None,
main_staking = main_staking,
stakes = {} }

payable stateful entrypoint register_validator() =
put(state{ staking_validator = Some(state.main_staking.new_validator(value = Call.value)) })

function get_staking_validator() =
switch(state.staking_validator)
Some(staking_validator) => staking_validator
None => abort("register_validator not yet called")

payable stateful entrypoint stake() =
state.main_staking.stake(value = Call.value, Contract.address)
161 changes: 161 additions & 0 deletions contracts/HCElection.aes
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
include "List.aes"
include "Pair.aes"
include "./MainStaking.aes"

contract HCElection =
record epoch_info =
{ start : int,
length : int,
seed : option(bytes()),
staking_distribution : option(list(address * int))
}

record pin_reward_info =
{ base : int,
current : int,
carry_over : int
}

record state =
{ main_staking_ct : MainStaking,
leader : address,
added_stake : int,
epoch : int,
epochs : map(int, epoch_info),
pin : option(bytes()),
pin_reward : pin_reward_info
}

entrypoint init(main_staking_ct : MainStaking) =
{ main_staking_ct = main_staking_ct,
leader = Contract.address,
added_stake = 0,
epoch = 0,
epochs = {},
pin = None,
pin_reward = {base = 0, current = 0, carry_over = 0} }

stateful entrypoint init_epochs(epoch_length : int, base_pin_reward : int) =
assert_protocol_call()
//require(Chain.block_height == 0, "Only in genesis")
put(state{ epochs = { [0] = mk_epoch_info(0, 1, None, None),
[1] = mk_epoch_info(1, epoch_length, None, Some(state.main_staking_ct.sorted_validators())),
[2] = mk_epoch_info(epoch_length + 1, epoch_length, None, Some(state.main_staking_ct.sorted_validators())),
[3] = mk_epoch_info(2 * epoch_length + 1, epoch_length, None, Some(state.main_staking_ct.sorted_validators())),
[4] = mk_epoch_info(3 * epoch_length + 1, epoch_length, None, Some(state.main_staking_ct.sorted_validators()))
},
epoch = 1,
pin_reward.base = base_pin_reward
})

function mk_epoch_info(start : int,
length : int,
seed : option(bytes),
staking_distribution : option(list(address * int))) =
{start = start, length = length, seed = seed, staking_distribution = staking_distribution}

stateful entrypoint step(leader : address) =
assert_protocol_call()
put(state{ leader = leader })

stateful entrypoint step_micro(leader : address) =
assert_protocol_call()
put(state{ leader = leader })

stateful entrypoint step_eoe(leader : address, seed : bytes(), epoch_adjust : int,
next_base_pin_reward : int, carry_over_flag : bool) =
assert_protocol_call()
let epoch = state.epoch
let ei = state.epochs[epoch]
// pin rewards
let next_carry_over = calc_carry_over(carry_over_flag)
let next_base = calc_next_base_reward(next_base_pin_reward)
let next_reward = next_base + next_carry_over
let pr = {current = next_reward, carry_over = next_carry_over, base = next_base}
// update epochs
require(ei.start + ei.length - 1 == Chain.block_height, "This is not the end")
let ei2 = state.epochs[epoch + 2]
let ei_adjust = state.epochs[epoch + 3]{ length = ei2.length + epoch_adjust }
let new_epochs = { [epoch] = state.epochs[epoch],
[epoch + 1] = state.epochs[epoch + 1],
[epoch + 2] = state.epochs[epoch + 2]{ seed = Some(seed) },
[epoch + 3] = ei_adjust,
[epoch + 4] = mk_epoch_info(ei_adjust.start + ei_adjust.length, ei_adjust.length, None,
Some(state.main_staking_ct.sorted_validators()))
}

put(state{ leader = leader,
epoch = epoch + 1,
epochs = new_epochs,
pin = None,
pin_reward = pr})

stateful entrypoint pin(proof : bytes()) =
let epoch = state.epoch
let last = state.epochs[epoch].start + state.epochs[epoch].length - 1
require(Chain.block_height == last, "Only in last block")
require(Call.caller == state.leader, "Must be called by the last leader of epoch")
put(state{pin = Some(proof)})

entrypoint leader() =
state.leader

// entrypoint added_stake() =
// state.added_stake

entrypoint epoch() =
state.epoch

entrypoint epoch_length() =
state.epochs[state.epoch].length

entrypoint epoch_info() =
(state.epoch, state.epochs[state.epoch])

entrypoint epoch_info_epoch(epoch : int) =
require(epoch >= state.epoch - 1 && epoch =< state.epoch + 2, "Epoch not in scope")
state.epochs[epoch]

entrypoint staking_contract() =
state.main_staking_ct

entrypoint validator_schedule(seed : bytes(), validators : list(address * int), length : int) =
let total_stake = List.foldl((+), 0, List.map(Pair.snd, validators))
// One extra hash operation to convert from bytes() to bytes(32)/hash
validator_schedule_(Crypto.blake2b(seed), (s) => Bytes.to_int(s) mod total_stake, validators, length, [])

entrypoint pin_info() =
state.pin

entrypoint pin_reward_info() =
state.pin_reward

function
validator_schedule_(_, _, _, 0, schedule) = List.reverse(schedule)
validator_schedule_(seed0, rnd, validators, n, schedule) =
let seed = Crypto.blake2b(seed0)
let validator = pick_validator(rnd(seed), validators)
validator_schedule_(seed, rnd, validators, n - 1, validator :: schedule)

function
pick_validator(n, (validator, stake) :: _) | n < stake = validator
pick_validator(n, (_, stake) :: validators) = pick_validator(n - stake, validators)

function assert_protocol_call() =
require(Call.caller == Contract.creator, "Must be called by the protocol")

function calc_carry_over(carry_over_flag : bool) =
let ei = state.pin_reward
if (carry_over_flag)
ei.base + ei.carry_over
else
0

function calc_next_base_reward(next_base_pin_reward : int) =
if ( next_base_pin_reward >= 0 )
next_base_pin_reward
else
state.pin_reward.base

// function accum_stake((accum, total_s, current_hash, network_id), (addr, stake)) =
// ((addr, stake) :: accum, stake + total_s, current_hash, network_id)
Loading

0 comments on commit 10c2536

Please sign in to comment.