diff --git a/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs b/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs index 374f8b7706515..89ae5721f4d39 100644 --- a/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs +++ b/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs @@ -1047,6 +1047,17 @@ pub enum EntryFunctionCall { contract_address: AccountAddress, }, + VestingWithoutStakingCreateVestingContractWithAmounts { + shareholders: Vec, + amounts: Vec, + schedule_numerator: Vec, + schedule_denominator: u64, + start_timestamp_secs: u64, + period_duration: u64, + withdrawal_address: AccountAddress, + contract_creation_seed: Vec, + }, + /// 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 { @@ -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, @@ -4853,6 +4883,39 @@ pub fn vesting_without_staking_admin_withdraw( )) } +pub fn vesting_without_staking_create_vesting_contract_with_amounts( + shareholders: Vec, + amounts: Vec, + schedule_numerator: Vec, + schedule_denominator: u64, + start_timestamp_secs: u64, + period_duration: u64, + withdrawal_address: AccountAddress, + contract_creation_seed: Vec, +) -> 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( @@ -6787,6 +6850,27 @@ mod decoder { } } + pub fn vesting_without_staking_create_vesting_contract_with_amounts( + payload: &TransactionPayload, + ) -> Option { + 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 { @@ -7460,6 +7544,10 @@ static SCRIPT_FUNCTION_DECODER_MAP: once_cell::sync::Lazy + + + +## Function `create_vesting_contract_with_amounts` + + + +
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>)
+
+ + + +
+Implementation + + +
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);
+    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),
+        });
+}
+
+ + +
diff --git a/aptos-move/framework/supra-framework/sources/genesis.move b/aptos-move/framework/supra-framework/sources/genesis.move index 1397e9c63cb4c..34c3985632e44 100644 --- a/aptos-move/framework/supra-framework/sources/genesis.move +++ b/aptos-move/framework/supra-framework/sources/genesis.move @@ -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; diff --git a/aptos-move/framework/supra-framework/sources/vesting_without_staking.move b/aptos-move/framework/supra-framework/sources/vesting_without_staking.move index d2fccc60df6ae..430a28ef43422 100644 --- a/aptos-move/framework/supra-framework/sources/vesting_without_staking.move +++ b/aptos-move/framework/supra-framework/sources/vesting_without_staking.move @@ -287,6 +287,93 @@ module supra_framework::vesting_without_staking { } } + public entry fun create_vesting_contract_with_amounts ( + admin: &signer, + shareholders: vector
, + amounts: vector, + schedule_numerator: vector, + schedule_denominator: u64, + start_timestamp_secs: u64, + period_duration: u64, + withdrawal_address: address, + contract_creation_seed: vector, + ) acquires AdminStore { + assert!(!system_addresses::is_reserved_address(withdrawal_address), + error::invalid_argument(EINVALID_WITHDRAWAL_ADDRESS),); + assert_account_is_registered_for_apt(withdrawal_address); + 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(admin_address)) { + move_to(admin, + AdminStore { + vesting_contracts: vector::empty
(), + nonce: 0, + create_events: new_event_handle(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(); + 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(admin, contract_signer_address, grant_amount); + + let admin_store = borrow_global_mut(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(), + vesting_schedule, + withdrawal_address, + signer_cap: contract_signer_cap, + set_beneficiary_events: new_event_handle(&contract_signer), + vest_events: new_event_handle(&contract_signer), + terminate_events: new_event_handle(&contract_signer), + admin_withdraw_events: new_event_handle(&contract_signer), + shareholder_removed_events: new_event_handle(&contract_signer), + }); + } + /// Create a vesting contract with a given configurations. public fun create_vesting_contract( admin: &signer,