async fn assert_unclaimed_neurons_can_be_forwarded(
    nns_canisters: &NnsCanisters<'_>,
    custodian_neuron_id: NeuronId,
    custodian_key_pair: &Keypair,
) {
    let gtc = &nns_canisters.genesis_token;
    let governance = &nns_canisters.governance;
    let ledger = &nns_canisters.ledger;

    let sign_cmd = move |msg: &[u8]| Ok(TEST_IDENTITY_1.sign(msg));

    let sender = Sender::ExternalHsm {
        pub_key: der_encode(&TEST_IDENTITY_1.public_key()),
        sign: Arc::new(sign_cmd),
    };

    // Assert that `TEST_IDENTITY_4` has not yet claimed or donated their neurons
    let get_account_response: Result<Result<AccountState, String>, String> = gtc
        .update_from_sender(
            "get_account",
            candid_one,
            TEST_IDENTITY_4.gtc_address.to_string(),
            &sender,
        )
        .await;
    let account_before_forward = get_account_response.unwrap().unwrap();
    assert!(!account_before_forward.has_claimed);
    assert!(!account_before_forward.has_donated);
    assert!(!account_before_forward.has_forwarded);

    // Calculate how much ICPT is expected to be forwarded to the custodian
    // neuron.
    let expected_custodian_account_balance_increase: Tokens = Tokens::from_e8s(
        Tokens::from_tokens(account_before_forward.icpts as u64)
            .unwrap()
            .get_e8s()
            - (TRANSACTION_FEE.get_e8s() * account_before_forward.neuron_ids.len() as u64),
    );

    // Get the custodian neuron and its ledger account, so that we can later
    // assert that the account value has increased (as the result of
    // forwarding).
    let get_full_neuron_response: Result<Result<Neuron, GovernanceError>, String> = governance
        .update_from_sender(
            "get_full_neuron",
            candid_one,
            custodian_neuron_id.id,
            &Sender::from_keypair(custodian_key_pair),
        )
        .await;

    let custodian_neuron = get_full_neuron_response.unwrap().unwrap();
    let custodian_subaccount = Subaccount::try_from(&custodian_neuron.account[..]).unwrap();
    let custodian_account =
        AccountIdentifier::new(GOVERNANCE_CANISTER_ID.get(), Some(custodian_subaccount));

    let account_balance_response: Result<Tokens, String> = ledger
        .query_from_sender(
            "account_balance_pb",
            protobuf,
            AccountBalanceArgs {
                account: custodian_account,
            },
            &Sender::from_keypair(custodian_key_pair),
        )
        .await;

    let custodian_account_balance = account_balance_response.unwrap();

    let expected_custodian_account_balance_after_forward =
        (custodian_account_balance + expected_custodian_account_balance_increase).unwrap();

    // Have `TEST_IDENTITY_1` forward `TEST_IDENTITY_2`'s and `TEST_IDENTITY_4`'s
    // neurons
    let forward_whitelisted_unclaimed_accounts_response: Result<Result<(), String>, String> = gtc
        .update_from_sender(
            "forward_whitelisted_unclaimed_accounts",
            candid_one,
            (),
            &sender,
        )
        .await;
    assert!(forward_whitelisted_unclaimed_accounts_response
        .unwrap()
        .is_ok());

    // Assert that the forward updated the account state as expected
    let get_account_response: Result<Result<AccountState, String>, String> = gtc
        .update_from_sender(
            "get_account",
            candid_one,
            TEST_IDENTITY_4.gtc_address.to_string(),
            &sender,
        )
        .await;
    let account_after_forward = get_account_response.unwrap().unwrap();
    assert!(!account_after_forward.has_claimed);
    assert!(!account_after_forward.has_donated);
    assert!(account_after_forward.has_forwarded);
    assert_eq!(account_after_forward.authenticated_principal_id, None);
    assert_eq!(
        account_after_forward.successfully_transferred_neurons.len(),
        account_before_forward.neuron_ids.len(),
    );

    // But has not forwarded not whitelisted accounts.

    // Assert that the custodian neuron's ledger account has received the
    // forwarded funds
    let account_balance_response: Result<Tokens, String> = ledger
        .query_from_sender(
            "account_balance_pb",
            protobuf,
            AccountBalanceArgs {
                account: custodian_account,
            },
            &Sender::from_keypair(custodian_key_pair),
        )
        .await;

    let actual_custodian_account_balance_after_forward = account_balance_response.unwrap();

    assert_eq!(
        expected_custodian_account_balance_after_forward,
        actual_custodian_account_balance_after_forward
    );

    // Assert that the custodian neuron's stake matches its ledger account
    // balance
    let get_full_neuron_response: Result<Result<Neuron, GovernanceError>, String> = governance
        .update_from_sender(
            "get_full_neuron",
            candid_one,
            custodian_neuron_id.id,
            &Sender::from_keypair(custodian_key_pair),
        )
        .await;

    let custodian_neuron = get_full_neuron_response.unwrap().unwrap();
    let custodian_neuron_stake = Tokens::from_e8s(custodian_neuron.cached_neuron_stake_e8s);

    assert_eq!(
        custodian_neuron_stake,
        actual_custodian_account_balance_after_forward
    );
}
/// Assert that any user can forward an unclaimed GTC account.
///
/// This assumes the window after Genesis, during which the forwarding of
/// unclaimed accounts is forbidden, has expired.
Assert that any user can forward an unclaimed GTC account.
This assumes the window after Genesis, during which the forwarding of
unclaimed accounts is forbidden, has expired.
Assert that any user can forward an unclaimed GTC account . This assumes the window after Genesis during which the forwarding of unclaimed accounts is forbidden has expired .
async fn assert_unclaimed_neurons_can_be_forwarded(
    nns_canisters: &NnsCanisters<'_>,
    custodian_neuron_id: NeuronId,
    custodian_key_pair: &Keypair,
) {
    let gtc = &nns_canisters.genesis_token;
    let governance = &nns_canisters.governance;
    let ledger = &nns_canisters.ledger;
    let sign_cmd = move |msg: &[u8]| Ok(TEST_IDENTITY_1.sign(msg));
    let sender = Sender::ExternalHsm {
        pub_key: der_encode(&TEST_IDENTITY_1.public_key()),
        sign: Arc::new(sign_cmd),
    };
    // Assert that `TEST_IDENTITY_4` has not yet claimed or donated their neurons
    let get_account_response: Result<Result<AccountState, String>, String> = gtc
        .update_from_sender(
            "get_account",
            candid_one,
            TEST_IDENTITY_4.gtc_address.to_string(),
            &sender,
        )
        .await;
    let account_before_forward = get_account_response.unwrap().unwrap();
    assert!(!account_before_forward.has_claimed);
    assert!(!account_before_forward.has_donated);
    assert!(!account_before_forward.has_forwarded);
    // Calculate how much ICPT is expected to be forwarded to the custodian
    // neuron.
    let expected_custodian_account_balance_increase: Tokens = Tokens::from_e8s(
        Tokens::from_tokens(account_before_forward.icpts as u64)
            .unwrap()
            .get_e8s()
            - (TRANSACTION_FEE.get_e8s() * account_before_forward.neuron_ids.len() as u64),
    );
    // Get the custodian neuron and its ledger account, so that we can later
    // assert that the account value has increased (as the result of
    // forwarding).
    let get_full_neuron_response: Result<Result<Neuron, GovernanceError>, String> = governance
        .update_from_sender(
            "get_full_neuron",
            candid_one,
            custodian_neuron_id.id,
            &Sender::from_keypair(custodian_key_pair),
        )
        .await;
    let custodian_neuron = get_full_neuron_response.unwrap().unwrap();
    let custodian_subaccount = Subaccount::try_from(&custodian_neuron.account[..]).unwrap();
    let custodian_account =
        AccountIdentifier::new(GOVERNANCE_CANISTER_ID.get(), Some(custodian_subaccount));
    let account_balance_response: Result<Tokens, String> = ledger
        .query_from_sender(
            "account_balance_pb",
            protobuf,
            AccountBalanceArgs {
                account: custodian_account,
            },
            &Sender::from_keypair(custodian_key_pair),
        )
        .await;
    let custodian_account_balance = account_balance_response.unwrap();
    let expected_custodian_account_balance_after_forward =
        (custodian_account_balance + expected_custodian_account_balance_increase).unwrap();
    // Have `TEST_IDENTITY_1` forward `TEST_IDENTITY_2`'s and `TEST_IDENTITY_4`'s
    // neurons
    let forward_whitelisted_unclaimed_accounts_response: Result<Result<(), String>, String> = gtc
        .update_from_sender(
            "forward_whitelisted_unclaimed_accounts",
            candid_one,
            (),
            &sender,
        )
        .await;
    assert!(forward_whitelisted_unclaimed_accounts_response
        .unwrap()
        .is_ok());
    // Assert that the forward updated the account state as expected
    let get_account_response: Result<Result<AccountState, String>, String> = gtc
        .update_from_sender(
            "get_account",
            candid_one,
            TEST_IDENTITY_4.gtc_address.to_string(),
            &sender,
        )
        .await;
    let account_after_forward = get_account_response.unwrap().unwrap();
    assert!(!account_after_forward.has_claimed);
    assert!(!account_after_forward.has_donated);
    assert!(account_after_forward.has_forwarded);
    assert_eq!(account_after_forward.authenticated_principal_id, None);
    assert_eq!(
        account_after_forward.successfully_transferred_neurons.len(),
        account_before_forward.neuron_ids.len(),
    );
    // But has not forwarded not whitelisted accounts.
    // Assert that the custodian neuron's ledger account has received the
    // forwarded funds
    let account_balance_response: Result<Tokens, String> = ledger
        .query_from_sender(
            "account_balance_pb",
            protobuf,
            AccountBalanceArgs {
                account: custodian_account,
            },
            &Sender::from_keypair(custodian_key_pair),
        )
        .await;
    let actual_custodian_account_balance_after_forward = account_balance_response.unwrap();
    assert_eq!(
        expected_custodian_account_balance_after_forward,
        actual_custodian_account_balance_after_forward
    );
    // Assert that the custodian neuron's stake matches its ledger account
    // balance
    let get_full_neuron_response: Result<Result<Neuron, GovernanceError>, String> = governance
        .update_from_sender(
            "get_full_neuron",
            candid_one,
            custodian_neuron_id.id,
            &Sender::from_keypair(custodian_key_pair),
        )
        .await;
    let custodian_neuron = get_full_neuron_response.unwrap().unwrap();
    let custodian_neuron_stake = Tokens::from_e8s(custodian_neuron.cached_neuron_stake_e8s);
    assert_eq!(
        custodian_neuron_stake,
        actual_custodian_account_balance_after_forward
    );
}
async fn assert_unclaimed_neurons_can_be_forwarded ( nns_canisters : & NnsCanisters < ' _ > , custodian_neuron_id : NeuronId , custodian_key_pair : & Keypair , ) { let gtc = & nns_canisters . genesis_token ; let governance = & nns_canisters . governance ; let ledger = & nns_canisters . ledger ; let sign_cmd = move | msg : & [ u8 ] | Ok ( TEST_IDENTITY_1 . sign ( msg ) ) ; let sender = Sender :: ExternalHsm { pub_key : der_encode ( & TEST_IDENTITY_1 . public_key ( ) ) , sign : Arc :: new ( sign_cmd ) , } ; // Assert that `TEST_IDENTITY_4` has not yet claimed or donated their neurons let get_account_response : Result < Result < AccountState , String > , String > = gtc . update_from_sender ( " " , candid_one , TEST_IDENTITY_4 . gtc_address . to_string ( ) , & sender , ) . await ; let account_before_forward = get_account_response . unwrap ( ) . unwrap ( ) ; assert ! ( account_before_forward has_claimed ) ; assert ! ( account_before_forward has_donated ) ; assert ! ( account_before_forward has_forwarded ) ; // Calculate how much ICPT is expected to be forwarded to the custodian // neuron. let expected_custodian_account_balance_increase : Tokens = Tokens :: from_e8s ( Tokens :: from_tokens ( account_before_forward . icpts as u64 ) . unwrap ( ) . get_e8s ( ) - ( TRANSACTION_FEE . get_e8s ( ) * account_before_forward . neuron_ids . len ( ) as u64 ) , ) ; // Get the custodian neuron and its ledger account, so that we can later // assert that the account value has increased (as the result of // forwarding). let get_full_neuron_response : Result < Result < Neuron , GovernanceError > , String > = governance . update_from_sender ( " " , candid_one , custodian_neuron_id . id , & Sender :: from_keypair ( custodian_key_pair ) , ) . await ; let custodian_neuron = get_full_neuron_response . unwrap ( ) . unwrap ( ) ; let custodian_subaccount = Subaccount :: try_from ( & custodian_neuron . account [ .. ] ) . unwrap ( ) ; let custodian_account = AccountIdentifier :: new ( GOVERNANCE_CANISTER_ID . get ( ) , Some ( custodian_subaccount ) ) ; let account_balance_response : Result < Tokens , String > = ledger . query_from_sender ( " " , protobuf , AccountBalanceArgs { account : custodian_account , } , & Sender :: from_keypair ( custodian_key_pair ) , ) . await ; let custodian_account_balance = account_balance_response . unwrap ( ) ; let expected_custodian_account_balance_after_forward = ( custodian_account_balance + expected_custodian_account_balance_increase ) . unwrap ( ) ; // Have `TEST_IDENTITY_1` forward `TEST_IDENTITY_2`'s and `TEST_IDENTITY_4`'s // neurons let forward_whitelisted_unclaimed_accounts_response : Result < Result < ( ) , String > , String > = gtc . update_from_sender ( " " , candid_one , ( ) , & sender , ) . await ; assert ! ( forward_whitelisted_unclaimed_accounts_response unwrap ( ) is_ok ( ) ) ; // Assert that the forward updated the account state as expected let get_account_response : Result < Result < AccountState , String > , String > = gtc . update_from_sender ( " " , candid_one , TEST_IDENTITY_4 . gtc_address . to_string ( ) , & sender , ) . await ; let account_after_forward = get_account_response . unwrap ( ) . unwrap ( ) ; assert ! ( account_after_forward has_claimed ) ; assert ! ( account_after_forward has_donated ) ; assert ! ( account_after_forward has_forwarded ) ; assert_eq ! ( account_after_forward authenticated_principal_id None ) ; assert_eq ! ( account_after_forward successfully_transferred_neurons len ( ) account_before_forward neuron_ids len ( ) ) ; // But has not forwarded not whitelisted accounts. // Assert that the custodian neuron's ledger account has received the // forwarded funds let account_balance_response : Result < Tokens , String > = ledger . query_from_sender ( " " , protobuf , AccountBalanceArgs { account : custodian_account , } , & Sender :: from_keypair ( custodian_key_pair ) , ) . await ; let actual_custodian_account_balance_after_forward = account_balance_response . unwrap ( ) ; assert_eq ! ( expected_custodian_account_balance_after_forward actual_custodian_account_balance_after_forward ) ; // Assert that the custodian neuron's stake matches its ledger account // balance let get_full_neuron_response : Result < Result < Neuron , GovernanceError > , String > = governance . update_from_sender ( " " , candid_one , custodian_neuron_id . id , & Sender :: from_keypair ( custodian_key_pair ) , ) . await ; let custodian_neuron = get_full_neuron_response . unwrap ( ) . unwrap ( ) ; let custodian_neuron_stake = Tokens :: from_e8s ( custodian_neuron . cached_neuron_stake_e8s ) ; assert_eq ! ( custodian_neuron_stake actual_custodian_account_balance_after_forward ) ; }
Assert that any user can forward an unclaimed GTC account.
Assert that any user can forward an unclaimed GTC account .
nns_canisters
&NnsCanisters<'_>
custodian_neuron_id
NeuronId
custodian_key_pair
&Keypair
nns_canisters
&NnsCanisters<'_>
custodian_neuron_id
NeuronId
custodian_key_pair
&Keypair