From 1c61db915ade4ee7d9cb8fe71f8f055d23f78bfd Mon Sep 17 00:00:00 2001 From: Aaron Date: Wed, 30 Oct 2024 16:10:40 -0600 Subject: [PATCH] [aptos_account] add transfer FA functions (#15116) * [aptos_account] add transfer FA functions * reorder input arguments to ensure metadata comes first --------- Co-authored-by: Greg Nazario --- .../aptos-framework/doc/aptos_account.md | 148 ++++++++++++++++++ .../sources/aptos_account.move | 37 ++++- .../sources/aptos_account.spec.move | 12 ++ 3 files changed, 196 insertions(+), 1 deletion(-) diff --git a/aptos-move/framework/aptos-framework/doc/aptos_account.md b/aptos-move/framework/aptos-framework/doc/aptos_account.md index 5ae53dbe92683..4777da7049787 100644 --- a/aptos-move/framework/aptos-framework/doc/aptos_account.md +++ b/aptos-move/framework/aptos-framework/doc/aptos_account.md @@ -15,6 +15,9 @@ - [Function `batch_transfer_coins`](#0x1_aptos_account_batch_transfer_coins) - [Function `transfer_coins`](#0x1_aptos_account_transfer_coins) - [Function `deposit_coins`](#0x1_aptos_account_deposit_coins) +- [Function `batch_transfer_fungible_assets`](#0x1_aptos_account_batch_transfer_fungible_assets) +- [Function `transfer_fungible_assets`](#0x1_aptos_account_transfer_fungible_assets) +- [Function `deposit_fungible_assets`](#0x1_aptos_account_deposit_fungible_assets) - [Function `assert_account_exists`](#0x1_aptos_account_assert_account_exists) - [Function `assert_account_is_registered_for_apt`](#0x1_aptos_account_assert_account_is_registered_for_apt) - [Function `set_allow_direct_coin_transfers`](#0x1_aptos_account_set_allow_direct_coin_transfers) @@ -34,6 +37,9 @@ - [Function `batch_transfer_coins`](#@Specification_1_batch_transfer_coins) - [Function `transfer_coins`](#@Specification_1_transfer_coins) - [Function `deposit_coins`](#@Specification_1_deposit_coins) + - [Function `batch_transfer_fungible_assets`](#@Specification_1_batch_transfer_fungible_assets) + - [Function `transfer_fungible_assets`](#@Specification_1_transfer_fungible_assets) + - [Function `deposit_fungible_assets`](#@Specification_1_deposit_fungible_assets) - [Function `assert_account_exists`](#@Specification_1_assert_account_exists) - [Function `assert_account_is_registered_for_apt`](#@Specification_1_assert_account_is_registered_for_apt) - [Function `set_allow_direct_coin_transfers`](#@Specification_1_set_allow_direct_coin_transfers) @@ -411,6 +417,100 @@ This would create the recipient account first and register it to receive the Coi + + + + +## Function `batch_transfer_fungible_assets` + +Batch version of transfer_fungible_assets. + + +
public entry fun batch_transfer_fungible_assets(from: &signer, metadata: object::Object<fungible_asset::Metadata>, recipients: vector<address>, amounts: vector<u64>)
+
+ + + +
+Implementation + + +
public entry fun batch_transfer_fungible_assets(
+    from: &signer,
+    metadata: Object<Metadata>,
+    recipients: vector<address>,
+    amounts: vector<u64>
+) {
+    let recipients_len = vector::length(&recipients);
+    assert!(
+        recipients_len == vector::length(&amounts),
+        error::invalid_argument(EMISMATCHING_RECIPIENTS_AND_AMOUNTS_LENGTH),
+    );
+
+    vector::enumerate_ref(&recipients, |i, to| {
+        let amount = *vector::borrow(&amounts, i);
+        transfer_fungible_assets(from, metadata, *to, amount);
+    });
+}
+
+ + + +
+ + + +## Function `transfer_fungible_assets` + +Convenient function to deposit fungible asset into a recipient account that might not exist. +This would create the recipient account first to receive the fungible assets. + + +
public entry fun transfer_fungible_assets(from: &signer, metadata: object::Object<fungible_asset::Metadata>, to: address, amount: u64)
+
+ + + +
+Implementation + + +
public entry fun transfer_fungible_assets(from: &signer, metadata: Object<Metadata>, to: address, amount: u64) {
+    deposit_fungible_assets(to, primary_fungible_store::withdraw(from, metadata, amount));
+}
+
+ + + +
+ + + +## Function `deposit_fungible_assets` + +Convenient function to deposit fungible asset into a recipient account that might not exist. +This would create the recipient account first to receive the fungible assets. + + +
public fun deposit_fungible_assets(to: address, fa: fungible_asset::FungibleAsset)
+
+ + + +
+Implementation + + +
public fun deposit_fungible_assets(to: address, fa: FungibleAsset) {
+    if (!account::exists_at(to)) {
+        create_account(to);
+    };
+    primary_fungible_store::deposit(to, fa)
+}
+
+ + +
@@ -1024,6 +1124,54 @@ Limit the address of auth_key is not @vm_reserved / @aptos_framework / @aptos_to + + +### Function `batch_transfer_fungible_assets` + + +
public entry fun batch_transfer_fungible_assets(from: &signer, metadata: object::Object<fungible_asset::Metadata>, recipients: vector<address>, amounts: vector<u64>)
+
+ + + + +
pragma verify = false;
+
+ + + + + +### Function `transfer_fungible_assets` + + +
public entry fun transfer_fungible_assets(from: &signer, metadata: object::Object<fungible_asset::Metadata>, to: address, amount: u64)
+
+ + + + +
pragma verify = false;
+
+ + + + + +### Function `deposit_fungible_assets` + + +
public fun deposit_fungible_assets(to: address, fa: fungible_asset::FungibleAsset)
+
+ + + + +
pragma verify = false;
+
+ + + ### Function `assert_account_exists` diff --git a/aptos-move/framework/aptos-framework/sources/aptos_account.move b/aptos-move/framework/aptos-framework/sources/aptos_account.move index 59679aada2903..d18abf2125186 100644 --- a/aptos-move/framework/aptos-framework/sources/aptos_account.move +++ b/aptos-move/framework/aptos-framework/sources/aptos_account.move @@ -4,7 +4,7 @@ module aptos_framework::aptos_account { use aptos_framework::coin::{Self, Coin}; use aptos_framework::create_signer::create_signer; use aptos_framework::event::{EventHandle, emit_event, emit}; - use aptos_framework::fungible_asset::{Self, Metadata, BurnRef}; + use aptos_framework::fungible_asset::{Self, Metadata, BurnRef, FungibleAsset}; use aptos_framework::primary_fungible_store; use aptos_framework::object; @@ -12,6 +12,7 @@ module aptos_framework::aptos_account { use std::features; use std::signer; use std::vector; + use aptos_framework::object::Object; friend aptos_framework::genesis; friend aptos_framework::resource_account; @@ -132,6 +133,40 @@ module aptos_framework::aptos_account { coin::deposit(to, coins) } + /// Batch version of transfer_fungible_assets. + public entry fun batch_transfer_fungible_assets( + from: &signer, + metadata: Object, + recipients: vector
, + amounts: vector + ) { + let recipients_len = vector::length(&recipients); + assert!( + recipients_len == vector::length(&amounts), + error::invalid_argument(EMISMATCHING_RECIPIENTS_AND_AMOUNTS_LENGTH), + ); + + vector::enumerate_ref(&recipients, |i, to| { + let amount = *vector::borrow(&amounts, i); + transfer_fungible_assets(from, metadata, *to, amount); + }); + } + + /// Convenient function to deposit fungible asset into a recipient account that might not exist. + /// This would create the recipient account first to receive the fungible assets. + public entry fun transfer_fungible_assets(from: &signer, metadata: Object, to: address, amount: u64) { + deposit_fungible_assets(to, primary_fungible_store::withdraw(from, metadata, amount)); + } + + /// Convenient function to deposit fungible asset into a recipient account that might not exist. + /// This would create the recipient account first to receive the fungible assets. + public fun deposit_fungible_assets(to: address, fa: FungibleAsset) { + if (!account::exists_at(to)) { + create_account(to); + }; + primary_fungible_store::deposit(to, fa) + } + public fun assert_account_exists(addr: address) { assert!(account::exists_at(addr), error::not_found(EACCOUNT_NOT_FOUND)); } diff --git a/aptos-move/framework/aptos-framework/sources/aptos_account.spec.move b/aptos-move/framework/aptos-framework/sources/aptos_account.spec.move index dc55f00112b4b..7c62849675512 100644 --- a/aptos-move/framework/aptos-framework/sources/aptos_account.spec.move +++ b/aptos-move/framework/aptos-framework/sources/aptos_account.spec.move @@ -238,6 +238,18 @@ spec aptos_framework::aptos_account { ensures if_exist_coin ==> post_coin_store_to == coin_store_to + coins.value; } + spec deposit_fungible_assets(to: address, fa: FungibleAsset) { + pragma verify = false; + } + + spec transfer_fungible_assets(from: &signer, metadata: Object, to: address, amount: u64) { + pragma verify = false; + } + + spec batch_transfer_fungible_assets(from: &signer, metadata: Object, recipients: vector
, amounts: vector) { + pragma verify = false; + } + spec transfer_coins(from: &signer, to: address, amount: u64) { // TODO(fa_migration) pragma verify = false;