Skip to content

Latest commit

 

History

History
1656 lines (1536 loc) · 56.7 KB

spec.md

File metadata and controls

1656 lines (1536 loc) · 56.7 KB

Spec

Table of contents

Diagrams

L2 Contracts block diagram

classDiagram
  class StakingContract{
    map < staker_address, Option < StakerInfo >>
    map < operational_address, staker_address >
    global_index
    global_index_last_update_timestamp
    min_stake
    total_stake
    pool_contract_class_hash
    map < UndelegateIntentKey, UndelegateIntentValue >
    pool_contract_admin
    is_paused
    stake()
    increase_stake()
    unstake_intent()
    unstake_action()
    claim_rewards()
    add_stake_from_pool()
    remove_from_delegation_pool_intent()
    remove_from_delegation_pool_action()
    switch_staking_delegation_pool()
    change_reward_address()
    change_operational_address()
    set_open_for_delegation()
    claim_delegation_pool_rewards()
    staker_info()
    contract_parameters()
    calculate_rewards()
    get_total_stake()

  }
  class DelegationPoolContract{
    map < pool_member_address, PoolMemberInfo >
    staker_address
    final_staker_index
    map < ContractAddress, Option < PoolMemberInfo >>
    commission
    enter_delegation_pool()
    add_to_delegation_pool()
    exit_delegation_pool_intent()
    exit_delegation_pool_action()
    claim_rewards()
    change_reward_address()
    pool_member_info()
    contract_parameters()
    switch_delegation_pool()
    enter_delegation_pool_from_staking_contract()
    set_final_staker_index()
    calculate_rewards()
  }
  class StakerInfo{
    reward_address
    operational_address
    option < unstake_time >
    amount_own
    index
    pooled_amount
    unclaimed_rewards_own
    pooled_unclaimed_rewards
    option < StakerPoolInfo >
  }
  class StakerPoolInfo{
    pool_contract
    amount
    unclaimed_rewards
    commission
  }
  class PoolMemberInfo{
    reward_address
    amount
    index
    unclaimed_rewards
    option < unpool_time >
  }
  class RewardSupplier {
    last_timestamp,
    unclaimed_rewards,
    l1_pending_requested_amount,
    base_mint_amount,
    base_mint_msg,
    minting_curve_dispatcher,
    staking_contract,
    erc20_dispatcher,
    l1_staking_minter,
    calculate_staking_rewards()
    claim_rewards()
    on_receive()
    contract_parameters()
  }
  class MintingCurve {
    staking_dispatcher,
    total_supply,
    l1_staking_minter_address,
    yearly_mint()
  }
  StakingContract o-- StakerInfo
  StakerInfo o-- StakerPoolInfo
  DelegationPoolContract o-- PoolMemberInfo
  StakingContract o-- RewardSupplier
  RewardSupplier o-- MintingCurve
Loading

L1 Contracts block diagram

classDiagram
  class RewardSupplier {
    tick()
  }
  class MintManager {
    mintRequest()
    allowance()
    approve()
    increaseAllowance()
    decreaseAllowance()
    stopAllowance()
  }
Loading

Enter protocol flow diagram

sequenceDiagram
  actor staker
  participant StakingContract
  participant DelegationPoolContract
  actor pool member
  staker ->>+ StakingContract: stake<br/>(pool enabled = true)
  StakingContract -->> DelegationPoolContract: deploy delegation pool contract
  par
    loop
      staker ->> StakingContract: increase_stake
    end
  and
    loop
      pool member ->>+ DelegationPoolContract: enter_delegation_pool
      DelegationPoolContract ->>- StakingContract: add_stake_from_pool
      loop
        pool member ->>+ DelegationPoolContract: add_to_delegation_pool
        DelegationPoolContract ->>- StakingContract: add_stake_from_pool
      end
    end
  end
Loading

Exit protocol flow diagram

sequenceDiagram
  actor staker
  participant StakingContract
  participant DelegationPoolContract
  actor pool member
  opt Loop
    pool member ->>+ DelegationPoolContract: exit_delegation_pool_intent
    DelegationPoolContract ->>- StakingContract: remove_from_delegation_pool_intent
    pool member ->>+ DelegationPoolContract: exit_delegation_pool_action
    DelegationPoolContract ->>- StakingContract: remove_from_delegation_pool_action
  end
  staker ->> StakingContract: unstake_intent
  staker ->> StakingContract: unstake_action
  opt Loop
    pool member ->>+ DelegationPoolContract: exit_delegation_pool_intent
    DelegationPoolContract ->>- StakingContract: remove_from_delegation_pool_intent
    pool member ->>+ DelegationPoolContract: exit_delegation_pool_action
    DelegationPoolContract ->>- StakingContract: remove_from_delegation_pool_action
  end
Loading

Rewards claim flow diagram

