Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new entry function create_vesting_contract_with_amounts #82

Open
wants to merge 6 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,17 @@ pub enum EntryFunctionCall {
contract_address: AccountAddress,
},

VestingWithoutStakingCreateVestingContractWithAmounts {
shareholders: Vec<AccountAddress>,
amounts: Vec<u64>,
schedule_numerator: Vec<u64>,
schedule_denominator: u64,
start_timestamp_secs: u64,
period_duration: u64,
withdrawal_address: AccountAddress,
contract_creation_seed: Vec<u8>,
},

/// Remove the lockup period for the vesting contract. This can only be called by the admin of the vesting contract.
/// Example usage: If admin find shareholder suspicious, admin can remove it.
VestingWithoutStakingRemoveShareholder {
Expand Down Expand Up @@ -1755,6 +1766,25 @@ impl EntryFunctionCall {
VestingWithoutStakingAdminWithdraw { contract_address } => {
vesting_without_staking_admin_withdraw(contract_address)
},
VestingWithoutStakingCreateVestingContractWithAmounts {
shareholders,
amounts,
schedule_numerator,
schedule_denominator,
start_timestamp_secs,
period_duration,
withdrawal_address,
contract_creation_seed,
} => vesting_without_staking_create_vesting_contract_with_amounts(
shareholders,
amounts,
schedule_numerator,
schedule_denominator,
start_timestamp_secs,
period_duration,
withdrawal_address,
contract_creation_seed,
),
VestingWithoutStakingRemoveShareholder {
contract_address,
shareholder_address,
Expand Down Expand Up @@ -4853,6 +4883,39 @@ pub fn vesting_without_staking_admin_withdraw(
))
}

pub fn vesting_without_staking_create_vesting_contract_with_amounts(
shareholders: Vec<AccountAddress>,
amounts: Vec<u64>,
schedule_numerator: Vec<u64>,
schedule_denominator: u64,
start_timestamp_secs: u64,
period_duration: u64,
withdrawal_address: AccountAddress,
contract_creation_seed: Vec<u8>,
) -> TransactionPayload {
TransactionPayload::EntryFunction(EntryFunction::new(
ModuleId::new(
AccountAddress::new([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1,
]),
ident_str!("vesting_without_staking").to_owned(),
),
ident_str!("create_vesting_contract_with_amounts").to_owned(),
vec![],
vec![
bcs::to_bytes(&shareholders).unwrap(),
bcs::to_bytes(&amounts).unwrap(),
bcs::to_bytes(&schedule_numerator).unwrap(),
bcs::to_bytes(&schedule_denominator).unwrap(),
bcs::to_bytes(&start_timestamp_secs).unwrap(),
bcs::to_bytes(&period_duration).unwrap(),
bcs::to_bytes(&withdrawal_address).unwrap(),
bcs::to_bytes(&contract_creation_seed).unwrap(),
],
))
}

/// Remove the lockup period for the vesting contract. This can only be called by the admin of the vesting contract.
/// Example usage: If admin find shareholder suspicious, admin can remove it.
pub fn vesting_without_staking_remove_shareholder(
Expand Down Expand Up @@ -6787,6 +6850,27 @@ mod decoder {
}
}

pub fn vesting_without_staking_create_vesting_contract_with_amounts(
payload: &TransactionPayload,
) -> Option<EntryFunctionCall> {
if let TransactionPayload::EntryFunction(script) = payload {
Some(
EntryFunctionCall::VestingWithoutStakingCreateVestingContractWithAmounts {
shareholders: bcs::from_bytes(script.args().get(0)?).ok()?,
amounts: bcs::from_bytes(script.args().get(1)?).ok()?,
schedule_numerator: bcs::from_bytes(script.args().get(2)?).ok()?,
schedule_denominator: bcs::from_bytes(script.args().get(3)?).ok()?,
start_timestamp_secs: bcs::from_bytes(script.args().get(4)?).ok()?,
period_duration: bcs::from_bytes(script.args().get(5)?).ok()?,
withdrawal_address: bcs::from_bytes(script.args().get(6)?).ok()?,
contract_creation_seed: bcs::from_bytes(script.args().get(7)?).ok()?,
},
)
} else {
None
}
}

pub fn vesting_without_staking_remove_shareholder(
payload: &TransactionPayload,
) -> Option<EntryFunctionCall> {
Expand Down Expand Up @@ -7460,6 +7544,10 @@ static SCRIPT_FUNCTION_DECODER_MAP: once_cell::sync::Lazy<EntryFunctionDecoderMa
"vesting_without_staking_admin_withdraw".to_string(),
Box::new(decoder::vesting_without_staking_admin_withdraw),
);
map.insert(
"vesting_without_staking_create_vesting_contract_with_amounts".to_string(),
Box::new(decoder::vesting_without_staking_create_vesting_contract_with_amounts),
);
map.insert(
"vesting_without_staking_remove_shareholder".to_string(),
Box::new(decoder::vesting_without_staking_remove_shareholder),
Expand Down
108 changes: 108 additions & 0 deletions aptos-move/framework/supra-framework/doc/vesting_without_staking.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Vesting without staking contract
- [Function `shareholders`](#0x1_vesting_without_staking_shareholders)
- [Function `shareholder`](#0x1_vesting_without_staking_shareholder)
- [Function `create_vesting_schedule`](#0x1_vesting_without_staking_create_vesting_schedule)
- [Function `create_vesting_contract_with_amounts`](#0x1_vesting_without_staking_create_vesting_contract_with_amounts)
- [Function `create_vesting_contract`](#0x1_vesting_without_staking_create_vesting_contract)
- [Function `vest`](#0x1_vesting_without_staking_vest)
- [Function `vest_individual`](#0x1_vesting_without_staking_vest_individual)
Expand Down Expand Up @@ -1105,6 +1106,113 @@ Create a vesting schedule with the given schedule of distributions, a vesting st



</details>

<a id="0x1_vesting_without_staking_create_vesting_contract_with_amounts"></a>

## Function `create_vesting_contract_with_amounts`



<pre><code><b>public</b> entry <b>fun</b> <a href="vesting_without_staking.md#0x1_vesting_without_staking_create_vesting_contract_with_amounts">create_vesting_contract_with_amounts</a>(admin: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, shareholders: <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector">vector</a>&lt;<b>address</b>&gt;, amounts: <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector">vector</a>&lt;u64&gt;, schedule_numerator: <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector">vector</a>&lt;u64&gt;, schedule_denominator: u64, start_timestamp_secs: u64, period_duration: u64, withdrawal_address: <b>address</b>, contract_creation_seed: <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector">vector</a>&lt;u8&gt;)
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> entry <b>fun</b> <a href="vesting_without_staking.md#0x1_vesting_without_staking_create_vesting_contract_with_amounts">create_vesting_contract_with_amounts</a> (
admin: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>,
shareholders: <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector">vector</a>&lt;<b>address</b>&gt;,
amounts: <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector">vector</a>&lt;u64&gt;,
schedule_numerator: <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector">vector</a>&lt;u64&gt;,
schedule_denominator: u64,
start_timestamp_secs: u64,
period_duration: u64,
withdrawal_address: <b>address</b>,
contract_creation_seed: <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector">vector</a>&lt;u8&gt;,
) <b>acquires</b> <a href="vesting_without_staking.md#0x1_vesting_without_staking_AdminStore">AdminStore</a> {
<b>assert</b>!(!<a href="system_addresses.md#0x1_system_addresses_is_reserved_address">system_addresses::is_reserved_address</a>(withdrawal_address),
<a href="../../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error_invalid_argument">error::invalid_argument</a>(<a href="vesting_without_staking.md#0x1_vesting_without_staking_EINVALID_WITHDRAWAL_ADDRESS">EINVALID_WITHDRAWAL_ADDRESS</a>),);
assert_account_is_registered_for_apt(withdrawal_address);
<b>assert</b>!(<a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector_length">vector::length</a>(&shareholders) &gt; 0,
<a href="../../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error_invalid_argument">error::invalid_argument</a>(<a href="vesting_without_staking.md#0x1_vesting_without_staking_ENO_SHAREHOLDERS">ENO_SHAREHOLDERS</a>));
<b>assert</b>!(
<a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector_length">vector::length</a>(&shareholders) == <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector_length">vector::length</a>(&amounts),
<a href="../../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error_invalid_argument">error::invalid_argument</a>(<a href="vesting_without_staking.md#0x1_vesting_without_staking_ESHARES_LENGTH_MISMATCH">ESHARES_LENGTH_MISMATCH</a>),
);

// If this is the first time this admin <a href="account.md#0x1_account">account</a> <b>has</b> created a <a href="vesting.md#0x1_vesting">vesting</a> contract, initialize the admin store.
<b>let</b> admin_address = <a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer_address_of">signer::address_of</a>(admin);
<b>if</b> (!<b>exists</b>&lt;<a href="vesting_without_staking.md#0x1_vesting_without_staking_AdminStore">AdminStore</a>&gt;(admin_address)) {
<b>move_to</b>(admin,
<a href="vesting_without_staking.md#0x1_vesting_without_staking_AdminStore">AdminStore</a> {
vesting_contracts: <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector_empty">vector::empty</a>&lt;<b>address</b>&gt;(),
nonce: 0,
create_events: new_event_handle&lt;<a href="vesting_without_staking.md#0x1_vesting_without_staking_CreateVestingContractEvent">CreateVestingContractEvent</a>&gt;(admin),
});
};

// Initialize the <a href="vesting.md#0x1_vesting">vesting</a> contract in a new resource <a href="account.md#0x1_account">account</a>. This allows the same admin <b>to</b> create multiple
// pools.
<b>let</b> (contract_signer, contract_signer_cap) = <a href="vesting_without_staking.md#0x1_vesting_without_staking_create_vesting_contract_account">create_vesting_contract_account</a>(admin,
contract_creation_seed);
<b>let</b> contract_signer_address = <a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer_address_of">signer::address_of</a>(&contract_signer);
<b>let</b> schedule = <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector_map_ref">vector::map_ref</a>(&schedule_numerator, |numerator| {
<b>let</b> <a href="event.md#0x1_event">event</a> = <a href="../../aptos-stdlib/../move-stdlib/doc/fixed_point32.md#0x1_fixed_point32_create_from_rational">fixed_point32::create_from_rational</a>(*numerator, schedule_denominator);
<a href="event.md#0x1_event">event</a>
});

<b>let</b> vesting_schedule = <a href="vesting_without_staking.md#0x1_vesting_without_staking_create_vesting_schedule">create_vesting_schedule</a>(schedule, start_timestamp_secs, period_duration);
<b>let</b> shareholders_map = <a href="../../aptos-stdlib/doc/simple_map.md#0x1_simple_map_create">simple_map::create</a>&lt;<b>address</b>, <a href="vesting_without_staking.md#0x1_vesting_without_staking_VestingRecord">VestingRecord</a>&gt;();
<b>let</b> grant_amount = 0;
<a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector_for_each_reverse">vector::for_each_reverse</a>(amounts, |amount| {
<b>let</b> shareholder = <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector_pop_back">vector::pop_back</a>(&<b>mut</b> shareholders);
<a href="../../aptos-stdlib/doc/simple_map.md#0x1_simple_map_add">simple_map::add</a>(&<b>mut</b> shareholders_map,
shareholder,
<a href="vesting_without_staking.md#0x1_vesting_without_staking_VestingRecord">VestingRecord</a> {
init_amount: amount,
left_amount: amount,
last_vested_period: vesting_schedule.last_vested_period,
}
);
grant_amount = grant_amount + amount;
});
<b>assert</b>!(grant_amount &gt; 0, <a href="../../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error_invalid_argument">error::invalid_argument</a>(<a href="vesting_without_staking.md#0x1_vesting_without_staking_EZERO_GRANT">EZERO_GRANT</a>));
<a href="coin.md#0x1_coin_transfer">coin::transfer</a>&lt;SupraCoin&gt;(admin, contract_signer_address, grant_amount);

<b>let</b> admin_store = <b>borrow_global_mut</b>&lt;<a href="vesting_without_staking.md#0x1_vesting_without_staking_AdminStore">AdminStore</a>&gt;(admin_address);
<a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector_push_back">vector::push_back</a>(&<b>mut</b> admin_store.vesting_contracts, contract_signer_address);
emit_event(&<b>mut</b> admin_store.create_events,
<a href="vesting_without_staking.md#0x1_vesting_without_staking_CreateVestingContractEvent">CreateVestingContractEvent</a> {
withdrawal_address,
grant_amount,
vesting_contract_address: contract_signer_address,
},
);

<b>move_to</b>(&contract_signer,
<a href="vesting_without_staking.md#0x1_vesting_without_staking_VestingContract">VestingContract</a> {
state: <a href="vesting_without_staking.md#0x1_vesting_without_staking_VESTING_POOL_ACTIVE">VESTING_POOL_ACTIVE</a>,
admin: admin_address,
shareholders:shareholders_map,
beneficiaries: <a href="../../aptos-stdlib/doc/simple_map.md#0x1_simple_map_create">simple_map::create</a>&lt;<b>address</b>, <b>address</b>&gt;(),
vesting_schedule,
withdrawal_address,
signer_cap: contract_signer_cap,
set_beneficiary_events: new_event_handle&lt;<a href="vesting_without_staking.md#0x1_vesting_without_staking_SetBeneficiaryEvent">SetBeneficiaryEvent</a>&gt;(&contract_signer),
vest_events: new_event_handle&lt;<a href="vesting_without_staking.md#0x1_vesting_without_staking_VestEvent">VestEvent</a>&gt;(&contract_signer),
terminate_events: new_event_handle&lt;<a href="vesting_without_staking.md#0x1_vesting_without_staking_TerminateEvent">TerminateEvent</a>&gt;(&contract_signer),
admin_withdraw_events: new_event_handle&lt;<a href="vesting_without_staking.md#0x1_vesting_without_staking_AdminWithdrawEvent">AdminWithdrawEvent</a>&gt;(&contract_signer),
shareholder_removed_events: new_event_handle&lt;<a href="vesting_without_staking.md#0x1_vesting_without_staking_ShareHolderRemovedEvent">ShareHolderRemovedEvent</a>&gt;(&contract_signer),
});
}
</code></pre>



</details>

<a id="0x1_vesting_without_staking_create_vesting_contract"></a>
Expand Down
2 changes: 1 addition & 1 deletion aptos-move/framework/supra-framework/sources/genesis.move
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module supra_framework::genesis {
use std::fixed_point32;
use std::vector;
use std::option;
use std::string::{Self, String};
use std::string::{String};

use aptos_std::simple_map;
use supra_framework::supra_account;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,93 @@ module supra_framework::vesting_without_staking {
}
}

public entry fun create_vesting_contract_with_amounts (
admin: &signer,
shareholders: vector<address>,
amounts: vector<u64>,
schedule_numerator: vector<u64>,
schedule_denominator: u64,
start_timestamp_secs: u64,
period_duration: u64,
withdrawal_address: address,
contract_creation_seed: vector<u8>,
) acquires AdminStore {
assert!(!system_addresses::is_reserved_address(withdrawal_address),
error::invalid_argument(EINVALID_WITHDRAWAL_ADDRESS),);
assert_account_is_registered_for_apt(withdrawal_address);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@axiongsupra , create an issue to replace assert_account_is_registered_for_apt with assert_account_is_registered_for_supra everywhere in the code base and address it in a separate PR.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see #90

assert!(vector::length(&shareholders) > 0,
error::invalid_argument(ENO_SHAREHOLDERS));
assert!(
vector::length(&shareholders) == vector::length(&amounts),
error::invalid_argument(ESHARES_LENGTH_MISMATCH),
);

// If this is the first time this admin account has created a vesting contract, initialize the admin store.
let admin_address = signer::address_of(admin);
if (!exists<AdminStore>(admin_address)) {
move_to(admin,
AdminStore {
vesting_contracts: vector::empty<address>(),
nonce: 0,
create_events: new_event_handle<CreateVestingContractEvent>(admin),
});
};

// Initialize the vesting contract in a new resource account. This allows the same admin to create multiple
// pools.
let (contract_signer, contract_signer_cap) = create_vesting_contract_account(admin,
contract_creation_seed);
let contract_signer_address = signer::address_of(&contract_signer);
let schedule = vector::map_ref(&schedule_numerator, |numerator| {
let event = fixed_point32::create_from_rational(*numerator, schedule_denominator);
event
});

let vesting_schedule = create_vesting_schedule(schedule, start_timestamp_secs, period_duration);
let shareholders_map = simple_map::create<address, VestingRecord>();
let grant_amount = 0;
vector::for_each_reverse(amounts, |amount| {
let shareholder = vector::pop_back(&mut shareholders);
simple_map::add(&mut shareholders_map,
shareholder,
VestingRecord {
init_amount: amount,
left_amount: amount,
last_vested_period: vesting_schedule.last_vested_period,
}
);
grant_amount = grant_amount + amount;
});
assert!(grant_amount > 0, error::invalid_argument(EZERO_GRANT));
coin::transfer<SupraCoin>(admin, contract_signer_address, grant_amount);

let admin_store = borrow_global_mut<AdminStore>(admin_address);
vector::push_back(&mut admin_store.vesting_contracts, contract_signer_address);
emit_event(&mut admin_store.create_events,
CreateVestingContractEvent {
withdrawal_address,
grant_amount,
vesting_contract_address: contract_signer_address,
},
);

move_to(&contract_signer,
VestingContract {
state: VESTING_POOL_ACTIVE,
admin: admin_address,
shareholders:shareholders_map,
beneficiaries: simple_map::create<address, address>(),
vesting_schedule,
withdrawal_address,
signer_cap: contract_signer_cap,
set_beneficiary_events: new_event_handle<SetBeneficiaryEvent>(&contract_signer),
vest_events: new_event_handle<VestEvent>(&contract_signer),
terminate_events: new_event_handle<TerminateEvent>(&contract_signer),
admin_withdraw_events: new_event_handle<AdminWithdrawEvent>(&contract_signer),
shareholder_removed_events: new_event_handle<ShareHolderRemovedEvent>(&contract_signer),
});
}

/// Create a vesting contract with a given configurations.
public fun create_vesting_contract(
admin: &signer,
Expand Down