diff --git a/framework/cached-packages/src/libra_framework_sdk_builder.rs b/framework/cached-packages/src/libra_framework_sdk_builder.rs index 41a38d8b2..6e00fdd5d 100644 --- a/framework/cached-packages/src/libra_framework_sdk_builder.rs +++ b/framework/cached-packages/src/libra_framework_sdk_builder.rs @@ -219,33 +219,33 @@ pub enum EntryFunctionCall { should_pass: bool, }, - DonorDirectedMakeDonorDirectedTx { + DonorVoiceMakeDonorVoiceTx { init_signers: Vec, cfg_n_signers: u64, }, - DonorDirectedProposeLiquidateTx { + DonorVoiceProposeLiquidateTx { multisig_address: AccountAddress, }, - DonorDirectedProposePaymentTx { + DonorVoiceProposePaymentTx { multisig_address: AccountAddress, payee: AccountAddress, value: u64, description: Vec, }, - DonorDirectedProposeVetoTx { + DonorVoiceProposeVetoTx { multisig_address: AccountAddress, id: u64, }, - DonorDirectedVoteLiquidationTx { + DonorVoiceVoteLiquidationTx { multisig_address: AccountAddress, }, /// Entry functiont to vote the veto. - DonorDirectedVoteVetoTx { + DonorVoiceVoteVetoTx { multisig_address: AccountAddress, id: u64, }, @@ -680,30 +680,30 @@ impl EntryFunctionCall { proposal_id, should_pass, } => diem_governance_vote(proposal_id, should_pass), - DonorDirectedMakeDonorDirectedTx { + DonorVoiceMakeDonorVoiceTx { init_signers, cfg_n_signers, - } => donor_directed_make_donor_directed_tx(init_signers, cfg_n_signers), - DonorDirectedProposeLiquidateTx { multisig_address } => { - donor_directed_propose_liquidate_tx(multisig_address) + } => donor_voice_make_donor_voice_tx(init_signers, cfg_n_signers), + DonorVoiceProposeLiquidateTx { multisig_address } => { + donor_voice_propose_liquidate_tx(multisig_address) } - DonorDirectedProposePaymentTx { + DonorVoiceProposePaymentTx { multisig_address, payee, value, description, - } => donor_directed_propose_payment_tx(multisig_address, payee, value, description), - DonorDirectedProposeVetoTx { + } => donor_voice_propose_payment_tx(multisig_address, payee, value, description), + DonorVoiceProposeVetoTx { multisig_address, id, - } => donor_directed_propose_veto_tx(multisig_address, id), - DonorDirectedVoteLiquidationTx { multisig_address } => { - donor_directed_vote_liquidation_tx(multisig_address) + } => donor_voice_propose_veto_tx(multisig_address, id), + DonorVoiceVoteLiquidationTx { multisig_address } => { + donor_voice_vote_liquidation_tx(multisig_address) } - DonorDirectedVoteVetoTx { + DonorVoiceVoteVetoTx { multisig_address, id, - } => donor_directed_vote_veto_tx(multisig_address, id), + } => donor_voice_vote_veto_tx(multisig_address, id), JailUnjailByVoucher { addr } => jail_unjail_by_voucher(addr), GasCoinClaimMintCapability {} => gas_coin_claim_mint_capability(), GasCoinDelegateMintCapability { to } => gas_coin_delegate_mint_capability(to), @@ -1380,7 +1380,7 @@ pub fn diem_governance_vote(proposal_id: u64, should_pass: bool) -> TransactionP )) } -pub fn donor_directed_make_donor_directed_tx( +pub fn donor_voice_make_donor_voice_tx( init_signers: Vec, cfg_n_signers: u64, ) -> TransactionPayload { @@ -1390,9 +1390,9 @@ pub fn donor_directed_make_donor_directed_tx( 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!("donor_directed").to_owned(), + ident_str!("donor_voice").to_owned(), ), - ident_str!("make_donor_directed_tx").to_owned(), + ident_str!("make_donor_voice_tx").to_owned(), vec![], vec![ bcs::to_bytes(&init_signers).unwrap(), @@ -1401,14 +1401,14 @@ pub fn donor_directed_make_donor_directed_tx( )) } -pub fn donor_directed_propose_liquidate_tx(multisig_address: AccountAddress) -> TransactionPayload { +pub fn donor_voice_propose_liquidate_tx(multisig_address: AccountAddress) -> 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!("donor_directed").to_owned(), + ident_str!("donor_voice").to_owned(), ), ident_str!("propose_liquidate_tx").to_owned(), vec![], @@ -1416,7 +1416,7 @@ pub fn donor_directed_propose_liquidate_tx(multisig_address: AccountAddress) -> )) } -pub fn donor_directed_propose_payment_tx( +pub fn donor_voice_propose_payment_tx( multisig_address: AccountAddress, payee: AccountAddress, value: u64, @@ -1428,7 +1428,7 @@ pub fn donor_directed_propose_payment_tx( 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!("donor_directed").to_owned(), + ident_str!("donor_voice").to_owned(), ), ident_str!("propose_payment_tx").to_owned(), vec![], @@ -1441,7 +1441,7 @@ pub fn donor_directed_propose_payment_tx( )) } -pub fn donor_directed_propose_veto_tx( +pub fn donor_voice_propose_veto_tx( multisig_address: AccountAddress, id: u64, ) -> TransactionPayload { @@ -1451,7 +1451,7 @@ pub fn donor_directed_propose_veto_tx( 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!("donor_directed").to_owned(), + ident_str!("donor_voice").to_owned(), ), ident_str!("propose_veto_tx").to_owned(), vec![], @@ -1462,14 +1462,14 @@ pub fn donor_directed_propose_veto_tx( )) } -pub fn donor_directed_vote_liquidation_tx(multisig_address: AccountAddress) -> TransactionPayload { +pub fn donor_voice_vote_liquidation_tx(multisig_address: AccountAddress) -> 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!("donor_directed").to_owned(), + ident_str!("donor_voice").to_owned(), ), ident_str!("vote_liquidation_tx").to_owned(), vec![], @@ -1478,17 +1478,14 @@ pub fn donor_directed_vote_liquidation_tx(multisig_address: AccountAddress) -> T } /// Entry functiont to vote the veto. -pub fn donor_directed_vote_veto_tx( - multisig_address: AccountAddress, - id: u64, -) -> TransactionPayload { +pub fn donor_voice_vote_veto_tx(multisig_address: AccountAddress, id: u64) -> 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!("donor_directed").to_owned(), + ident_str!("donor_voice").to_owned(), ), ident_str!("vote_veto_tx").to_owned(), vec![], @@ -2642,11 +2639,11 @@ mod decoder { } } - pub fn donor_directed_make_donor_directed_tx( + pub fn donor_voice_make_donor_voice_tx( payload: &TransactionPayload, ) -> Option { if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::DonorDirectedMakeDonorDirectedTx { + Some(EntryFunctionCall::DonorVoiceMakeDonorVoiceTx { init_signers: bcs::from_bytes(script.args().get(0)?).ok()?, cfg_n_signers: bcs::from_bytes(script.args().get(1)?).ok()?, }) @@ -2655,11 +2652,11 @@ mod decoder { } } - pub fn donor_directed_propose_liquidate_tx( + pub fn donor_voice_propose_liquidate_tx( payload: &TransactionPayload, ) -> Option { if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::DonorDirectedProposeLiquidateTx { + Some(EntryFunctionCall::DonorVoiceProposeLiquidateTx { multisig_address: bcs::from_bytes(script.args().get(0)?).ok()?, }) } else { @@ -2667,11 +2664,11 @@ mod decoder { } } - pub fn donor_directed_propose_payment_tx( + pub fn donor_voice_propose_payment_tx( payload: &TransactionPayload, ) -> Option { if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::DonorDirectedProposePaymentTx { + Some(EntryFunctionCall::DonorVoiceProposePaymentTx { multisig_address: bcs::from_bytes(script.args().get(0)?).ok()?, payee: bcs::from_bytes(script.args().get(1)?).ok()?, value: bcs::from_bytes(script.args().get(2)?).ok()?, @@ -2682,11 +2679,9 @@ mod decoder { } } - pub fn donor_directed_propose_veto_tx( - payload: &TransactionPayload, - ) -> Option { + pub fn donor_voice_propose_veto_tx(payload: &TransactionPayload) -> Option { if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::DonorDirectedProposeVetoTx { + Some(EntryFunctionCall::DonorVoiceProposeVetoTx { multisig_address: bcs::from_bytes(script.args().get(0)?).ok()?, id: bcs::from_bytes(script.args().get(1)?).ok()?, }) @@ -2695,11 +2690,11 @@ mod decoder { } } - pub fn donor_directed_vote_liquidation_tx( + pub fn donor_voice_vote_liquidation_tx( payload: &TransactionPayload, ) -> Option { if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::DonorDirectedVoteLiquidationTx { + Some(EntryFunctionCall::DonorVoiceVoteLiquidationTx { multisig_address: bcs::from_bytes(script.args().get(0)?).ok()?, }) } else { @@ -2707,9 +2702,9 @@ mod decoder { } } - pub fn donor_directed_vote_veto_tx(payload: &TransactionPayload) -> Option { + pub fn donor_voice_vote_veto_tx(payload: &TransactionPayload) -> Option { if let TransactionPayload::EntryFunction(script) = payload { - Some(EntryFunctionCall::DonorDirectedVoteVetoTx { + Some(EntryFunctionCall::DonorVoiceVoteVetoTx { multisig_address: bcs::from_bytes(script.args().get(0)?).ok()?, id: bcs::from_bytes(script.args().get(1)?).ok()?, }) @@ -3312,28 +3307,28 @@ static SCRIPT_FUNCTION_DECODER_MAP: once_cell::sync::Lazy, // donor directed wallets need a place to reference all the donors in the case of liquidation. + depositors: vector
, // TODO: donor directed wallets need a + // place to reference all the donors in the case of liquidation, maybe + // this is the wrong place. } - - //////// 0L //////// // init struct for storing cumulative deposits, for community wallets - // TODO: set true or false, that the account gets current balance or - // starts at zero. public(friend) fun init_cumulative_deposits(sender: &signer) { let addr = signer::address_of(sender); if (!exists(addr)) { @@ -35,28 +33,17 @@ module ol_framework::cumulative_deposits { }; } - public fun vm_migrate_cumulative_deposits(vm: &signer, sender: &signer, starting_balance: u64) { - system_addresses::assert_ol(vm); - let addr = signer::address_of(sender); - if (!exists(addr)) { - move_to(sender, CumulativeDeposits { - value: starting_balance, - index: starting_balance, - depositors: vector::empty
(), - }) - }; - } - /// private function for the genesis fork migration /// adjust for the coin split factor. - // TODO! split factor wil likely have fractions - fun fork_migrate_cumulative_deposits(vm: &signer, sender: &signer, value: u64, index: u64, coin_split_factor: u64) { + // NOTE: doing split factor on rust side + fun genesis_migrate_cumulative_deposits(vm: &signer, sender: &signer, value: + u64, index: u64, depositors: vector
) { system_addresses::assert_ol(vm); if (!exists(signer::address_of(sender))) { move_to(sender, CumulativeDeposits { - value: value * coin_split_factor, - index: index * coin_split_factor, - depositors: vector::empty
(), + value, + index, + depositors, }) }; } @@ -145,4 +132,9 @@ module ol_framework::cumulative_deposits { borrow_global(addr).index } + #[test_only] + public fun test_init_cumulative_deposits(sig: &signer) { + init_cumulative_deposits(sig) + } + } \ No newline at end of file diff --git a/framework/libra-framework/sources/ol_sources/epoch_boundary.move b/framework/libra-framework/sources/ol_sources/epoch_boundary.move index 4a9f6f93a..352e107a3 100644 --- a/framework/libra-framework/sources/ol_sources/epoch_boundary.move +++ b/framework/libra-framework/sources/ol_sources/epoch_boundary.move @@ -10,7 +10,7 @@ module diem_framework::epoch_boundary { // use ol_framework::grade; use ol_framework::safe; use ol_framework::burn; - use ol_framework::donor_directed; + use ol_framework::donor_voice; use ol_framework::fee_maker; use ol_framework::tower_state; use ol_framework::infra_escrow; @@ -162,7 +162,7 @@ module diem_framework::epoch_boundary { // bill root service fees; root_service_billing(root, status); // run the transactions of donor directed accounts - let (count, amount, success) = donor_directed::process_donor_directed_accounts(root, closing_epoch); + let (count, amount, success) = donor_voice::process_donor_voice_accounts(root, closing_epoch); status.dd_accounts_count = count; status.dd_accounts_amount = amount; status.dd_accounts_success = success; diff --git a/framework/libra-framework/sources/ol_sources/match_index.move b/framework/libra-framework/sources/ol_sources/match_index.move index 5a34f7a1e..466470479 100644 --- a/framework/libra-framework/sources/ol_sources/match_index.move +++ b/framework/libra-framework/sources/ol_sources/match_index.move @@ -18,7 +18,8 @@ module ol_framework::match_index { /// The Match index keeps accounts that have opted-in. struct MatchIndex has key { addr: vector
, - index: vector, // the index of cumulative deposits: weighted in favor of most recent deposits. + index: vector, // the index of cumulative deposits: weighted in favor + // of most recent deposits, per cumulative_deposits.move ratio: vector, } /// initialize, usually for testnet. diff --git a/framework/libra-framework/sources/ol_sources/ol_account.move b/framework/libra-framework/sources/ol_sources/ol_account.move index 0ab950f07..7bb976116 100644 --- a/framework/libra-framework/sources/ol_sources/ol_account.move +++ b/framework/libra-framework/sources/ol_sources/ol_account.move @@ -18,7 +18,7 @@ module ol_framework::ol_account { #[test_only] use std::vector; - friend ol_framework::donor_directed; + friend ol_framework::donor_voice; friend ol_framework::burn; friend ol_framework::safe; friend diem_framework::genesis; diff --git a/framework/libra-framework/sources/ol_sources/tests/cumu_deposits.test.move b/framework/libra-framework/sources/ol_sources/tests/cumu_deposits.test.move index daa2a71de..075858d6e 100644 --- a/framework/libra-framework/sources/ol_sources/tests/cumu_deposits.test.move +++ b/framework/libra-framework/sources/ol_sources/tests/cumu_deposits.test.move @@ -6,12 +6,13 @@ module ol_framework::test_cumu_deposits { use ol_framework::cumulative_deposits; use ol_framework::receipts; use ol_framework::mock; + // use std::vector; // use diem_std::debug::print; #[test(root = @ol_framework, alice = @0x1000a)] fun cumu_deposits_init(root: &signer, alice: &signer) { mock::genesis_n_vals(root, 2); - cumulative_deposits::vm_migrate_cumulative_deposits(root, alice, 0); + cumulative_deposits::test_init_cumulative_deposits(alice); assert!(cumulative_deposits::is_init_cumu_tracking(@0x1000a), 7357001); let t = cumulative_deposits::get_cumulative_deposits(@0x1000a); @@ -25,7 +26,7 @@ module ol_framework::test_cumu_deposits { fun cumu_deposits_track(root: &signer, alice: &signer, bob: &signer) { mock::genesis_n_vals(root, 2); mock::ol_initialize_coin_and_fund_vals(root, 10000, true); - cumulative_deposits::vm_migrate_cumulative_deposits(root, alice, 0); + cumulative_deposits::test_init_cumulative_deposits(alice); assert!(cumulative_deposits::is_init_cumu_tracking(@0x1000a), 7357001); let t = cumulative_deposits::get_cumulative_deposits(@0x1000a); diff --git a/framework/libra-framework/sources/ol_sources/tests/donor_directed.test.move b/framework/libra-framework/sources/ol_sources/tests/donor_voicetest.move similarity index 63% rename from framework/libra-framework/sources/ol_sources/tests/donor_directed.test.move rename to framework/libra-framework/sources/ol_sources/tests/donor_voicetest.move index 897582037..984f5acf1 100644 --- a/framework/libra-framework/sources/ol_sources/tests/donor_directed.test.move +++ b/framework/libra-framework/sources/ol_sources/tests/donor_voicetest.move @@ -1,13 +1,13 @@ #[test_only] -module ol_framework::test_donor_directed { - use ol_framework::donor_directed; +module ol_framework::test_donor_voice { + use ol_framework::donor_voice; use ol_framework::mock; use ol_framework::ol_account; use diem_framework::resource_account; use ol_framework::receipts; - use ol_framework::donor_directed_governance; + use ol_framework::donor_voice_governance; use ol_framework::burn; use std::guid; use std::vector; @@ -21,17 +21,17 @@ module ol_framework::test_donor_directed { // Alice turns this account into a resource account. This can also happen after other donor directed initializations happen (or deposits). But must be complete before the donor directed wallet can be used. let (resource_sig, _cap) = ol_account::ol_create_resource_account(alice, b"0x1"); - let donor_directed_address = signer::address_of(&resource_sig); - assert!(resource_account::is_resource_account(donor_directed_address), 7357003); + let donor_voice_address = signer::address_of(&resource_sig); + assert!(resource_account::is_resource_account(donor_voice_address), 7357003); // the account needs basic donor directed structs - donor_directed::make_donor_directed(&resource_sig, vals, 2); + donor_voice::make_donor_voice(&resource_sig, vals, 2); - let list = donor_directed::get_root_registry(); + let list = donor_voice::get_root_registry(); assert!(vector::length(&list) == 1, 7357001); - assert!(donor_directed::is_donor_directed(donor_directed_address), 7357002); + assert!(donor_voice::is_donor_voice(donor_voice_address), 7357002); } #[test(root = @ol_framework, alice = @0x1000a, bob = @0x1000b)] @@ -41,20 +41,20 @@ module ol_framework::test_donor_directed { let vals = mock::genesis_n_vals(root, 4); let (resource_sig, _cap) = ol_account::ol_create_resource_account(alice, b"0x1"); - let donor_directed_address = signer::address_of(&resource_sig); + let donor_voice_address = signer::address_of(&resource_sig); // the account needs basic donor directed structs - donor_directed::make_donor_directed(&resource_sig, vals, 2); + donor_voice::make_donor_voice(&resource_sig, vals, 2); - let uid = donor_directed::propose_payment(bob, donor_directed_address, @0x1000b, 100, b"thanks bob"); - let (found, idx, status_enum, completed) = donor_directed::get_multisig_proposal_state(donor_directed_address, &uid); + let uid = donor_voice::propose_payment(bob, donor_voice_address, @0x1000b, 100, b"thanks bob"); + let (found, idx, status_enum, completed) = donor_voice::get_multisig_proposal_state(donor_voice_address, &uid); assert!(found, 7357004); assert!(idx == 0, 7357005); assert!(status_enum == 1, 7357006); assert!(!completed, 7357007); // it is not yet scheduled, it's still only a proposal by an admin - assert!(!donor_directed::is_scheduled(donor_directed_address, &uid), 7357008); + assert!(!donor_voice::is_scheduled(donor_voice_address, &uid), 7357008); } #[test(root = @ol_framework, alice = @0x1000a, bob = @0x1000b, carol = @0x1000c)] @@ -64,33 +64,33 @@ module ol_framework::test_donor_directed { let vals = mock::genesis_n_vals(root, 4); let (resource_sig, _cap) = ol_account::ol_create_resource_account(alice, b"0x1"); - let donor_directed_address = signer::address_of(&resource_sig); + let donor_voice_address = signer::address_of(&resource_sig); // the account needs basic donor directed structs - donor_directed::make_donor_directed(&resource_sig, vals, 2); + donor_voice::make_donor_voice(&resource_sig, vals, 2); - let uid = donor_directed::propose_payment(bob, donor_directed_address, @0x1000b, 100, b"thanks bob"); - let (found, idx, status_enum, completed) = donor_directed::get_multisig_proposal_state(donor_directed_address, &uid); + let uid = donor_voice::propose_payment(bob, donor_voice_address, @0x1000b, 100, b"thanks bob"); + let (found, idx, status_enum, completed) = donor_voice::get_multisig_proposal_state(donor_voice_address, &uid); assert!(found, 7357004); assert!(idx == 0, 7357005); assert!(status_enum == 1, 7357006); assert!(!completed, 7357007); // it is not yet scheduled, it's still only a proposal by an admin - assert!(!donor_directed::is_scheduled(donor_directed_address, &uid), 7357008); + assert!(!donor_voice::is_scheduled(donor_voice_address, &uid), 7357008); - let uid = donor_directed::propose_payment(carol, donor_directed_address, @0x1000b, 100, b"thanks bob"); - let (found, idx, status_enum, completed) = donor_directed::get_multisig_proposal_state(donor_directed_address, &uid); + let uid = donor_voice::propose_payment(carol, donor_voice_address, @0x1000b, 100, b"thanks bob"); + let (found, idx, status_enum, completed) = donor_voice::get_multisig_proposal_state(donor_voice_address, &uid); assert!(found, 7357004); assert!(idx == 0, 7357005); assert!(status_enum == 1, 7357006); assert!(completed, 7357007); // now completed // confirm it is scheduled - assert!(donor_directed::is_scheduled(donor_directed_address, &uid), 7357008); + assert!(donor_voice::is_scheduled(donor_voice_address, &uid), 7357008); // the default timed payment is 3 epochs, we are in epoch 1 - let list = donor_directed::find_by_deadline(donor_directed_address, 3); + let list = donor_voice::find_by_deadline(donor_voice_address, 3); assert!(vector::contains(&list, &uid), 7357009); } @@ -106,49 +106,49 @@ module ol_framework::test_donor_directed { mock::trigger_epoch(root); let (resource_sig, _cap) = ol_account::ol_create_resource_account(alice, b"0x1"); - let donor_directed_address = signer::address_of(&resource_sig); + let donor_voice_address = signer::address_of(&resource_sig); // the account needs basic donor directed structs - donor_directed::make_donor_directed(&resource_sig, vals, 2); + donor_voice::make_donor_voice(&resource_sig, vals, 2); // EVE Establishes some governance over the wallet, when donating. let eve_donation = 42; - ol_account::transfer(eve, donor_directed_address, eve_donation); - let (_, _, total_funds_sent_by_eve) = receipts::read_receipt(signer::address_of(eve), donor_directed_address); + ol_account::transfer(eve, donor_voice_address, eve_donation); + let (_, _, total_funds_sent_by_eve) = receipts::read_receipt(signer::address_of(eve), donor_voice_address); assert!(total_funds_sent_by_eve == eve_donation, 7357001); // last payment - let is_donor = donor_directed_governance::check_is_donor(donor_directed_address, signer::address_of(eve)); + let is_donor = donor_voice_governance::check_is_donor(donor_voice_address, signer::address_of(eve)); assert!(is_donor, 7357002); // Dave will also be a donor - ol_account::transfer(dave, donor_directed_address, 1); - let is_donor = donor_directed_governance::check_is_donor(donor_directed_address, signer::address_of(dave)); + ol_account::transfer(dave, donor_voice_address, 1); + let is_donor = donor_voice_governance::check_is_donor(donor_voice_address, signer::address_of(dave)); assert!(is_donor, 7357003); // Bob proposes a tx that will come from the donor directed account. // It is not yet scheduled because it doesnt have the MultiAuth quorum. Still waiting for Alice or Carol to approve. - let uid_of_transfer = donor_directed::propose_payment(bob, donor_directed_address, @0x1000b, 100, b"thanks bob"); + let uid_of_transfer = donor_voice::propose_payment(bob, donor_voice_address, @0x1000b, 100, b"thanks bob"); - let (_found, _idx, _status_enum, completed) = donor_directed::get_multisig_proposal_state(donor_directed_address, &uid_of_transfer); + let (_found, _idx, _status_enum, completed) = donor_voice::get_multisig_proposal_state(donor_voice_address, &uid_of_transfer); assert!(!completed, 7357004); // Eve wants to propose a Veto, but this should fail at this, because // the tx is not yet scheduled - let _uid_of_veto_prop = donor_directed::propose_veto(eve, &uid_of_transfer); - let has_veto = donor_directed_governance::tx_has_veto(donor_directed_address, guid::id_creation_num(&uid_of_transfer)); + let _uid_of_veto_prop = donor_voice::propose_veto(eve, &uid_of_transfer); + let has_veto = donor_voice_governance::tx_has_veto(donor_voice_address, guid::id_creation_num(&uid_of_transfer)); assert!(!has_veto, 7357005); // propose does not cast a vote. // Now Carol, along with Bob, as admins have proposed the payment. // Now the payment should be scheduled - let uid_of_transfer = donor_directed::propose_payment(carol, donor_directed_address, @0x1000b, 100, b"thanks bob"); - let (_found, _idx, state) = donor_directed::get_schedule_state(donor_directed_address, &uid_of_transfer); + let uid_of_transfer = donor_voice::propose_payment(carol, donor_voice_address, @0x1000b, 100, b"thanks bob"); + let (_found, _idx, state) = donor_voice::get_schedule_state(donor_voice_address, &uid_of_transfer); assert!(state == 1, 7357006); // is scheduled // Eve tries again after it has been scheduled - let _uid_of_veto_prop = donor_directed::propose_veto(eve, &uid_of_transfer); - let has_veto = donor_directed_governance::tx_has_veto(donor_directed_address, guid::id_creation_num(&uid_of_transfer)); + let _uid_of_veto_prop = donor_voice::propose_veto(eve, &uid_of_transfer); + let has_veto = donor_voice_governance::tx_has_veto(donor_voice_address, guid::id_creation_num(&uid_of_transfer)); assert!(has_veto, 7357007); // propose does not cast a vote. // now vote on the proposal @@ -157,22 +157,22 @@ module ol_framework::test_donor_directed { // proposing is not same as voting, now eve votes // NOTE: there is a tx function that can propose and vote in single step - donor_directed::vote_veto_tx(eve, donor_directed_address, id_num); + donor_voice::vote_veto_tx(eve, donor_voice_address, id_num); - let (approve_pct, req_threshold) = donor_directed_governance::get_veto_tally(donor_directed_address, guid::id_creation_num(&uid_of_transfer)); + let (approve_pct, req_threshold) = donor_voice_governance::get_veto_tally(donor_voice_address, guid::id_creation_num(&uid_of_transfer)); assert!(approve_pct == 10000, 7357008); assert!(req_threshold == 5100, 7357009); // since Eve is the majority donor, and has almost all the votes, the voting will end early. On the next epoch the vote should end mock::trigger_epoch(root); - donor_directed::vote_veto_tx(dave, donor_directed_address, id_num); + donor_voice::vote_veto_tx(dave, donor_voice_address, id_num); // it is not yet scheduled, it's still only a proposal by an admin - assert!(!donor_directed::is_scheduled(donor_directed_address, &uid_of_transfer), 7357010); + assert!(!donor_voice::is_scheduled(donor_voice_address, &uid_of_transfer), 7357010); // should not be scheduled - let (_found, _idx, state) = donor_directed::get_schedule_state(donor_directed_address, &uid_of_transfer); + let (_found, _idx, state) = donor_voice::get_schedule_state(donor_voice_address, &uid_of_transfer); assert!(state == 2, 7357006); // is veto } @@ -188,44 +188,44 @@ module ol_framework::test_donor_directed { assert!(bob_balance_pre == 10000000, 7357001); let (resource_sig, _cap) = ol_account::ol_create_resource_account(alice, b"0x1"); - let donor_directed_address = signer::address_of(&resource_sig); + let donor_voice_address = signer::address_of(&resource_sig); // fund the account - ol_account::transfer(alice, donor_directed_address, 100); - let (_, resource_balance) = ol_account::balance(donor_directed_address); + ol_account::transfer(alice, donor_voice_address, 100); + let (_, resource_balance) = ol_account::balance(donor_voice_address); assert!(resource_balance == 100, 7357002); // the account needs basic donor directed structs - donor_directed::make_donor_directed(&resource_sig, vals, 2); + donor_voice::make_donor_voice(&resource_sig, vals, 2); - let uid = donor_directed::propose_payment(bob, donor_directed_address, @0x1000b, 100, b"thanks bob"); - let (found, idx, status_enum, completed) = donor_directed::get_multisig_proposal_state(donor_directed_address, &uid); + let uid = donor_voice::propose_payment(bob, donor_voice_address, @0x1000b, 100, b"thanks bob"); + let (found, idx, status_enum, completed) = donor_voice::get_multisig_proposal_state(donor_voice_address, &uid); assert!(found, 7357004); assert!(idx == 0, 7357005); assert!(status_enum == 1, 7357006); assert!(!completed, 7357007); // it is not yet scheduled, it's still only a proposal by an admin - assert!(!donor_directed::is_scheduled(donor_directed_address, &uid), 7357008); + assert!(!donor_voice::is_scheduled(donor_voice_address, &uid), 7357008); - let uid = donor_directed::propose_payment(carol, donor_directed_address, @0x1000b, 100, b"thanks bob"); - let (found, idx, status_enum, completed) = donor_directed::get_multisig_proposal_state(donor_directed_address, &uid); + let uid = donor_voice::propose_payment(carol, donor_voice_address, @0x1000b, 100, b"thanks bob"); + let (found, idx, status_enum, completed) = donor_voice::get_multisig_proposal_state(donor_voice_address, &uid); assert!(found, 7357004); assert!(idx == 0, 7357005); assert!(status_enum == 1, 7357006); assert!(completed, 7357007); // now completed // confirm it is scheduled - assert!(donor_directed::is_scheduled(donor_directed_address, &uid), 7357008); + assert!(donor_voice::is_scheduled(donor_voice_address, &uid), 7357008); // PROCESS THE PAYMENT // the default timed payment is 3 epochs, we are in epoch 1 - let list = donor_directed::find_by_deadline(donor_directed_address, 3); + let list = donor_voice::find_by_deadline(donor_voice_address, 3); assert!(vector::contains(&list, &uid), 7357009); // process epoch 3 accounts - donor_directed::process_donor_directed_accounts(root, 3); + donor_voice::process_donor_voice_accounts(root, 3); let (_, bob_balance) = ol_account::balance(@0x1000b); assert!(bob_balance > bob_balance_pre, 7357005); @@ -246,44 +246,44 @@ module ol_framework::test_donor_directed { let (resource_sig, _cap) = ol_account::ol_create_resource_account(alice, b"0x1"); - let donor_directed_address = signer::address_of(&resource_sig); + let donor_voice_address = signer::address_of(&resource_sig); // fund the account - ol_account::transfer(alice, donor_directed_address, 100); - let (_, resource_balance) = ol_account::balance(donor_directed_address); + ol_account::transfer(alice, donor_voice_address, 100); + let (_, resource_balance) = ol_account::balance(donor_voice_address); assert!(resource_balance == 100, 7357002); // the account needs basic donor directed structs - donor_directed::make_donor_directed(&resource_sig, vals, 2); + donor_voice::make_donor_voice(&resource_sig, vals, 2); - let uid = donor_directed::propose_payment(bob, donor_directed_address, signer::address_of(marlon_rando), 100, b"thanks marlon"); - let (found, idx, status_enum, completed) = donor_directed::get_multisig_proposal_state(donor_directed_address, &uid); + let uid = donor_voice::propose_payment(bob, donor_voice_address, signer::address_of(marlon_rando), 100, b"thanks marlon"); + let (found, idx, status_enum, completed) = donor_voice::get_multisig_proposal_state(donor_voice_address, &uid); assert!(found, 7357004); assert!(idx == 0, 7357005); assert!(status_enum == 1, 7357006); assert!(!completed, 7357007); // it is not yet scheduled, it's still only a proposal by an admin - assert!(!donor_directed::is_scheduled(donor_directed_address, &uid), 7357008); + assert!(!donor_voice::is_scheduled(donor_voice_address, &uid), 7357008); - let uid = donor_directed::propose_payment(carol, donor_directed_address, signer::address_of(marlon_rando), 100, b"thanks marlon"); - let (found, idx, status_enum, completed) = donor_directed::get_multisig_proposal_state(donor_directed_address, &uid); + let uid = donor_voice::propose_payment(carol, donor_voice_address, signer::address_of(marlon_rando), 100, b"thanks marlon"); + let (found, idx, status_enum, completed) = donor_voice::get_multisig_proposal_state(donor_voice_address, &uid); assert!(found, 7357004); assert!(idx == 0, 7357005); assert!(status_enum == 1, 7357006); assert!(completed, 7357007); // now completed // confirm it is scheduled - assert!(donor_directed::is_scheduled(donor_directed_address, &uid), 7357008); + assert!(donor_voice::is_scheduled(donor_voice_address, &uid), 7357008); // PROCESS THE PAYMENT // the default timed payment is 3 epochs, we are in epoch 1 - let list = donor_directed::find_by_deadline(donor_directed_address, 3); + let list = donor_voice::find_by_deadline(donor_voice_address, 3); assert!(vector::contains(&list, &uid), 7357009); // process epoch 3 accounts - // donor_directed::process_donor_directed_accounts(root, 3); + // donor_voice::process_donor_voice_accounts(root, 3); mock::trigger_epoch(root); // into epoch 1 mock::trigger_epoch(root); // into epoch 2 mock::trigger_epoch(root); // into epoch 3, processes at the end of this epoch. @@ -311,42 +311,42 @@ module ol_framework::test_donor_directed { let (lifetime_burn_pre, _) = burn::get_lifetime_tracker(); let (resource_sig, _cap) = ol_account::ol_create_resource_account(alice, b"0x1"); - let donor_directed_address = signer::address_of(&resource_sig); + let donor_voice_address = signer::address_of(&resource_sig); // the account needs basic donor directed structs - donor_directed::make_donor_directed(&resource_sig, vals, 2); - // donor_directed::set_liquidate_to_match_index(&resource_sig, true); + donor_voice::make_donor_voice(&resource_sig, vals, 2); + // donor_voice::set_liquidate_to_match_index(&resource_sig, true); // EVE Establishes some governance over the wallet, when donating. let eve_donation = 42; - ol_account::transfer(eve, donor_directed_address, eve_donation); - let (_, _, total_funds_sent_by_eve) = receipts::read_receipt(signer::address_of(eve), donor_directed_address); + ol_account::transfer(eve, donor_voice_address, eve_donation); + let (_, _, total_funds_sent_by_eve) = receipts::read_receipt(signer::address_of(eve), donor_voice_address); assert!(total_funds_sent_by_eve == eve_donation, 7357001); - let is_donor = donor_directed_governance::check_is_donor(donor_directed_address, signer::address_of(eve)); + let is_donor = donor_voice_governance::check_is_donor(donor_voice_address, signer::address_of(eve)); assert!(is_donor, 7357002); // Dave will also be a donor, with half the amount of what Eve let dave_donation = 21; - ol_account::transfer(dave, donor_directed_address, dave_donation); - let is_donor = donor_directed_governance::check_is_donor(donor_directed_address, signer::address_of(dave)); + ol_account::transfer(dave, donor_voice_address, dave_donation); + let is_donor = donor_voice_governance::check_is_donor(donor_voice_address, signer::address_of(dave)); assert!(is_donor, 7357003); // Dave proposes to liquidate the account. - donor_directed::propose_liquidation(dave, donor_directed_address); + donor_voice::propose_liquidation(dave, donor_voice_address); - assert!(donor_directed_governance::is_liquidation_propsed(donor_directed_address), 7357004); + assert!(donor_voice_governance::is_liquidation_propsed(donor_voice_address), 7357004); // Dave proposed, now Dave and Eve need to vote - donor_directed::vote_liquidation_tx(eve, donor_directed_address); + donor_voice::vote_liquidation_tx(eve, donor_voice_address); mock::trigger_epoch(root); // needs a vote on the day after the threshold has passed - donor_directed::vote_liquidation_tx(dave, donor_directed_address); + donor_voice::vote_liquidation_tx(dave, donor_voice_address); - let list = donor_directed::get_liquidation_queue(); + let list = donor_voice::get_liquidation_queue(); assert!(vector::length(&list) > 0, 7357005); - let (addrs, refunds) = donor_directed::get_pro_rata(donor_directed_address); + let (addrs, refunds) = donor_voice::get_pro_rata(donor_voice_address); assert!(*vector::borrow(&addrs, 0) == @0x1000e, 7357006); assert!(*vector::borrow(&addrs, 1) == @0x1000d, 7357007); @@ -361,12 +361,12 @@ module ol_framework::test_donor_directed { assert!((*dave_donation_pro_rata + superman_3) == dave_donation, 7357009); - let (_, program_balance_pre) = ol_account::balance(donor_directed_address); + let (_, program_balance_pre) = ol_account::balance(donor_voice_address); let (_, eve_balance_pre) = ol_account::balance(@0x1000e); - donor_directed::test_helper_vm_liquidate(root); + donor_voice::test_helper_vm_liquidate(root); - let (_, program_balance) = ol_account::balance(donor_directed_address); + let (_, program_balance) = ol_account::balance(donor_voice_address); let (_, eve_balance) = ol_account::balance(@0x1000e); assert!(program_balance < program_balance_pre, 7357010); @@ -396,44 +396,44 @@ module ol_framework::test_donor_directed { let (lifetime_burn_pre, _) = burn::get_lifetime_tracker(); let (resource_sig, _cap) = ol_account::ol_create_resource_account(alice, b"0x1"); - let donor_directed_address = signer::address_of(&resource_sig); + let donor_voice_address = signer::address_of(&resource_sig); // the account needs basic donor directed structs - donor_directed::make_donor_directed(&resource_sig, vals, 2); - donor_directed::set_liquidate_to_match_index(&resource_sig, true); + donor_voice::make_donor_voice(&resource_sig, vals, 2); + donor_voice::set_liquidate_to_match_index(&resource_sig, true); // EVE Establishes some governance over the wallet, when donating. let eve_donation = 42; - ol_account::transfer(eve, donor_directed_address, eve_donation); - let (_, _, total_funds_sent_by_eve) = receipts::read_receipt(signer::address_of(eve), donor_directed_address); + ol_account::transfer(eve, donor_voice_address, eve_donation); + let (_, _, total_funds_sent_by_eve) = receipts::read_receipt(signer::address_of(eve), donor_voice_address); assert!(total_funds_sent_by_eve == eve_donation, 7357001); - let is_donor = donor_directed_governance::check_is_donor(donor_directed_address, signer::address_of(eve)); + let is_donor = donor_voice_governance::check_is_donor(donor_voice_address, signer::address_of(eve)); assert!(is_donor, 7357002); // Dave will also be a donor, with half the amount of what Eve sends let dave_donation = 21; - ol_account::transfer(dave, donor_directed_address, dave_donation); - let is_donor = donor_directed_governance::check_is_donor(donor_directed_address, signer::address_of(dave)); + ol_account::transfer(dave, donor_voice_address, dave_donation); + let is_donor = donor_voice_governance::check_is_donor(donor_voice_address, signer::address_of(dave)); assert!(is_donor, 7357003); // Dave proposes to liquidate the account. - donor_directed::propose_liquidation(dave, donor_directed_address); + donor_voice::propose_liquidation(dave, donor_voice_address); - assert!(donor_directed_governance::is_liquidation_propsed(donor_directed_address), 7357004); + assert!(donor_voice_governance::is_liquidation_propsed(donor_voice_address), 7357004); // Dave proposed, now Dave and Eve need to vote - donor_directed::vote_liquidation_tx(eve, donor_directed_address); + donor_voice::vote_liquidation_tx(eve, donor_voice_address); mock::trigger_epoch(root); // needs a vote on the day after the threshold has passed - donor_directed::vote_liquidation_tx(dave, donor_directed_address); + donor_voice::vote_liquidation_tx(dave, donor_voice_address); - let list = donor_directed::get_liquidation_queue(); + let list = donor_voice::get_liquidation_queue(); assert!(vector::length(&list) > 0, 7357005); // check the table of refunds // dave and eve should be receiving - let (addrs, refunds) = donor_directed::get_pro_rata(donor_directed_address); + let (addrs, refunds) = donor_voice::get_pro_rata(donor_voice_address); assert!(*vector::borrow(&addrs, 0) == @0x1000e, 7357006); assert!(*vector::borrow(&addrs, 1) == @0x1000d, 7357007); @@ -447,12 +447,12 @@ module ol_framework::test_donor_directed { let superman_3 = 1; // rounding from fixed_point32 assert!((*dave_donation_pro_rata + superman_3) == dave_donation, 7357009); - let (_, program_balance_pre) = ol_account::balance(donor_directed_address); + let (_, program_balance_pre) = ol_account::balance(donor_voice_address); let (_, eve_balance_pre) = ol_account::balance(@0x1000e); - donor_directed::test_helper_vm_liquidate(root); + donor_voice::test_helper_vm_liquidate(root); - let (_, program_balance) = ol_account::balance(donor_directed_address); + let (_, program_balance) = ol_account::balance(donor_voice_address); let (_, eve_balance) = ol_account::balance(@0x1000e); assert!(program_balance < program_balance_pre, 7357010); diff --git a/framework/libra-framework/sources/ol_sources/vote_lib/donor_directed.move b/framework/libra-framework/sources/ol_sources/vote_lib/donor_voice.move similarity index 86% rename from framework/libra-framework/sources/ol_sources/vote_lib/donor_directed.move rename to framework/libra-framework/sources/ol_sources/vote_lib/donor_voice.move index dccc38475..cae159bf7 100644 --- a/framework/libra-framework/sources/ol_sources/vote_lib/donor_directed.move +++ b/framework/libra-framework/sources/ol_sources/vote_lib/donor_voice.move @@ -1,9 +1,19 @@ -/// Donor directed wallets is a service of the chain. -/// Any address can voluntarily turn their account into a donor directed account. - -/// The DonorDirected payment workflow is: -/// Managers use a MultiSig to schedule -> +/// Donor Voice wallets is a service of the chain. +/// Any address can voluntarily turn their account into a Donor Voice account. + +/// Definitions +/// Unless otherwise specified the assumption of the Donor Voice app is +/// that there is an Owner of the account and property. +/// The Owner can assign Proxy Authorities, who acting as custodians can issue +/// transactions on behalf of Owner +/// Depositors are called Donors, and the app gives depositors +/// visibility of the transactions, and also limited authority over +/// specific actions: alterting the Owner and Depositors from +/// unauthorized transaction. + +/// The DonorVoice Account Lifecycle: +/// Proxy Authorities use a MultiSig to schedule -> /// Once scheduled the Donors use a TurnoutTally to Veto -> /// Epoch boundary: transaction executes when the VM reads the Schedule struct at the epoch boundary, and issues payment. @@ -21,11 +31,9 @@ /// 6. The donors can vote to liquidate a frozen TxSchedule account. The result will depend on the configuration of the TxSchedule account from when it was initialized: the funds by default return to the end user who was the donor. -/// 7. Third party contracts can wrap the Donor Directed wallet. The outcomes of the votes can be returned to a handler in a third party contract For example, liquidiation of a frozen account is programmable: a handler can be coded to determine the outcome of the donor directed wallet. See in CommunityWallets the funds return to the InfrastructureEscrow side-account of the user. - -module ol_framework::donor_directed { - // friend ol_framework::reconfiguration; +/// 7. Third party contracts can wrap the Donor Voice wallet. The outcomes of the votes can be returned to a handler in a third party contract For example, liquidiation of a frozen account is programmable: a handler can be coded to determine the outcome of the Donor Voice wallet. See in CommunityWallets the funds return to the InfrastructureEscrow side-account of the user. +module ol_framework::donor_voice { use diem_framework::system_addresses; use std::vector; use std::signer; @@ -38,15 +46,17 @@ module ol_framework::donor_directed { use ol_framework::receipts; use ol_framework::multi_action; use ol_framework::account::{Self, WithdrawCapability}; - use ol_framework::donor_directed_governance; + use ol_framework::donor_voice_governance; use ol_framework::ballot; use ol_framework::cumulative_deposits; use ol_framework::transaction_fee; use ol_framework::match_index; // use diem_std::debug::print; - /// Not initialized as a donor directed account. - const ENOT_INIT_DONOR_DIRECTED: u64 = 1; + friend ol_framework::community_wallet; + + /// Not initialized as a Donor Voice account. + const ENOT_INIT_DONOR_VOICE: u64 = 1; /// User is not a donor and cannot vote on this account const ENOT_AUTHORIZED_TO_VOTE: u64 = 2; /// Could not find a pending transaction by this GUID @@ -70,7 +80,7 @@ module ol_framework::donor_directed { const DEFAULT_VETO_DURATION: u64 = 7; - // root registry for the donor directed accounts + // root registry for the Donor Voice accounts struct Registry has key { list: vector
, liquidation_queue: vector
, @@ -85,7 +95,7 @@ module ol_framework::donor_directed { } /// This is the basic payment information. - /// This is used initially in a MultiSig, for the managers + /// This is used initially in a MultiSig, for the Authorities /// initially to schedule. struct Payment has copy, drop, store { payee: address, @@ -93,13 +103,14 @@ module ol_framework::donor_directed { description: vector, } - struct TimedTransfer has drop, store { // TODO: remove key, copy + struct TimedTransfer has drop, store { uid: guid::ID, // copy of ID generated by MultiSig for the transaction deadline: u64, // what epoch does the transaction execute tx: Payment, // The transaction properties epoch_latest_veto_received: u64, // This is to check if we need to extend the deadline } + // account's freeze policy which donor's have a "voice" in struct Freeze has key { is_frozen: bool, consecutive_rejections: u64, @@ -107,18 +118,18 @@ module ol_framework::donor_directed { liquidate_to_match_index: bool, } - struct Donors has key { - list: vector
, - } + // struct Donors has key { + // list: vector
, + // } - // A flag on the account that it wants to be considered a community walley - struct CommunityWallet has key { } + // // A flag on the account that it wants to be considered a community walley + // struct CommunityWallet has key { } - //////// INIT REGISRTY OF DONOR DIRECTED ACCOUNTS //////// + //////// INIT REGISRTY OF DONOR VOICE ACCOUNTS //////// - // Donor Directed Accounts are a root security service. So the root account needs to keep a registry of all donor directed accounts, using this service. + // Donor Voice Accounts are a root security service. So the root account needs to keep a registry of all Donor Voice accounts, using this service. // Utility used at genesis (and on upgrade) to initialize the system state. public fun initialize(vm: &signer) { @@ -147,23 +158,29 @@ module ol_framework::donor_directed { }; } - //////// DONOR DIRECTED INITIALIZATION //////// + // can only be called by genesis + public(friend) fun migrate_community_wallet_account(vm: &signer, dv_account: + &signer) acquires Registry { + system_addresses::assert_ol(vm); + let liquidate_to_match_index = true; + // skip setting up the multisig + structs_init(dv_account, liquidate_to_match_index); + add_to_registry(dv_account); + } + + //////// DONOR VOICE INITIALIZATION //////// // There are three steps in initializing an account. These steps can be combined in a single transaction, or done in separate transactions. The "bricking" of the sponsor key should be done in a separate transaction, in case there are any errors in the initialization. - // 1. The basic structs for a donor directed account need to be initialized, and the account needs to be added to the Registry at root. + // 1. The basic structs for a Donor Voice account need to be initialized, and the account needs to be added to the Registry at root. // 2. A MultiSig action structs need to be initialized. // 3. Once the MultiSig is initialized, the account needs to be bricked, before the MultiSig can be used. - public fun make_donor_directed(sponsor: &signer, init_signers: vector
, cfg_n_signers: u64) acquires Registry { - // let init_signers = vector::singleton(signer_one); - // vector::push_back(&mut init_signers, signer_two); - // vector::push_back(&mut init_signers, signer_three); - + public fun make_donor_voice(sponsor: &signer, init_signers: vector
, cfg_n_signers: u64) acquires Registry { cumulative_deposits::init_cumulative_deposits(sponsor); - // we are setting liquidation to infra escrow as false by default + // we are setting liquidation to match_index as false by default // the user can send another transacton to change this. let liquidate_to_match_index = false; structs_init(sponsor, liquidate_to_match_index); @@ -192,7 +209,7 @@ module ol_framework::donor_directed { guid_capability, }); - donor_directed_governance::init_donor_governance(sig); + donor_voice_governance::init_donor_governance(sig); } // add to root registry @@ -218,8 +235,8 @@ module ol_framework::donor_directed { } - /// Check if the account is a donor directed account, and initialized properly. - public fun is_donor_directed(multisig_address: address):bool { + /// Check if the account is a Donor Voice account, and initialized properly. + public fun is_donor_voice(multisig_address: address):bool { multi_action::is_multi_action(multisig_address) && multi_action::has_action(multisig_address) && exists(multisig_address) && @@ -239,7 +256,7 @@ module ol_framework::donor_directed { ///////// MULTISIG ACTIONS TO SCHEDULE A TIMED TRANSFER ///////// /// As in any MultiSig instance, the transaction which proposes the action (the scheduled transfer) must be signed by an authority on the MultiSig. /// The same function is the handler for the approval case of the MultiSig action. - /// Since Donor Directed accounts are involved with sensitive assets, we have moved the WithdrawCapability to the MultiSig instance. Even though we don't need it for any account functions for paying, we use it to ensure no private functions related to assets can be called. Belt and suspenders. + /// Since Donor Voice accounts are involved with sensitive assets, we have moved the WithdrawCapability to the MultiSig instance. Even though we don't need it for any account functions for paying, we use it to ensure no private functions related to assets can be called. Belt and suspenders. /// Returns the GUID of the transfer. public fun propose_payment( @@ -326,7 +343,7 @@ module ol_framework::donor_directed { /// needing to intervene. /// Returns (accounts_processed, amount_processed, success) // TODO: add to the return the tuple of sender/recipient that failed - public fun process_donor_directed_accounts( + public fun process_donor_voice_accounts( vm: &signer, epoch: u64, ): (u64, u64, bool) acquires Registry, TxSchedule, Freeze { @@ -413,7 +430,7 @@ module ol_framework::donor_directed { //////// GOVERNANCE HANDLERS //////// - // Governance logic is defined in donor_directed_governance.move + // Governance logic is defined in donor_voice_governance.move // Below are functions to handle the cases for rejecting and freezing accounts based on governance outcomes. //////// VETO //////// @@ -429,9 +446,9 @@ module ol_framework::donor_directed { tx_uid: &guid::ID, ) acquires TxSchedule, Freeze { let multisig_address = guid::id_creator_address(tx_uid); - donor_directed_governance::assert_authorized(sender, multisig_address); + donor_voice_governance::assert_authorized(sender, multisig_address); - let veto_is_approved = donor_directed_governance::veto_by_id(sender, veto_uid); + let veto_is_approved = donor_voice_governance::veto_by_id(sender, veto_uid); if (option::is_none(&veto_is_approved)) return; let (_found, _idx, state) = get_schedule_state(multisig_address, tx_uid); @@ -455,7 +472,7 @@ module ol_framework::donor_directed { // is the same as the end of the veto ballot // This is because the ballot expiration can be // extended based on the threshold of votes. - donor_directed_governance::sync_ballot_and_tx_expiration(sender, veto_uid, tx_mut.deadline) + donor_voice_governance::sync_ballot_and_tx_expiration(sender, veto_uid, tx_mut.deadline) } } @@ -494,7 +511,7 @@ module ol_framework::donor_directed { /// The transaction must first have been scheduled, otherwise this proposal will abort. public fun propose_veto(donor: &signer, uid_of_tx: &guid::ID): Option acquires TxSchedule { let multisig_address = guid::id_creator_address(uid_of_tx); - donor_directed_governance::assert_authorized(donor, multisig_address); + donor_voice_governance::assert_authorized(donor, multisig_address); let state = borrow_global(multisig_address); // need to check if the tx is already schdules. @@ -502,7 +519,7 @@ module ol_framework::donor_directed { if (found && status == SCHEDULED) { let epochs_duration = DEFAULT_VETO_DURATION; - let uid = donor_directed_governance::propose_veto(&state.guid_capability, uid_of_tx, epochs_duration); + let uid = donor_voice_governance::propose_veto(&state.guid_capability, uid_of_tx, epochs_duration); return option::some(uid) }; option::none() @@ -555,16 +572,16 @@ module ol_framework::donor_directed { //////// LIQUIDATION //////// /// propose and vote on the liquidation of this wallet public fun propose_liquidation(donor: &signer, multisig_address: address) acquires TxSchedule { - donor_directed_governance::assert_authorized(donor, multisig_address); + donor_voice_governance::assert_authorized(donor, multisig_address); let state = borrow_global(multisig_address); let epochs_duration = 365; // liquidation vote can take a whole year - donor_directed_governance::propose_liquidate(&state.guid_capability, epochs_duration); + donor_voice_governance::propose_liquidate(&state.guid_capability, epochs_duration); } /// Once a liquidation has been proposed, other donors can vote on it. fun liquidation_handler(donor: &signer, multisig_address: address) acquires Freeze, Registry { - donor_directed_governance::assert_authorized(donor, multisig_address); - let res = donor_directed_governance::vote_liquidation(donor, multisig_address); + donor_voice_governance::assert_authorized(donor, multisig_address); + let res = donor_voice_governance::vote_liquidation(donor, multisig_address); if (option::is_some(&res) && *option::borrow(&res)) { // The VM will call this function to liquidate the wallet. @@ -586,7 +603,7 @@ module ol_framework::donor_directed { *&f.liquidation_queue } - /// The VM will call this function to liquidate all donor directed + /// The VM will call this function to liquidate all Donor Voice /// wallets in the queue. public(friend) fun vm_liquidate(vm: &signer) acquires Freeze, Registry { system_addresses::assert_ol(vm); @@ -726,7 +743,7 @@ module ol_framework::donor_directed { //////// TRANSACTION SCRIPTS //////// - // public fun init_donor_directed(sponsor: &signer, init_signers: vector
, cfg_n_signers: u64) acquires Registry { + // public fun init_donor_voice(sponsor: &signer, init_signers: vector
, cfg_n_signers: u64) acquires Registry { // // let init_signers = vector::singleton(signer_one); // // vector::push_back(&mut init_signers, signer_two); // // vector::push_back(&mut init_signers, signer_three); @@ -736,7 +753,7 @@ module ol_framework::donor_directed { // // we are setting liquidation to infra escrow as false by default // // the user can send another transacton to change this. // let liquidate_to_match_index = false; - // set_donor_directed(sponsor, liquidate_to_match_index); + // set_donor_voice(sponsor, liquidate_to_match_index); // make_multi_action(sponsor, cfg_n_signers, init_signers); // add_to_registry(sponsor); // } @@ -755,12 +772,12 @@ module ol_framework::donor_directed { // assert!(multi_action::has_action(multisig_address), error::invalid_state(EMULTISIG_NOT_INIT)); - // assert!(exists(multisig_address), error::invalid_state(ENOT_INIT_DONOR_DIRECTED)); + // assert!(exists(multisig_address), error::invalid_state(ENOT_INIT_DONOR_VOICE)); - // assert!(exists(multisig_address), error::invalid_state(ENOT_INIT_DONOR_DIRECTED)); + // assert!(exists(multisig_address), error::invalid_state(ENOT_INIT_DONOR_VOICE)); // // multi_action::finalize_and_brick(sponsor); - // assert!(is_donor_directed(multisig_address), error::invalid_state(ENOT_INIT_DONOR_DIRECTED)); + // assert!(is_donor_voice(multisig_address), error::invalid_state(ENOT_INIT_DONOR_VOICE)); // // only add to registry if INIT is successful. // add_to_registry(sponsor); @@ -770,9 +787,9 @@ module ol_framework::donor_directed { //////// TX HELPER //////// - // transaction helper to wrap donor directed init - public entry fun make_donor_directed_tx(sponsor: &signer, init_signers: vector
, cfg_n_signers: u64) acquires Registry { - make_donor_directed(sponsor, init_signers, cfg_n_signers); + // transaction helper to wrap Donor Voice init + public entry fun make_donor_voice_tx(sponsor: &signer, init_signers: vector
, cfg_n_signers: u64) acquires Registry { + make_donor_voice(sponsor, init_signers, cfg_n_signers); } public entry fun propose_payment_tx( @@ -798,7 +815,7 @@ module ol_framework::donor_directed { /// Entry functiont to vote the veto. public entry fun vote_veto_tx(donor: &signer, multisig_address: address, id: u64) acquires TxSchedule, Freeze { let tx_uid = guid::create_id(multisig_address, id); - let (found, veto_uid) = donor_directed_governance::find_tx_veto_id(tx_uid); + let (found, veto_uid) = donor_voice_governance::find_tx_veto_id(tx_uid); assert!(found, error::invalid_argument(ENO_VETO_ID_FOUND)); veto_handler(donor, &veto_uid, &tx_uid); } @@ -810,6 +827,4 @@ module ol_framework::donor_directed { public entry fun vote_liquidation_tx(donor: &signer, multisig_address: address) acquires Freeze, Registry { liquidation_handler(donor, multisig_address); } - - } \ No newline at end of file diff --git a/framework/libra-framework/sources/ol_sources/vote_lib/donor_directed_governance.move b/framework/libra-framework/sources/ol_sources/vote_lib/donor_voice_governance.move similarity index 76% rename from framework/libra-framework/sources/ol_sources/vote_lib/donor_directed_governance.move rename to framework/libra-framework/sources/ol_sources/vote_lib/donor_voice_governance.move index dd6f8b3b6..66267f1ca 100644 --- a/framework/libra-framework/sources/ol_sources/vote_lib/donor_directed_governance.move +++ b/framework/libra-framework/sources/ol_sources/vote_lib/donor_voice_governance.move @@ -1,16 +1,16 @@ - /// DonorDirected wallet governance. See documentation at DonorDirected.move + /// Donor Voice account governance. See documentation at Donor Voice.move - /// For each DonorDirected account there are Donors. + /// For each Donor Voice account there are Donors. /// We establish who is a Donor through the Receipts module. - /// The DonorDirected account also has a tracker for the Cumulative amount of funds that have been sent to this account. + /// The Donor Voice account also has a tracker for the Cumulative amount of funds that have been sent to this account. /// We will use the lifetime cumulative amounts sent as the total amount of votes that can be cast (voter enrollment). /// The voting on a veto of a transaction or an outright liquidation of the account is done by the Donors. /// The voting mechanism is a TurnoutTally. Such votes ajust the threshold for passing a vote based on the actual turnout. I.e. The fewer people that vote, the higher the threshold to reach consensus. But a vote is not scuttled if the turnout is low. See more details in the TurnoutTally.move module. -module ol_framework::donor_directed_governance { - friend ol_framework::donor_directed; +module ol_framework::donor_voice_governance { + friend ol_framework::donor_voice; use std::error; use std::signer; @@ -50,46 +50,46 @@ module ol_framework::donor_directed_governance { - public fun init_donor_governance(directed_account: &signer) { + public fun init_donor_governance(dv_account: &signer) { // let t = turnout_tally::new_tally_struct(); let veto = Governance> { tracker: ballot::new_tracker() }; - move_to(directed_account, veto); + move_to(dv_account, veto); let liquidate = Governance> { tracker: ballot::new_tracker() }; - move_to(directed_account, liquidate); + move_to(dv_account, liquidate); } - /// For a DonorDirected account get the total number of votes enrolled from reading the Cumulative tracker. - fun get_enrollment(directed_account: address): u64 { - cumulative_deposits::get_cumulative_deposits(directed_account) + /// For a Donor Voice account get the total number of votes enrolled from reading the Cumulative tracker. + fun get_enrollment(dv_account: address): u64 { + cumulative_deposits::get_cumulative_deposits(dv_account) } - /// public function to check that a user account is a Donor for a DonorDirected account. + /// public function to check that a user account is a Donor for a Donor Voice account. - public fun check_is_donor(directed_account: address, user: address): bool { - get_user_donations(directed_account, user) > 0 + public fun check_is_donor(dv_account: address, user: address): bool { + get_user_donations(dv_account, user) > 0 } - public fun assert_authorized(sig: &signer, directed_account: address) { + public fun assert_authorized(sig: &signer, dv_account: address) { let user = signer::address_of(sig); - assert!(check_is_donor(directed_account, user), error::permission_denied(ENOT_A_DONOR)); + assert!(check_is_donor(dv_account, user), error::permission_denied(ENOT_A_DONOR)); } - public fun is_authorized(user: address, directed_account: address):bool { - check_is_donor(directed_account, user) + public fun is_authorized(user: address, dv_account: address):bool { + check_is_donor(dv_account, user) } - /// For an individual donor, get the amount of votes that they can cast, based on their cumulative donations to the DonorDirected account. + /// For an individual donor, get the amount of votes that they can cast, based on their cumulative donations to the Donor Voice account. - fun get_user_donations(directed_account: address, user: address): u64 { - let (_, _, cumulative_donations) = receipts::read_receipt(user, directed_account); + fun get_user_donations(dv_account: address, user: address): u64 { + let (_, _, cumulative_donations) = receipts::read_receipt(user, dv_account); cumulative_donations } @@ -107,7 +107,7 @@ module ol_framework::donor_directed_governance { turnout_tally::vote(user, ballot, uid, veto_tx, user_votes) } - /// Liquidation tally only. The handler for liquidation exists in DonorDirected, where a tx script will call it. + /// Liquidation tally only. The handler for liquidation exists in Donor Voice, where a tx script will call it. public(friend) fun vote_liquidation(donor: &signer, multisig_address: address): Option acquires Governance{ assert_authorized(donor, multisig_address); let state = borrow_global_mut>>(multisig_address); @@ -133,26 +133,26 @@ module ol_framework::donor_directed_governance { /// Public script transaction to propose a veto, or vote on it if it already exists. - /// should only be called by the DonorDirected.move so that the handlers can be called on "pass" conditions. + /// should only be called by the Donor Voice.move so that the handlers can be called on "pass" conditions. public(friend) fun veto_by_id(user: &signer, proposal_guid: &guid::ID): Option acquires Governance { - let directed_account = guid::id_creator_address(proposal_guid); - assert_authorized(user, directed_account); + let dv_account = guid::id_creator_address(proposal_guid); + assert_authorized(user, dv_account); - let state = borrow_global_mut>>(directed_account); + let state = borrow_global_mut>>(dv_account); let ballot = ballot::get_ballot_by_id_mut(&mut state.tracker, proposal_guid); let tally_state = ballot::get_type_struct_mut(ballot); - vote_veto(user, tally_state, proposal_guid, directed_account) + vote_veto(user, tally_state, proposal_guid, dv_account) } public(friend) fun sync_ballot_and_tx_expiration(user: &signer, proposal_guid: &guid::ID, epoch_deadline: u64) acquires Governance { - let directed_account = guid::id_creator_address(proposal_guid); - assert_authorized(user, directed_account); + let dv_account = guid::id_creator_address(proposal_guid); + assert_authorized(user, dv_account); - let state = borrow_global_mut>>(directed_account); + let state = borrow_global_mut>>(dv_account); let ballot = ballot::get_ballot_by_id_mut(&mut state.tracker, proposal_guid); let tally_state = ballot::get_type_struct_mut(ballot); @@ -161,7 +161,7 @@ module ol_framework::donor_directed_governance { } - /// only DonorDirected can call this. The veto and liquidate handlers need + /// only Donor Voice can call this. The veto and liquidate handlers need /// to be located there. So users should not call functions here. public(friend) fun propose_veto( cap: &account::GUIDCapability, @@ -183,13 +183,13 @@ module ol_framework::donor_directed_governance { /// a private function to propose a ballot for a veto. This is called by a verified donor. fun propose_gov(cap: &account::GUIDCapability, proposal: GovAction, epochs_duration: u64): guid::ID acquires Governance { - let directed_account = account::get_guid_capability_address(cap); - let gov_state = borrow_global_mut>>(directed_account); + let dv_account = account::get_guid_capability_address(cap); + let gov_state = borrow_global_mut>>(dv_account); assert!(is_unique_proposal(&gov_state.tracker, &proposal), error::invalid_argument(EDUPLICATE_PROPOSAL)); // what's the maximum universe of valid votes. - let max_votes_enrollment = get_enrollment(directed_account); + let max_votes_enrollment = get_enrollment(dv_account); // enforce a minimum deadline. Liquidation deadlines are one year, Veto should be minimum 7. if (epochs_duration < 7) { @@ -235,9 +235,9 @@ module ol_framework::donor_directed_governance { // with a known transaction uid, scan all the pending vetos to see if there is a veto for that transaction, and what the index is. // NOTE: what is being returned is a different ID, that of the proposal to veto public fun find_tx_veto_id(tx_id: guid::ID): (bool, guid::ID) acquires Governance { - // let proposal_guid = guid::create_id(directed_account, id); - let directed_account = guid::id_creator_address(&tx_id); - let state = borrow_global_mut>>(directed_account); + // let proposal_guid = guid::create_id(dv_account, id); + let dv_account = guid::id_creator_address(&tx_id); + let state = borrow_global_mut>>(dv_account); let pending = ballot::get_list_ballots_by_enum(&state.tracker, ballot::get_pending_enum()); let i = 0; @@ -257,19 +257,19 @@ module ol_framework::donor_directed_governance { //////// GETTERS //////// #[view] // for a transaction UID return if the address and proposal ID have any vetos. guid::ID is destructured for view functions - public fun tx_has_veto(directed_account: address, id: u64): bool acquires Governance { - let uid = guid::create_id(directed_account, id); + public fun tx_has_veto(dv_account: address, id: u64): bool acquires Governance { + let uid = guid::create_id(dv_account, id); let (found, _) = find_tx_veto_id(uid); found } #[view] // returns a tuple of the (percent approval, threshold required) - public fun get_veto_tally(directed_account: address, id: u64): (u64, u64) acquires Governance{ - let (found, prop_id) = find_tx_veto_id(guid::create_id(directed_account, id)); + public fun get_veto_tally(dv_account: address, id: u64): (u64, u64) acquires Governance{ + let (found, prop_id) = find_tx_veto_id(guid::create_id(dv_account, id)); assert!(found, error::invalid_argument(ENO_BALLOT_FOUND)); - let state = borrow_global_mut>>(directed_account); + let state = borrow_global_mut>>(dv_account); let ballot = ballot::get_ballot_by_id(&state.tracker, &prop_id); let tally = ballot::get_type_struct(ballot); @@ -279,8 +279,8 @@ module ol_framework::donor_directed_governance { } #[view] - public fun is_liquidation_propsed(directed_account: address): bool acquires Governance { - let state = borrow_global_mut>>(directed_account); + public fun is_liquidation_propsed(dv_account: address): bool acquires Governance { + let state = borrow_global_mut>>(dv_account); let list_pending = ballot::get_list_ballots_by_enum(&state.tracker, ballot::get_pending_enum()); vector::length(list_pending) > 0 diff --git a/framework/releases/head.mrb b/framework/releases/head.mrb index e6ad04257..c4ca58528 100644 Binary files a/framework/releases/head.mrb and b/framework/releases/head.mrb differ diff --git a/tools/genesis/Makefile b/tools/genesis/Makefile index 5c228ce26..3ba1f0ee9 100644 --- a/tools/genesis/Makefile +++ b/tools/genesis/Makefile @@ -9,8 +9,8 @@ FUTURE_USES = 0.70 endif ifndef RECOVERY_FILE -RECOVERY_FILE = v5_recovery -# RECOVERY_FILE = sample_export_recovery +# RECOVERY_FILE = v5_recovery +RECOVERY_FILE = sample_export_recovery endif @@ -32,7 +32,8 @@ endif genesis: stdlib - cargo r -- -c ${CHAIN} \ + cargo r -- \ + -c ${CHAIN} \ genesis --org-github ${GIT_ORG} \ --name-github ${GIT_REPO} \ --local-framework \ @@ -76,11 +77,11 @@ ALICE_IP = 134.209.32.159 endif ifndef BOB_IP -BOB_IP = 174.138.92.116 +BOB_IP = 165.22.44.147 endif ifndef CAROL_IP -CAROL_IP = 174.138.92.121 +CAROL_IP = 165.22.34.98 endif test-genesis: diff --git a/tools/genesis/src/genesis.rs b/tools/genesis/src/genesis.rs index e6d91380e..1ead79578 100644 --- a/tools/genesis/src/genesis.rs +++ b/tools/genesis/src/genesis.rs @@ -88,14 +88,20 @@ fn test_recovery_genesis() { let recovery = parse_json::recovery_file_parse(p).unwrap(); - let test_validators = TestValidator::new_test_set(Some(4), Some(100_000_000)); + let test_validators = TestValidator::new_test_set(Some(4), Some(100_000)); let validators: Vec = test_validators.iter().map(|t| t.data.clone()).collect(); + + let supply = SupplySettings { + target_supply: 10_000.0, // because we overflow the u64 + ..Default::default() + }; + let tx = make_recovery_genesis_from_vec_legacy_recovery( Some(&recovery), &validators, &head_release_bundle(), ChainId::test(), - None, + Some(supply), &libra_genesis_default(NamedChain::TESTING), ) .unwrap(); diff --git a/tools/genesis/src/genesis_functions.rs b/tools/genesis/src/genesis_functions.rs index 7146f045c..084ce031d 100644 --- a/tools/genesis/src/genesis_functions.rs +++ b/tools/genesis/src/genesis_functions.rs @@ -1,5 +1,8 @@ //! ol functions to run at genesis e.g. migration. -use crate::supply::{Supply, SupplySettings}; +use crate::{ + process_comm_wallet, + supply::{Supply, SupplySettings}, +}; use anyhow::Context; use diem_types::account_config::CORE_CODE_ADDRESS; use diem_vm::move_vm_ext::SessionExt; @@ -22,7 +25,7 @@ pub fn genesis_migrate_all_users( .progress_with_style(OLProgress::bar()) .for_each(|a| { // do basic account creation and coin scaling - match genesis_migrate_one_user(session, a, supply.split_factor, supply.escrow_pct) { + match genesis_migrate_one_user(session, a, supply.split_factor) { Ok(_) => {} Err(e) => { // TODO: compile a list of errors. @@ -34,6 +37,7 @@ pub fn genesis_migrate_all_users( // migrating slow wallets if a.slow_wallet.is_some() { + // TODO: this should not happen on a community wallet match genesis_migrate_slow_wallet(session, a, supply.split_factor) { Ok(_) => {} Err(e) => { @@ -99,7 +103,6 @@ pub fn genesis_migrate_one_user( session: &mut SessionExt, user_recovery: &LegacyRecovery, split_factor: f64, - _escrow_pct: f64, ) -> anyhow::Result<()> { if user_recovery.account.is_none() || user_recovery.auth_key.is_none() @@ -380,6 +383,72 @@ pub fn genesis_migrate_ancestry( Ok(()) } +/// migrate the registry of Donor Voice Accounts +/// Also mark them Community Wallets if they have chosen that designation. + +pub fn genesis_migrate_community_wallet( + session: &mut SessionExt, + user_recovery: &[LegacyRecovery], +) -> anyhow::Result<()> { + if let Some(root) = user_recovery.iter().find(|e| e.role == AccountRole::System) { + let cw_list = &root + .comm_wallet + .as_ref() + .context("no comm_wallet struct")? + .list; + + cw_list.iter().for_each(|el| { + let acc_str = el.to_string(); + + let new_address = AccountAddress::from_hex_literal(&format!("0x{}", acc_str)) + .expect("could not parse address"); + + let serialized_values = serialize_values(&vec![ + MoveValue::Signer(CORE_CODE_ADDRESS), + MoveValue::Signer(new_address), + ]); + + exec_function( + session, + "community_wallet", + "migrate_community_wallet_account", + vec![], + serialized_values, + ); + }); + } + + Ok(()) +} + +/// migrate the Cumulative Deposits Structs (for the Match Index weights). +pub fn genesis_migrate_cumu_deposits( + session: &mut SessionExt, + user_recovery: &[LegacyRecovery], + split_factor: f64, +) -> anyhow::Result<()> { + let (_dr, cw) = process_comm_wallet::prepare_cw_and_receipts(user_recovery, split_factor)?; + + cw.list.iter().for_each(|(addr, wallet)| { + let serialized_values = serialize_values(&vec![ + MoveValue::Signer(CORE_CODE_ADDRESS), + MoveValue::Signer(addr.to_owned()), + MoveValue::U64(wallet.cumulative_value), + MoveValue::U64(wallet.cumulative_index), + MoveValue::vector_address(wallet.depositors.clone()), + ]); + + exec_function( + session, + "cumulative_deposits", + "genesis_migrate_cumulative_deposits", + vec![], + serialized_values, + ); + }); + + Ok(()) +} /// Since we are minting for each account to convert account balances there may be a rounding difference from target. Add those micro cents into the transaction fee account. /// Note: we could have minted one giant coin and then split it, however there's no place to store in on chain without repurposing accounts (ie. system accounts by design do no hold any funds, only the transaction_fee contract can temporarily hold an aggregatable coin which by design can only be fully withdrawn (not split)). So the rounding mint is less elegant, but practical. pub fn rounding_mint(session: &mut SessionExt, supply_settings: &SupplySettings) { @@ -414,12 +483,6 @@ pub fn set_final_supply(session: &mut SessionExt, supply_settings: &SupplySettin ); } -// pub fn mint_genesis_bootstrap_coin(session: &mut SessionExt, validators: &[Validator]) { -// validators.iter().for_each(|v| { -// let serialized_values = serialize_values(&vec![ -// MoveValue::Signer(AccountAddress::ZERO), // must be called by 0x0 -// MoveValue::Address(v.owner_address), -// ]); pub fn set_validator_baseline_reward(session: &mut SessionExt, nominal_reward: u64) { let serialized_values = serialize_values(&vec![ MoveValue::Signer(AccountAddress::ZERO), // must be called by 0x0 diff --git a/tools/genesis/src/lib.rs b/tools/genesis/src/lib.rs index 7dd8c09ab..49274d65f 100644 --- a/tools/genesis/src/lib.rs +++ b/tools/genesis/src/lib.rs @@ -8,6 +8,7 @@ pub mod genesis_reader; pub mod genesis_registration; pub mod github_extensions; pub mod parse_json; +pub mod process_comm_wallet; pub mod supply; pub mod testnet_setup; pub mod vm; diff --git a/tools/genesis/src/process_comm_wallet.rs b/tools/genesis/src/process_comm_wallet.rs new file mode 100644 index 000000000..4e3b435f0 --- /dev/null +++ b/tools/genesis/src/process_comm_wallet.rs @@ -0,0 +1,298 @@ +use std::collections::BTreeMap; + +use diem_types::account_address::AccountAddress; +use libra_types::legacy_types::legacy_recovery::LegacyRecovery; +use serde::Serialize; + +pub struct AllCommWallets { + pub list: BTreeMap, + pub total_deposits: u64, +} +#[derive(Debug, Serialize)] +pub struct WalletState { + pub cumulative_value: u64, + pub cumulative_index: u64, + pub depositors: Vec, + pub audit_deposits_with_receipts: u64, +} + +#[derive(Debug)] +pub struct DonorReceipts { + pub list: BTreeMap, + pub total_cumu: u64, + pub audit_not_cw: Vec, +} + +#[derive(Debug)] +pub struct ReceiptsResourceV7 { + pub destination: Vec, + pub cumulative: Vec, + pub last_payment_timestamp: Vec, + pub last_payment_value: Vec, + pub audit_not_found: Vec, +} + +/// do the entire workflow of processing community wallet accounts +/// and inserting the donor information based on receipts +pub fn prepare_cw_and_receipts( + recovery: &[LegacyRecovery], + split_factor: f64, +) -> anyhow::Result<(DonorReceipts, AllCommWallets)> { + let mut dr = rebuild_donor_receipts(recovery, split_factor)?; + let mut cw = rebuild_cw_cumu_deposits(recovery, split_factor)?; + update_cw_with_donor(&mut cw, &mut dr, split_factor); + + Ok((dr, cw)) +} + +/// process donor receipts +pub fn rebuild_donor_receipts( + recovery: &[LegacyRecovery], + split_factor: f64, +) -> anyhow::Result { + let total_cumu = 0; + let mut list = BTreeMap::new(); + + recovery + .iter() + .filter(|e| e.receipts.is_some()) + .for_each(|e| { + // NOTE this is not mutable because we don't want to change + // the underlying LegacyRecovery. So it will be intentionally + // less efficient + let temp_receipts = e.receipts.as_ref().expect("no receipts field"); + let destinations_cast: Vec = temp_receipts + .destination + .iter() + .map(|&a| a.try_into().expect("could not cast LegacyAdresss")) + .collect(); + // this resource should now show the split numbers + let mut cast_receipts = ReceiptsResourceV7 { + destination: destinations_cast, + cumulative: temp_receipts.clone().cumulative, + last_payment_timestamp: temp_receipts.clone().last_payment_timestamp, + last_payment_value: temp_receipts.clone().last_payment_value, + audit_not_found: vec![], + }; + + // iterate through the list of payments and split + // then with the new split value reduce/fold into the total + // user payments. + // let user_cumu = + cast_receipts.cumulative.iter_mut().for_each(|this_cumu| { + // mutate it + *this_cumu = (split_factor * (*this_cumu as f64)) as u64; + // return to next step in iter + // this_cumu + }); + // .fold(0u64, |sum, next| { + // sum.checked_add(*next).expect("overflow summing cumu payments after split applied") + // }); + + // // add to totals for comparison purposes + // total_cumu += user_cumu; + + // same for the last_payment. Just no need to fold + cast_receipts.last_payment_value.iter_mut().for_each(|el| { + *el = (split_factor * (*el as f64)) as u64; + }); + + let user: AccountAddress = e + .account + .expect("no legacy_account") + .try_into() + .expect("could not cast LegacyAddress"); + + list.insert(user, cast_receipts); + }); + + Ok(DonorReceipts { + list, + total_cumu, + audit_not_cw: vec![], + }) +} + +pub fn rebuild_cw_cumu_deposits( + recovery: &[LegacyRecovery], + split_factor: f64, +) -> anyhow::Result { + let mut total_cumu = 0; + let mut list = BTreeMap::new(); + + recovery + .iter() + .filter(|e| e.cumulative_deposits.is_some()) + .for_each(|e| { + let cd = e.cumulative_deposits.as_ref().expect("no receipts field"); + let split_value = split_factor * (cd.value as f64); + total_cumu += split_value as u64; + + let split_index = split_factor * (cd.index as f64); + + let cast_receipts = WalletState { + cumulative_value: split_value as u64, + cumulative_index: split_index as u64, + depositors: vec![], + audit_deposits_with_receipts: 0, + }; + + let user: AccountAddress = e + .account + .expect("could not get account addr") + .try_into() + .expect("could not cast LegacyAddress"); + + list.insert(user, cast_receipts); + }); + + Ok(AllCommWallets { + list, + total_deposits: total_cumu, + }) +} + +/// extract donor addresses from receipts and place into new +/// communit wallet struct +pub fn update_cw_with_donor( + cw: &mut AllCommWallets, + donors: &mut DonorReceipts, + split_factor: f64, +) { + donors.list.iter_mut().for_each(|(donor, receipt)| { + receipt.audit_not_found = receipt + .destination + .iter() + .enumerate() + .filter_map(|(i, &maybe_cw)| { + if let Some(w) = cw.list.get_mut(&maybe_cw) { + // get the cumulative value from the cumu Vec. + + let value = receipt.cumulative.get(i).expect("cant parse value"); + let split_value = split_factor * (*value as f64); + w.audit_deposits_with_receipts += split_value as u64; + + // populate the list of depositors to that CW + if !w.depositors.contains(donor) { + w.depositors.push(*donor) + } + } else { + // does this community wallet exist + // say we can't find it in cw list + if !donors.audit_not_cw.contains(&maybe_cw) { + donors.audit_not_cw.push(maybe_cw) + } + + return Some(maybe_cw); + } + None + }) + .collect(); + }); +} + +#[test] +fn test_cw_recovery() { + use crate::parse_json; + + let p = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("tests/fixtures/sample_export_recovery.json"); + + let recovery = parse_json::recovery_file_parse(p).unwrap(); + + // first, test with no split + let split_factor = 1.0; + + let t = rebuild_cw_cumu_deposits(&recovery, split_factor).unwrap(); + + assert!(t.total_deposits == 1208569282086623, "cumu not equal"); + + assert!(t.list.len() == 134, "len not equal"); +} + +#[test] +fn test_receipt_recovery() { + use crate::parse_json; + + let p = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("tests/fixtures/sample_export_recovery.json"); + + let recovery = parse_json::recovery_file_parse(p.clone()).unwrap(); + + // first, test with no split + let split_factor = 1.0; + + let t = rebuild_donor_receipts(&recovery, split_factor).unwrap(); + let test_addr = "00000000000000000000000000000000123c6ca26a6ed35ad00868b33b4a98d1" + .parse::() + .unwrap(); + + dbg!(&t.list.get(&test_addr)); + + if let Some(t) = t.list.get(&test_addr) { + assert!(t.cumulative[0] == 6555272577, "cumu does not match"); + } + + // Do it again with a split factor + let recovery = parse_json::recovery_file_parse(p).unwrap(); + let split_factor = 2.0; + + let t = rebuild_donor_receipts(&recovery, split_factor).unwrap(); + let test_addr = "00000000000000000000000000000000123c6ca26a6ed35ad00868b33b4a98d1" + .parse::() + .unwrap(); + + if let Some(t) = t.list.get(&test_addr) { + assert!( + t.cumulative[0] == (split_factor * 6555272577.0) as u64, + "cumu does not match" + ); + } +} + +#[test] +fn test_update_cw_from_receipts() { + use crate::parse_json; + let p = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("tests/fixtures/sample_export_recovery.json"); + let recovery = parse_json::recovery_file_parse(p.clone()).unwrap(); + + // first, test with no split + let split_factor = 1.0; + + let (_dr, cw) = prepare_cw_and_receipts(&recovery, split_factor).unwrap(); + + let v = cw + .list + .get(&AccountAddress::from_hex_literal("0x7209c13e1253ad8fb2d96a30552052aa").unwrap()) + .unwrap(); + + let original_value = 162900862; + assert!(v.cumulative_value == original_value, "cumu value not equal"); + assert!( + v.audit_deposits_with_receipts == 116726512, + "receipts value not equal" + ); + + let recovery = parse_json::recovery_file_parse(p).unwrap(); + + // now add the split + let split_factor = 2.0; + + let (_dr, cw) = prepare_cw_and_receipts(&recovery, split_factor).unwrap(); + + let v = cw + .list + .get(&AccountAddress::from_hex_literal("0x7209c13e1253ad8fb2d96a30552052aa").unwrap()) + .unwrap(); + + assert!( + v.cumulative_value == (original_value as f64 * split_factor) as u64, + "cumu value not equal" + ); + + // assert!( + // v.audit_deposits_with_receipts == 116726512, + // "receipts value not equal" + // ); +} diff --git a/tools/genesis/src/vm.rs b/tools/genesis/src/vm.rs index 3c457f9ed..f84a16306 100644 --- a/tools/genesis/src/vm.rs +++ b/tools/genesis/src/vm.rs @@ -26,7 +26,10 @@ use diem_vm_genesis::{ use libra_types::{legacy_types::legacy_recovery::LegacyRecovery, ol_progress::OLProgress}; use crate::{ - genesis_functions::{rounding_mint, set_final_supply, set_validator_baseline_reward}, + genesis_functions::{ + genesis_migrate_community_wallet, genesis_migrate_cumu_deposits, rounding_mint, + set_final_supply, set_validator_baseline_reward, + }, supply::{populate_supply_stats_from_legacy, SupplySettings}, }; @@ -150,6 +153,14 @@ pub fn encode_genesis_change_set( // need to set the baseline reward based on supply settings set_validator_baseline_reward(&mut session, supply.epoch_reward_base_case as u64); + + // migrate community wallets + genesis_migrate_community_wallet(&mut session, r) + .expect("could not migrate community wallets"); + // cumulative deposits (for match index) also need separate + // migration for CW + genesis_migrate_cumu_deposits(&mut session, r, supply.split_factor) + .expect("could not migrate cumu deposits of cw"); } } OLProgress::complete("user migration complete"); diff --git a/tools/genesis/tests/e2e.rs b/tools/genesis/tests/e2e.rs index ab14aeae8..f74fc53a6 100644 --- a/tools/genesis/tests/e2e.rs +++ b/tools/genesis/tests/e2e.rs @@ -36,6 +36,7 @@ fn end_to_end_single() { let validators: Vec = test_validators.iter().map(|t| t.data.clone()).collect(); let supply_settings = SupplySettings { + // target_supply: 10_000_000.0, target_future_uses: 0.70, map_dd_to_slow: vec![ // FTW @@ -87,7 +88,9 @@ fn end_to_end_single() { #[test] fn end_to_end_all() { - let blob = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/genesis.blob"); + let temp_dir = TempPath::new(); + temp_dir.create_as_dir().unwrap(); + let blob = temp_dir.path().join("temp_genesis.blob"); let p = PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("tests/fixtures/sample_export_recovery.json"); @@ -126,7 +129,7 @@ fn end_to_end_all() { save_genesis(&tx, &blob).unwrap(); assert!(blob.exists(), "genesis.blob does not exist"); - let gen_bytes = fs::read(blob).unwrap(); + let gen_bytes = fs::read(&blob).unwrap(); match bcs::from_bytes(&gen_bytes).unwrap() { Transaction::GenesisTransaction(WriteSetPayload::Direct(recovery_changeset)) => { @@ -146,6 +149,4 @@ fn end_to_end_all() { } _ => panic!("not a genesis transaction"), } - - // drop.maybe_cleanup(); } diff --git a/tools/genesis/tests/fixtures/genesis.blob b/tools/genesis/tests/fixtures/genesis.blob index 24e9815df..57a3cf29b 100644 Binary files a/tools/genesis/tests/fixtures/genesis.blob and b/tools/genesis/tests/fixtures/genesis.blob differ diff --git a/tools/genesis/tests/json_to_genesis_audit_all.rs b/tools/genesis/tests/json_to_genesis_audit_all.rs index 93cda97ae..83943305c 100644 --- a/tools/genesis/tests/json_to_genesis_audit_all.rs +++ b/tools/genesis/tests/json_to_genesis_audit_all.rs @@ -32,6 +32,7 @@ fn test_correct_supply_arithmetic_all() { .set_ratios_from_settings(&supply_settings) .unwrap(); + dbg!(&supply_stats); let gen_tx = make_recovery_genesis_from_vec_legacy_recovery( Some(&user_accounts), &genesis_vals, diff --git a/types/src/legacy_types/legacy_address.rs b/types/src/legacy_types/legacy_address.rs index bf6884e01..62a25cfe9 100644 --- a/types/src/legacy_types/legacy_address.rs +++ b/types/src/legacy_types/legacy_address.rs @@ -6,6 +6,7 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 +use diem_types::account_address::AccountAddress; // NOTE: this is the new type we want to cast into use hex::FromHex; use rand::{rngs::OsRng, Rng}; use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer}; @@ -251,6 +252,17 @@ impl Serialize for LegacyAddress { } } +impl TryFrom for AccountAddress { + type Error = anyhow::Error; // Note: two types from legacy and next + + /// Tries to convert legacy address by using string representation hack + fn try_from(legacy: LegacyAddress) -> Result { + let acc_str = legacy.to_hex_literal(); + let new_addr_type = AccountAddress::from_hex_literal(&acc_str)?; + Ok(new_addr_type) + } +} + #[derive(Clone, Copy, Debug)] pub struct AccountAddressParseError; @@ -366,7 +378,7 @@ mod tests { let hex = "ca843279e3427144cead5e4d5999a3d0"; let json_hex = "\"ca843279e3427144cead5e4d5999a3d0\""; - let address = LegacyAddress::from_hex(hex).unwrap(); + let address: LegacyAddress = LegacyAddress::from_hex(hex).unwrap(); let json = serde_json::to_string(&address).unwrap(); let json_address: LegacyAddress = serde_json::from_str(json_hex).unwrap(); @@ -380,4 +392,16 @@ mod tests { assert!(LegacyAddress::try_from("".to_string()).is_err()); assert!(LegacyAddress::from_str("").is_err()); } + + //////// 0L //////// + #[test] + fn cast_between_legacy() { + use diem_types::account_address::AccountAddress; + let hex = "ca843279e3427144cead5e4d5999a3d0"; + let address: LegacyAddress = LegacyAddress::from_hex(hex).unwrap(); + let old_str = address.to_hex_literal(); + let parsed = AccountAddress::from_hex_literal(&old_str).unwrap(); + let p: AccountAddress = address.try_into().unwrap(); + assert!(parsed == p, "not equal"); + } } diff --git a/types/src/legacy_types/receipts.rs b/types/src/legacy_types/receipts.rs index cfb093e31..b83c72de8 100644 --- a/types/src/legacy_types/receipts.rs +++ b/types/src/legacy_types/receipts.rs @@ -1,8 +1,7 @@ //! fullnode counter for system address -use anyhow::Result; -// use move_core_types::account_address::LegacyAddress; use super::legacy_address::LegacyAddress; +use anyhow::Result; use move_core_types::{ident_str, identifier::IdentStr, move_resource::MoveStructType}; use serde::{Deserialize, Serialize}; diff --git a/types/src/move_resource/ancestry.rs b/types/src/move_resource/ancestry.rs index 1ad6a5d38..5349bfcf9 100644 --- a/types/src/move_resource/ancestry.rs +++ b/types/src/move_resource/ancestry.rs @@ -9,12 +9,6 @@ use move_core_types::{ move_resource::{MoveResource, MoveStructType}, }; use serde::{Deserialize, Serialize}; -// use diem_types::access_path::AccessPath; -// use move_core_types::language_storage::StructTag; -// use move_core_types::account_address::AccountAddress; -// use move_core_types::language_storage::CORE_CODE_ADDRESS; - -// use super::legacy_address::LegacyAddress; /// Struct that represents a AutoPay resource #[derive(Debug, Serialize, Deserialize)] @@ -30,25 +24,6 @@ impl MoveStructType for AncestryResource { impl MoveResource for AncestryResource {} impl AncestryResource { - // // /// - // pub fn struct_tag() -> StructTag { - // StructTag { - // address: CORE_CODE_ADDRESS, - // module: AncestryResource::module_identifier(), - // name: AncestryResource::struct_identifier(), - // type_params: vec![], - // } - // } - // // /// - // pub fn access_path(account: AccountAddress) -> AccessPath { - // AccessPath::resource_access_path(account, AncestryResource::struct_tag()).unwrap() - // } - // // /// - // // pub fn resource_path() -> Vec { - - // // AccessPath::resource_access_path(AncestryResource::struct_tag()) - // // } - /// pub fn try_from_bytes(bytes: &[u8]) -> Result { bcs::from_bytes(bytes).map_err(Into::into)