sequenceDiagram
  actor staker
  participant RewardSupplier
  participant StakingContract
  participant DelegationPoolContract
  actor pool member
  Loop
    staker ->> StakingContract: claim_rewards
    StakingContract ->>+ RewardSupplier: claim_rewards
    RewardSupplier -->> StakingContract: Transfer
    StakingContract -->> staker: Transfer
  end
  opt Loop
    pool member ->>+ DelegationPoolContract: claim_rewards
    DelegationPoolContract ->>+ StakingContract: claim_delegation_pool_rewards
    StakingContract ->>+ RewardSupplier: claim_rewards
    RewardSupplier -->> StakingContract: Transfer
    StakingContract -->> DelegationPoolContract: Transfer
    DelegationPoolContract -->> pool member: Transfer
  end
Loading

Delegation pool switching flow diagram

sequenceDiagram
  participant DelegationPoolContract B
  participant StakingContract
  participant DelegationPoolContract A
  actor pool member
  pool member ->>+ DelegationPoolContract A: exit_delegation_pool_intent
  DelegationPoolContract A ->>- StakingContract: remove_from_delegation_pool_intent
  pool member ->>+ DelegationPoolContract A: switch_delegation_pool
  DelegationPoolContract A ->>+ StakingContract: switch_staking_delegation_pool
  StakingContract ->>- DelegationPoolContract B: enter_delegation_pool_from_staking_contract
  deactivate DelegationPoolContract A
  loop 
    Note left of StakingContract:  optional for switching some<br/> of the funds but keeping the rest<br/> with the original stakeror splitting<br/> between multiple stakers
    pool member ->>+ DelegationPoolContract A: switch_delegation_pool
    DelegationPoolContract A ->> StakingContract: switch_staking_delegation_pool
    StakingContract ->> DelegationPoolContract B: enter_delegation_pool_from_staking_contract
    deactivate DelegationPoolContract A
  end
Loading

L1 Mint & transfer flow diagram

sequenceDiagram
  actor anyAccount
  participant RewardSupplier
  participant MintingManager
  participant STRK ERC20
  participant StarkGate bridge
  anyAccount ->>+ RewardSupplier: tick(tokensPerMintAmount, maxMessagesToProcess)
  RewardSupplier ->>+ MintingManager: mintRequest(totalAmountToMint)
  MintingManager ->>- STRK ERC20: mint
  RewardSupplier ->>+ StarkGate bridge: depositWithMessage
  deactivate RewardSupplier
Loading

L2 Rewards calculation and minting request flow diagram

sequenceDiagram
  actor caller
  participant Staking
  participant RewardSupplier
  participant MintingCurve
  participant L1
  caller ->>+ Staking: update_global_index
  Staking ->>+ RewardSupplier: calculate_staking_rewards
  RewardSupplier ->>+ MintingCurve: yearly_mint
  MintingCurve ->> Staking: get_total_stake
  MintingCurve -->>- RewardSupplier: return yearly amount
  RewardSupplier ->>- L1: send mint request
  deactivate Staking
Loading

Staking contract

Functions

stake

fn stake(
  ref self: TContractState,
  reward_address: ContractAddress,
  operational_address: ContractAddress,
  amount: u128,
  pool_enabled: bool,
  commission: u16
)

description

Add a new staker to the stake.

emits

  1. New Delegation Pool - if pool_enabled is true
  2. Stake Balance Changed
  3. New Staker

errors

  1. CONTRACT_IS_PAUSED
  2. ONLY_OPERATOR
  3. STAKER_EXISTS
  4. OPERATIONAL_EXISTS
  5. AMOUNT_LESS_THAN_MIN_STAKE
  6. COMMISSION_OUT_OF_RANGE

pre-condition

  1. Staking contract is unpaused.
  2. Staker (caller) has operator role.
  3. Staker (caller) is not listed in the contract.
  4. operational_address is not listed in the contract.
  5. amount is above the minimum amount for staking.
  6. commission is not above the maximum commission for staking.

access control

Only staker address.

logic

  1. Transfer amount from staker to be locked in the contract.
  2. Create a new registry for the staker (caller).
  3. Set:
    1. Staker index = current global index.
    2. Unclaimed amount = 0.
    3. amount = given amount.
  4. If pool enabled then deploy a pool contract instance.

increase_stake

fn increase_stake(
    ref self: ContractState, 
    staker_address: ContractAddress, 
    amount: u128
) -> u128

description

Increase the amount staked for an existing staker. Return the updated total amount.

emits

Stake Balance Changed

errors

  1. CONTRACT_IS_PAUSED
  2. ONLY_OPERATOR
  3. STAKER_NOT_EXISTS
  4. UNSTAKE_IN_PROGRESS
  5. CALLER_CANNOT_INCREASE_STAKE

pre-condition

  1. Staking contract is unpaused.
  2. caller_address has operator role.
  3. Staker is listed in the contract.
  4. Staker is not in an exit window.

