-
Originally asked on stack overflow I need to somehow transfer APT coins to another account from smart contract itself. Here is an issue, because transfer function needs &signer of an sender and that's why I can not send it from contract. Is there any chance that I can send APT directly from contract itself inside a function by getting &signer somehow, or without it? I've read a lot of docs, search for it on GitHub and found nothing. I would appreciate any type of help. Regards! |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 1 reply
-
There are 2 ways of doing it, either store the signer capability in object as Object is the recommended approach now because it's more flexible and used as a successor of resource account. Here's how you can do it. module 0x12345::my_module {
const APP_OBJECT_SEED: vector<u8> = b"MY_APP";
// We use extend ref to generate the signer
struct AppObjectCapability has key {
extend_ref: ExtendRef,
}
// Create the object during init
fun init_module(deployer: &signer) {
let constructor_ref = object::create_named_object(
account,
APP_OBJECT_SEED,
);
let extend_ref = object::generate_extend_ref(&constructor_ref);
let app_signer = &object::generate_signer(&constructor_ref);
move_to(app_signer, AppObjectCapability {
extend_ref,
});
}
fun get_app_object_signer(app_object_address: address): signer acquires AppObjectCapability {
object::generate_signer_for_extending(&borrow_global<AppObjectCapability>(app_object_address).extend_ref)
}
fun get_app_object_address(): address {
object::create_object_address(&0x12345, APP_OBJECT_SEED)
}
// deposit APT from user to the object
entry fun deposit_apt<CoinType>(depositor: &signer, amount: u64) acquires AppObjectCapability {
let coins = coin::withdraw<CoinType>(depositor, amount);
aptos_account::deposit_coins(get_app_object_address(), coins);
}
// transfer APT from object to user
entry fun transfer_apt_to_user<CoinType>(recipient_address: address, amount: u64) acquires AppObjectCapability {
// do some validation to check recipient has permission to withdraw
let signer = get_app_object_signer(get_app_object_address());
let coins = coin::withdraw<CoinType>(&signer, amount);
aptos_account::deposit_coins(recipient_address, coins);
}
} |
Beta Was this translation helpful? Give feedback.
-
I inadvertently answered this question too somewhere else! Here is my take on it. Similar but different, each answer might suit different users better! The easiest way to do this would be with an object.
Overall your code to create the object + account would look like this: entry fun create(caller: &signer) {
// Create an object.
let caller_address = signer::address_of(caller);
let constructor_ref = object::create_object(caller_address);
let object_address = object::address_from_constructor_ref(&constructor_ref);
// Create an account alongside the object.
aptos_account::create_account(object_address);
// Store an ExtendRef alongside the object.
let object_signer = object::generate_signer(&constructor_ref);
let extend_ref = object::generate_extend_ref(&constructor_ref);
move_to(
&object_signer,
MyRefs { extend_ref: extend_ref },
);
} You'll see we store this struct MyRefs has key, store {
extend_ref: ExtendRef,
} The code to transfer funds from the account would look like this: entry fun transfer(caller: &signer, obj: Object<Account>, to: address, amount: u64) acquires MyRefs {
let caller_address = signer::address_of(caller);
assert!(object::is_owner(obj, caller_address), error::permission_denied(CALLER_NOT_OWNER));
let obj_address = object::object_address(&obj);
let my_refs = borrow_global<MyRefs>(obj_address);
let object_signer = object::generate_signer_for_extending(&my_refs.extend_ref);
aptos_account::transfer(&object_signer, to, amount);
} This You can see the full code for this example here: https://github.com/banool/move-examples/tree/main/object_account. Previously the recommended approach was to use a resource account. For example, to get the signer for a resource account, you could call |
Beta Was this translation helpful? Give feedback.
-
@banool why do we need to create an account alongside the object? Is it because we need to create account in order for that object to receive APT? |
Beta Was this translation helpful? Give feedback.
I inadvertently answered this question too somewhere else! Here is my take on it. Similar but different, each answer might suit different users better!
The easiest way to do this would be with an object.
Overall your code to create the object + account would look like this: