starcoin-framework

Module 0x1::TreasuryWithdrawDaoProposal

TreasuryWithdrawDaoProposal is a dao proposal for withdraw Token from Treasury.

use 0x1::CoreAddresses;
use 0x1::Dao;
use 0x1::Errors;
use 0x1::Signer;
use 0x1::Token;
use 0x1::Treasury;

Resource WrappedWithdrawCapability

A wrapper of Token MintCapability.

struct WrappedWithdrawCapability<TokenT> has key
Fields
cap: Treasury::WithdrawCapability<TokenT>

Struct WithdrawToken

WithdrawToken request.

struct WithdrawToken has copy, drop, store
Fields
receiver: address
the receiver of withdraw tokens.
amount: u128
how many tokens to mint.
period: u64
How long in milliseconds does it take for the token to be released

Constants

const ERR_NOT_AUTHORIZED: u64 = 101;

Only receiver can execute TreasuryWithdrawDaoProposal

const ERR_NEED_RECEIVER_TO_EXECUTE: u64 = 102;

The withdraw amount of propose is too many.

const ERR_TOO_MANY_WITHDRAW_AMOUNT: u64 = 103;

Function plugin

Plugin method of the module. Should be called by token issuer.

public fun plugin<TokenT: store>(signer: &signer, cap: Treasury::WithdrawCapability<TokenT>)
Implementation
public fun plugin<TokenT: store>(signer: &signer, cap: Treasury::WithdrawCapability<TokenT>) {
    let token_issuer = Token::token_address<TokenT>();
    assert!(Signer::address_of(signer) == token_issuer, Errors::requires_address(ERR_NOT_AUTHORIZED));
    move_to(signer, WrappedWithdrawCapability<TokenT> { cap: cap });
}
Specification
pragma aborts_if_is_partial = false;
let sender = Signer::address_of(signer);
aborts_if sender != Token::SPEC_TOKEN_TEST_ADDRESS();
aborts_if !exists<Treasury::WithdrawCapability<TokenT>>(sender);
aborts_if exists<WrappedWithdrawCapability<TokenT>>(sender);
ensures !exists<Treasury::WithdrawCapability<TokenT>>(sender);
ensures exists<WrappedWithdrawCapability<TokenT>>(sender);

Function propose_withdraw

Entrypoint for the proposal.

public fun propose_withdraw<TokenT: copy, drop, store>(signer: &signer, receiver: address, amount: u128, period: u64, exec_delay: u64)
Implementation
public fun propose_withdraw<TokenT: copy + drop + store>(signer: &signer, receiver: address, amount: u128, period: u64, exec_delay: u64) {
    let quorum_votes = Dao::quorum_votes<TokenT>();
    assert!(amount <= quorum_votes,  Errors::invalid_argument(ERR_TOO_MANY_WITHDRAW_AMOUNT));
    Dao::propose<TokenT, WithdrawToken>(
        signer,
        WithdrawToken { receiver, amount, period },
        exec_delay,
    );
}
Specification
pragma aborts_if_is_partial = false;
let quorum_votes = Dao::spec_quorum_votes<TokenT>();
aborts_if amount > quorum_votes;
include Dao::AbortIfDaoConfigNotExist<TokenT>;
include Dao::AbortIfDaoInfoNotExist<TokenT>;
aborts_if !exists<Timestamp::CurrentTimeMilliseconds>(CoreAddresses::SPEC_GENESIS_ADDRESS());
aborts_if exec_delay > 0 && exec_delay < Dao::spec_dao_config<TokenT>().min_action_delay;
include Dao::CheckQuorumVotes<TokenT>;
let sender = Signer::address_of(signer);
aborts_if exists<Dao::Proposal<TokenT, WithdrawToken>>(sender);

Function execute_withdraw_proposal

Once the proposal is agreed, anyone can call the method to make the proposal happen.

public fun execute_withdraw_proposal<TokenT: copy, drop, store>(signer: &signer, proposer_address: address, proposal_id: u64)
Implementation
public fun execute_withdraw_proposal<TokenT: copy + drop + store>(
    signer: &signer,
    proposer_address: address,
    proposal_id: u64,
) acquires WrappedWithdrawCapability {
    let WithdrawToken { receiver, amount, period } = Dao::extract_proposal_action<TokenT, WithdrawToken>(
        proposer_address,
        proposal_id,
    );
    assert!(receiver == Signer::address_of(signer), Errors::requires_address(ERR_NEED_RECEIVER_TO_EXECUTE));
    let cap = borrow_global_mut<WrappedWithdrawCapability<TokenT>>(Token::token_address<TokenT>());
    let linear_cap = Treasury::issue_linear_withdraw_capability<TokenT>(&mut cap.cap, amount, period);
    Treasury::add_linear_withdraw_capability(signer, linear_cap);
}
Specification
pragma aborts_if_is_partial = true;
let expected_states = vec<u8>(6);
include Dao::CheckProposalStates<TokenT, WithdrawToken>{expected_states};
let proposal = global<Dao::Proposal<TokenT, WithdrawToken>>(proposer_address);
aborts_if Option::is_none(proposal.action);
aborts_if !exists<WrappedWithdrawCapability<TokenT>>(Token::SPEC_TOKEN_TEST_ADDRESS());

Function withdraw_for_block_reward

Provider a port for get block reward STC from Treasury, only genesis account can invoke this function. The TreasuryWithdrawCapability is locked in TreasuryWithdrawDaoProposal, and only can withdraw by DAO proposal. This approach is not graceful, but restricts the operation to genesis accounts only, so there are no security issues either.

public fun withdraw_for_block_reward<TokenT: store>(signer: &signer, reward: u128): Token::Token<TokenT>
Implementation
public fun withdraw_for_block_reward<TokenT: store>(signer: &signer, reward: u128):Token<TokenT> acquires WrappedWithdrawCapability  {
    CoreAddresses::assert_genesis_address(signer);
    let cap = borrow_global_mut<WrappedWithdrawCapability<TokenT>>(Signer::address_of(signer));
    Treasury::withdraw_with_capability(&mut cap.cap, reward)
}

Module Specification

pragma verify = false;
pragma aborts_if_is_strict;
pragma aborts_if_is_partial;