access control

Only the staker address or rewards address for which the change is requested for.

logic

  1. Calculate rewards.
  2. Increase staked amount.

unstake_intent

fn unstake_intent(ref self: ContractState) -> u64

description

Inform of the intent to exit the stake. This will remove the funds from the stake, pausing rewards collection for the staker and it's pool members (if exist). This will also start the exit window timeout. Return the time in which the staker will be able to unstake.

emits

  1. Staker Exit Intent
  2. Stake Balance Changed

errors

  1. CONTRACT_IS_PAUSED
  2. ONLY_OPERATOR
  3. STAKER_NOT_EXISTS
  4. UNSTAKE_IN_PROGRESS

pre-condition

  1. Staking contract is unpaused.
  2. Staker (caller) has operator role.
  3. Staker (caller) is listed in the contract.
  4. Staker (caller) is not in an exit window.

access control

Only the staker address for which the operation is requested for.

logic

  1. Calculate rewards.
  2. Set unstake time.

unstake_action

fn unstake_action(
  ref self: ContractState, 
  staker_address: ContractAddress
) -> u128

description

Executes the intent to exit the stake if enough time have passed. Transfers the funds back to the staker. Return the amount of tokens transferred back to the staker.

emits

  1. Staker Reward Claimed
  2. If pool exists: Rewards Supplied To Delegation Pool
  3. If pool exists: Final Index Set
  4. Delete Staker

errors

  1. CONTRACT_IS_PAUSED
  2. ONLY_OPERATOR
  3. STAKER_NOT_EXISTS
  4. MISSING_UNSTAKE_INTENT
  5. INTENT_WINDOW_NOT_FINISHED
  6. UNEXPECTED_BALANCE
  7. FINAL_STAKER_INDEX_ALREADY_SET

pre-condition

  1. Staking contract is unpaused.
  2. Staker (caller) has operator role.
  3. Staker exist and requested to unstake.
  4. Enough time have passed from the unstake intent call.

access control

Any address can execute.

logic

  1. Claim rewards.
  2. Remove funds and transfer to staker.
  3. Transfer pool unclaimed rewards and stake to delegation pool contract.
  4. Call set_final_staker_index on the delegation_pool_contract.
  5. Delete staker record.

claim_rewards

fn claim_rewards(
  ref self: ContractState, 
  staker_address: ContractAddress
) -> u128

description

Calculate rewards and transfer them to the reward address. Return the amount of tokens transferred to the reward address.

emits

  1. Staker Reward Claimed

errors

  1. CONTRACT_IS_PAUSED
  2. ONLY_OPERATOR
  3. STAKER_NOT_EXISTS
  4. CLAIM_REWARDS_FROM_UNAUTHORIZED_ADDRESS

pre-condition

  1. Staking contract is unpaused.
  2. caller_address has operator role.
  3. Staker is listed in the contract.

access control

Only staker address or reward address can execute.

logic

  1. Calculate rewards.
  2. Transfer unclaimed_rewards.
  3. Set unclaimed_rewards = 0.

add_stake_from_pool

fn add_stake_from_pool(
    ref self: ContractState, 
    staker_address: ContractAddress, 
    amount: u128
) -> (u128, u64)

description

Delegation pool contract's way to add funds to the staking pool.

return

pool_amount: u128 - total pool amount after addition. index: u64 - updated index

emits

  1. Stake Balance Changed

errors

  1. CONTRACT_IS_PAUSED
  2. ONLY_OPERATOR
  3. STAKER_NOT_EXISTS
  4. UNSTAKE_IN_PROGRESS
  5. MISSING_POOL_CONTRACT
  6. CALLER_IS_NOT_POOL_CONTRACT

pre-condition

  1. Staking contract is unpaused.
  2. Pool contract (caller) has operator role.
  3. Staker is listed in the contract.
  4. Staker is not in an exit window.
  5. Staker has pool contract.

access control

Only pool contract for the given staker can execute.

logic

  1. Calculate rewards
  2. transfer funds from pool contract to staking contract.
  3. Add amount to staker's pooled amount

remove_from_delegation_pool_intent

fn remove_from_delegation_pool_intent(
    ref self: ContractState,
    staker_address: ContractAddress,
    identifier: felt252,
    amount: u128,
) -> u64

description

Inform the staker that an amount will be reduced from the delegation pool. Return the time in which the pool member will be able to exit.

emits

  1. Stake Balance Changed

errors

  1. CONTRACT_IS_PAUSED
  2. ONLY_OPERATOR
  3. STAKER_NOT_EXISTS
  4. MISSING_POOL_CONTRACT
  5. CALLER_IS_NOT_POOL_CONTRACT
  6. AMOUNT_TOO_HIGH

pre-condition

  1. Staking contract is unpaused.
  2. Pool contract (caller) has operator role.
  3. Staker is listed in the contract.
  4. Staker has pool contract.
  5. Pooled amount is greater or equal then amount requested to remove.

access control

Only pool contract for the given staker can execute.

logic

  1. Calculate rewards.
  2. Remove amount from staker's pooled amount.
  3. Register intent with given identifier, amount and unstake_time.

remove_from_delegation_pool_action

fn remove_from_delegation_pool_action(
    ref self: ContractState, 
    identifier: felt252
) -> u128

description

Execute the intent to remove funds from pool if enough time have passed. Transfers the funds to the pool contract. Return the amount being transferred to the pool contract.

emits

errors

  1. CONTRACT_IS_PAUSED
  2. ONLY_OPERATOR
  3. INTENT_WINDOW_NOT_FINISHED

pre-condition

  1. Staking contract is unpaused.
  2. caller_address has operator role.
  3. Removal intent request with the given identifier have been sent before.
  4. Enough time have passed since the intent request.

access control

Any address can execute.

logic

  1. Transfer funds from staking contract to pool contract.
  2. Remove intent from staker's list.

switch_staking_delegation_pool

fn switch_staking_delegation_pool(
    ref self: ContractState,
    to_staker: ContractAddress,
    to_pool: ContractAddress,
    switched_amount: u128,
    data: Span<felt252>,
    identifier: felt252
) -> bool

description

Execute a pool member request to move from one staker's delegation pool to another staker's delegation pool. Return true upon success, otherwise return false.

emits

  1. Delegation Pool Member Balance Changed

errors

  1. CONTRACT_IS_PAUSED
  2. ONLY_OPERATOR
  3. MISSING_UNDELEGATE_INTENT
  4. AMOUNT_TOO_HIGH
  5. STAKER_NOT_EXISTS
  6. UNSTAKE_IN_PROGRESS
  7. MISSING_POOL_CONTRACT
  8. MISSMATCHED_DELEGATION_POOL

pre-condition

  1. Staking contract is unpaused.
  2. Pool contract (caller) has operator role.
  3. switched_amount is not zero.
  4. Enough funds is in intent for switching.
  5. to_staker exist in the contract and is not in exit window.
  6. to_pool is the delegation pool contract for to_staker.

access control

Only pool contract for the given staker can execute.

logic

  1. Calculate rewards.
  2. Remove requested amount from the caller pool intent amount.
  3. Add requested amount to to_staker's pool with pool contract address to_pool.
  4. Call to_pool's enter_delegation_pool_from_staking_contract function.

change_reward_address

fn change_reward_address(
  ref self: ContractState, 
  reward_address: ContractAddress
)

description

Change the reward address for a staker.

emits

  1. Staker Reward Address Changed

errors

  1. CONTRACT_IS_PAUSED
  2. ONLY_OPERATOR
  3. STAKER_NOT_EXISTS

pre-condition

  1. Staking contract is unpaused.
  2. Staker (caller) has operator role.
  3. Staker (caller) exist in the contract.

access control

Only staker address.

logic

  1. Change registered reward_address for the staker.

set_open_for_delegation

fn set_open_for_delegation(
  ref self: ContractState, 
  commission: u16
) -> ContractAddress

description

Creates a staking delegation pool for a staker that doesn't have one. Return the pool address.

emits

  1. New Delegation Pool

errors

  1. CONTRACT_IS_PAUSED
  2. ONLY_OPERATOR
  3. STAKER_NOT_EXISTS
  4. COMMISSION_OUT_OF_RANGE
  5. STAKER_ALREADY_HAS_POOL

pre-condition

  1. Staking contract is unpaused.
  2. Staker (caller) has operator role.
  3. Staker (caller) exist in the contract.
  4. commission is in valid range.
  5. Staker has no pool.

access control

Only staker address.

logic

  1. Generate pool contract for staker.
  2. Register pool.

claim_delegation_pool_rewards

fn claim_delegation_pool_rewards(
    ref self: ContractState, 
    staker_address: ContractAddress
) -> u64

description

Calculate rewards and transfer the delegation pool rewards to the delegation pool contract. Return the updated staker index.

emits

Rewards Supplied To Delegation Pool

errors

  1. CONTRACT_IS_PAUSED
  2. ONLY_OPERATOR
  3. STAKER_NOT_EXISTS
  4. MISSING_POOL_CONTRACT
  5. CALLER_IS_NOT_POOL_CONTRACT
  6. AMOUNT_TOO_HIGH
  7. UNEXPECTED_BALANCE

pre-condition

  1. Staking contract is unpaused.
  2. Pool contract (caller) has operator role.
  3. Staker exist in the contract.
  4. Delegation pool exist for the staker.

access control

Delegation pool contract of the given staker.

logic

  1. Calculate rewards
  2. Transfer rewards to pool contract.

staker_info

fn staker_info(
  self: @ContractState, 
  staker_address: ContractAddress
) -> StakerInfo

description

Return StakerInfo of the given staker.

emits

errors

  1. STAKER_NOT_EXISTS

pre-condition

  1. Staker exist in the contract.

access control

Any address can execute.

logic

  1. Return Staker's info.

contract_parameters

fn contract_parameters(self: @ContractState) -> StakingContractInfo

description

Return general parameters of the contract.

emits

errors

pre-condition

access control

logic

get_total_stake

get_total_stake(self: @ContractState) -> u128

description

Return the total stake amount.

emits

errors

pre-condition

access control

logic

calculate_rewards

note: internal logic

fn calculate_rewards(
  ref self: ContractState, 
  ref staker_info: StakerInfo
) -> bool

description

Calculate rewards, add amount to unclaimed_rewards, update index.

emits

errors

pre-condition

access control

Internal function.

logic

  1. If Staker is in an exit window, return false.
  2. Update index.
  3. Calculate rewards for amount_own.
  4. Calculate rewards for pool_info.amount.
  5. Update unclaimed_rewards_own with own rewards + pool rewards commission.
  6. Update pool_info.unclaimed_rewards with pool rewards without commission.

change_operational_address

fn change_operational_address(
    ref self: ContractState, 
    operational_address: ContractAddress
)

description

Change the operational address for a staker.

emits

  1. Operational Address Changed

errors

  1. CONTRACT_IS_PAUSED
  2. ONLY_OPERATOR
  3. STAKER_NOT_EXISTS

pre-condition

  1. Staking contract is unpaused.
  2. Staker (caller) has operator role.
  3. Staker (caller) exist in the contract.

access control

Only staker address.

logic

  1. Change registered operational_address for the staker.

update_global_index_if_needed

fn update_global_index_if_needed(ref self: TContractState) -> bool

description

Update the global index if enough time has passed since the last update. This function is called in every staking function that alter the state. Return true if the index has been updated.

emits

  1. Global Index Updated

errors

  1. CONTRACT_IS_PAUSED
  2. ONLY_OPERATOR

pre-condition

  1. Staking contract is unpaused.
  2. Caller has operator role.

access control

Any address can execute.

logic

  1. Check if enough time has passed since the last update, if not, return false.
  2. calculate_staking_rewards.
  3. get_total_stake.
  4. Update the global index.

is_paused

fn is_paused(self: @TContractState) -> bool

description

Return true if the staking contract is paused.

emits

errors

pre-condition

access control

Any address can execute.

logic

pause

fn pause(ref self: TContractState)

description

Pause the staking contract.

emits

  1. Paused

errors

  1. ONLY_SECURITY_AGENT

pre-condition

access control

Only security agent.

logic

unpause

fn unpause(ref self: TContractState)

description

Unpause the staking contract.

emits

  1. Unpaused

errors

  1. ONLY_SECURITY_ADMIN

pre-condition

access control

Only security admin.

logic

Events

Stake Balance Changed

data type keyed
staker_address address
old_self_stake u128
old_delegated_stake u128
new_self_stake u128
new_delegated_stake u128

New Delegation Pool

data type keyed
staker_address address
pool_contract address
commission u16

New Staker

data type keyed
staker_address address
reward_address address
operational_address address
self_stake u128

Staker Exit intent

data type keyed
staker address
exit_at time

Rewards Supplied To Delegation Pool

data type keyed
staker_address address
pool_address address
amount u128

Delete Staker

data type keyed
staker_address address
reward_address address
operational_address address
pool_contract Option

Staker Reward Claimed

data type keyed
staker_address address
reward_address address
amount u128

Staker Reward Address Changed

data type keyed
staker_address address
new_address address
old_address address

Operational Address Changed

data type keyed
staker_address address
new_address address
old_address address

Global Index Updated

data type keyed
old_index u64
new_index u64
global_index_last_update_timestamp u64
global_index_current_update_timestamp u64

Paused

data type keyed
account address

Unpaused

data type keyed
account address

Delegation pool contract

Functions

enter_delegation_pool

fn enter_delegation_pool(
    ref self: ContractState, 
    reward_address: ContractAddress, 
    amount: u128
)

description

Add a new pool member to the delegation pool.

emits

  1. Stake Balance Changed
  2. New Pool Member
  3. Delegation Pool Member Balance Changed

errors

  1. STAKER_INACTIVE
  2. POOL_MEMBER_EXISTS
  3. AMOUNT_IS_ZERO
  4. INSUFFICIENT_ALLOWANCE
  5. UNSTAKE_IN_PROGRESS

pre-condition

  1. Staker is active and not in an exit window.
  2. caller_address is not listed in the contract as a pool member.
  3. amount is not zero.
  4. caller_address has enough funds.

access control

Only a non-listed pool member address.

logic

  1. Transfer funds from pool member to pool contract.
  2. Approve transferal from pool contract to staking contract.
  3. Call staking contract's add_stake_from_pool.
  4. Get current index from staking contract.
  5. Create entry for pool member.

add_to_delegation_pool

fn add_to_delegation_pool(
    ref self: ContractState, 
    pool_member: ContractAddress, 
    amount: u128
) -> u128

description

Increase the funds for an existing pool member. Return the updated total amount.

emits

  1. Stake Balance Changed
  2. Delegation Pool Member Balance Changed

errors

  1. STAKER_INACTIVE
  2. POOL_MEMBER_DOES_NOT_EXIST
  3. CALLER_CANNOT_ADD_TO_POOL
  4. UNSTAKE_IN_PROGRESS

pre-condition

  1. Staker is active and not in an exit window.
  2. pool_member listed in the contract.
  3. pool_member has enough funds.

access control

Only the pool member address or rewards address for which the change is requested for.

logic

  1. Transfer funds from caller to the contract.
  2. Call staking contract's add_stake_from_pool.
  3. Get current index from staking contract.
  4. Calculate rewards
  5. Update pool member entry with
    1. index
    2. amount
    3. unclaimed rewards

exit_delegation_pool_intent

fn exit_delegation_pool_intent(
  ref self: ContractState, 
  amount: u128
)

description

Inform of the intent to exit the stake. This will remove the funds from the stake, pausing rewards collection for the pool member. This will also start the exit window timeout.

emits

  1. If staker is active: Rewards Supplied To Delegation Pool
  2. If staker is active: Stake Balance Changed
  3. Pool Member Exit Intent

errors

  1. POOL_MEMBER_DOES_NOT_EXIST
  2. AMOUNT_TOO_HIGH
  3. UNDELEGATE_IN_PROGRESS
  4. CONTRACT_IS_PAUSED
  5. ONLY_OPERATOR

pre-condition

  1. Pool member (caller) is listed in the contract.
  2. amount is lower or equal to the total amount of the pool member (caller).
  3. Pool member (caller) is not in an exit window or staker is active.
  4. Staking contract is unpaused.

access control

Only the pool member address for which the operation is requested for.

logic

  1. Calculate rewards
  2. If staker is active, call remove from delegation pool intent
  3. If amount is zero, remove request for intent (if exist).
  4. If amount is not zero, set exit window timeout.

exit_delegation_pool_action

fn exit_delegation_pool_action(
    ref self: ContractState, 
    pool_member: ContractAddress
) -> u128

description

Executes the intent to exit the stake if enough time have passed. Transfers the funds back to the pool member. Return the amount of tokens transferred back to the pool member.

emits

  1. Pool Member Reward Claimed
  2. Delete Pool Member

errors

  1. POOL_MEMBER_DOES_NOT_EXIST
  2. MISSING_UNDELEGATE_INTENT
  3. INTENT_WINDOW_NOT_FINISHED
  4. CONTRACT_IS_PAUSED
  5. ONLY_OPERATOR

pre-condition

  1. Pool member exist and requested to unstake.
  2. Enough time have passed from the delegation pool exit intent call.

access control

Any address can execute.

logic

  1. Remove from delegation pool action.
  2. Transfer rewards to pool member.
  3. Transfer funds to pool member.

claim_rewards

fn claim_rewards(
  ref self: ContractState, 
  pool_member: ContractAddress
) -> u128

description

Calculate rewards and transfer them to the reward address. Return the amount transferred to the reward address.

emits

errors

  1. POOL_MEMBER_DOES_NOT_EXIST
  2. POOL_CLAIM_REWARDS_FROM_UNAUTHORIZED_ADDRESS
  3. CONTRACT_IS_PAUSED
  4. ONLY_OPERATOR
  5. UNEXPECTED_BALANCE
  6. AMOUNT_TOO_HIGH

pre-condition

  1. pool_member is listed in the contract.

access control

Only pool member address or reward address can execute.

logic

  1. Calculate rewards.
  2. Transfer unclaimed_rewards
  3. Set unclaimed_rewards = 0.

switch_delegation_pool

fn switch_delegation_pool(
    ref self: ContractState,
    to_staker: ContractAddress,
    to_pool: ContractAddress,
    amount: u128
) -> u128

description

Request the staking contract to move a pool member to another pool contract. Return the amount left in exit window for the pool member in this pool.

emits

  1. Delegation Pool Member Balance Changed
  2. If pool member amount and intent amount are zero: Delete Pool Member

errors

  1. AMOUNT_IS_ZERO
  2. POOL_MEMBER_DOES_NOT_EXIST
  3. MISSING_UNDELEGATE_INTENT
  4. AMOUNT_TOO_HIGH
  5. CONTRACT_IS_PAUSED
  6. ONLY_OPERATOR
  7. UNSTAKE_IN_PROGRESS
  8. MISSMATCHED_DELEGATION_POOL

pre-condition

  1. amount is not zero.
  2. Pool member (caller) is in exit window.
  3. Pool member's amount is greater or equal to the amount requested.
  4. to_staker exist in the staking contract and is not in an exit window.
  5. to_pool is the delegation pool contract for to_staker.

access control

Only pool member can execute.

logic

  1. Compose and serialize data: pool member address and reward address.
  2. If pool member amount and intent amount are zero, transfer rewards to pool member and remove him from the pool.
  3. Call staking contract's switch delegation pool.

enter_delegation_pool_from_staking_contract

fn enter_delegation_pool_from_staking_contract(
    ref self: ContractState, 
    amount: u128, 
    index: u64, 
    data: Span<felt252>
)

description

Entry point for staking contract to inform pool of a pool member being moved from another pool to this one. No funds need to be transferred since staking contract holds the pool funds.

emits

  1. Delegation Pool Member Balance Changed

errors

  1. AMOUNT_IS_ZERO
  2. CALLER_IS_NOT_STAKING_CONTRACT
  3. SWITCH_POOL_DATA_DESERIALIZATION_FAILED

pre-condition

  1. amount is not zero.
  2. pool_member is not in an exit window.

access control

Only staking contract can execute.

logic

  1. Deserialize data, get pool_member and rewrad_address.
  2. If pool member is listed in the contract:
    1. Calculate rewards
    2. Update pool member entry
  3. Else
    1. Create an entry for the pool member.

set_final_staker_index

fn set_final_staker_index(
  ref self: ContractState, 
  final_staker_index: u64
)

description

Informs the delegation pool contract that the staker has left and the contract is now detached from the staking contract.

emits

  1. Final Index Set

errors

  1. CALLER_IS_NOT_STAKING_CONTRACT
  2. FINAL_STAKER_INDEX_ALREADY_SET

pre-condition

  1. Final staker index is not already set.

access control

Only staking contract can execute.

logic

  1. Set staker final index to the provided index.

change_reward_address

fn change_reward_address(
  ref self: ContractState, 
  reward_address: ContractAddress
)

description

Change the reward address for a pool member.

emits

  1. Pool Member Reward Address Changed

errors

  1. POOL_MEMBER_DOES_NOT_EXIST

pre-condition

  1. Pool member exist in the contract.

access control

Only pool member can execute.

logic

  1. Change registered reward_address for the pool member.

pool_member_info

fn pool_member_info(
  self: @ContractState, 
  pool_member: ContractAddress
) -> PoolMemberInfo

description

Return PoolMemberInfo of the given pool member.

emits

errors

  1. POOL_MEMBER_DOES_NOT_EXIST

pre-condition

  1. Pool member exist in the contract.

access control

Any address can execute.

logic

  1. Return Pool member info.

contract_parameters

fn contract_parameters(self: @ContractState) -> StakingContractInfo

description

Return PoolContractInfo of the contract.

emits

errors

pre-condition

access control

logic

calculate_rewards

fn calculate_rewards(
    ref self: ContractState, 
    ref pool_member_info: PoolMemberInfo, 
    updated_index: u64
)

note: internal logic

description

Calculate rewards, add amount to unclaimed_rewards, update index.

emits

errors

pre-condition

access control

internal function.

logic

  1. Update index.
  2. Calculate rewards for pool_member_info.
  3. Update unclaimed_rewards.

Events

New Staking Delegation Pool Member

data type keyed
staker address
pool_member address
amount u128

Delegation Pool Member Balance Changed

data type keyed
pool_member address
old_delegated_stake u128
new_delegated_stake u128

Pool Member Exit Intent

data type keyed
pool_member address
exit_at time

Final Index Set

data type keyed
staker_address address
final_staker_index u64

New Pool Member

data type keyed
pool_member address
staker_address address
reward_address address
amount u128

Delete Pool Member

data type keyed
pool_member address
reward_address address

Pool Member Reward Claimed

data type keyed
pool_member address
reward_address address
amount u128

Pool Member Reward Address Changed

data type keyed
pool_member address
new_address address
old_address address

L2 Reward supplier contract

Functions

calculate_staking_rewards

fn calculate_staking_rewards(ref self: TContractState) -> u128

description

Calculate the total amount of rewards owed to the stakers (based on total stake), since the previous time it was calculated.

return

rewards: u128 - the rewards owed to stakers, in FRI.

emits

Mint Request

errors

logic

  1. Invoke the Minting Curve's yearly_mint to receive the theoretic yearly amount of rewards.
  2. From the theoretic yearly amount, deduce the rewards from the last timestamp.
  3. Request funds from L1 if needed.

access control

Only staking contract.

claim_rewards

fn claim_rewards(ref self: TContractState, amount: u128)

description

Transfers amount FRI to staking contract

return

emits

errors

pre-condition

unclaimed_rewards >= amount

logic

  1. Transfer amount FRI to staking contract and decrease it from unclaimed_rewards.

access control

Only staking contract.

contract_parameters

fn contract_parameters(self: @TContractState) -> RewardSupplierInfo

description

Return RewardSupplierInfo filled with the corresponding storage values.

emits

errors

pre-condition

logic

access control

Any address can execute.

on_receive

fn on_receive(
    ref self: TContractState,
    l2_token: ContractAddress,
    amount: u256,
    depositor: EthAddress,
    message: Span<felt252>
)

description

Get notified by StarkGate amount was transferred from L1. Return true upon success. The function will fail only in the unlikely scenario where amount is over 2**128 FRI.

emits

errors

pre-condition

logic

  1. Decrease amount from l1_pending_requested_amount. If the expected result is negative, the variable is set to 0.

access control

Events

Mint Request

data type keyed
total_amount u128
num_msgs u128

Minting Curve Contract

Functions

yearly_mint

fn yearly_mint(self: @TContractState) -> u128

description

Return the amount to be minted in a year given the current total stake in the staking contract.

emits

errors

logic

  1. get_total_stake.
  2. Compute the yearly mint by using total_stake and total_supply.

access control

Any address can execute.

Events

Total Supply Changed

data type keyed
old_total_supply u128
new_total_supply u128

Errors

STAKER_EXISTS

"Staker already exists, use increase_stake instead."

STAKER_NOT_EXISTS

"Staker does not exist."

OPERATIONAL_EXISTS

"Operational address already exists."

AMOUNT_LESS_THAN_MIN_STAKE

"Amount is less than min stake - try again with enough funds."

COMMISSION_OUT_OF_RANGE

"Commission is out of range, expected to be 0-10000."

CONTRACT_IS_PAUSED

"Contract is paused."

UNSTAKE_IN_PROGRESS

"Unstake is in progress, staker is in an exit window."

CALLER_CANNOT_INCREASE_STAKE

"Caller address should be staker address or reward address."

MISSING_UNSTAKE_INTENT

"Unstake intent is missing."

INTENT_WINDOW_NOT_FINISHED

"Intent window is not finished."

UNEXPECTED_BALANCE

"Unexpected balance."

ONLY_OPERATOR

"ONLY_OPERATOR"

FINAL_STAKER_INDEX_ALREADY_SET

"Final staker index already set."

CLAIM_REWARDS_FROM_UNAUTHORIZED_ADDRESS

"Claim rewards must be called from staker address or reward address."

CALLER_IS_NOT_POOL_CONTRACT

"Caller is not pool contract."

MISSING_POOL_CONTRACT

"Staker does not have a pool contract."

AMOUNT_TOO_HIGH

"Amount is too high."

MISSMATCHED_DELEGATION_POOL

"to_pool is not the delegation pool contract for to_staker."

MISSING_UNDELEGATE_INTENT

"Undelegate intent is missing."

STAKER_ALREADY_HAS_POOL

"Staker already has a pool."

STAKER_INACTIVE

"Staker inactive."

POOL_MEMBER_EXISTS

"Pool member exists, use add_to_delegation_pool instead."

AMOUNT_IS_ZERO

"Amount is zero."

POOL_MEMBER_DOES_NOT_EXIST

"Pool member does not exist."

UNDELEGATE_IN_PROGRESS

"Undelegate from pool in progress, pool member is in an exit window."

CALLER_CANNOT_ADD_TO_POOL

"Caller address should be pool member address or reward address."

POOL_CLAIM_REWARDS_FROM_UNAUTHORIZED_ADDRESS

"Claim rewards must be called from pool member address or reward address."

CALLER_IS_NOT_STAKING_CONTRACT

"Caller is not staking contract."

SWITCH_POOL_DATA_DESERIALIZATION_FAILED

"Switch pool data deserialization failed."

ONLY_SECURITY_AGENT

"ONLY_SECURITY_AGENT"

ONLY_SECURITY_ADMIN

"ONLY_SECURITY_ADMIN"

Structs

StakerPoolInfo

name type
pool_contract address
amount u128
unclaimed_rewards u128
commission u16

StakerInfo

name type
reward_address address
operational_address address
unstake_time Option
amount_own u128
index u64
unclaimed_rewards_own u128
pool_info Option

StakingContractInfo

name type
min_stake u128
token_address address
global_index u64
pool_contract_class_hash ClassHash
reward_supplier address

PoolMemberInfo

name type
reward_address address
amount u128
index u64
unclaimed_rewards u128
unpool_amount u128
unpool_time Option

PoolContractInfo

name type
staker_address address
final_staker_index Option
staking_contract address
token_address address
commission u16

RewardSupplierInfo

name type
last_timestamp u64
unclaimed_rewards u128
l1_pending_requested_amount u128