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!
These days 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 MyRefs
struct alongside the object. This is necessary to store the ExtendRef
, which we need to generate a signer later so we can transfer coins. It looks like 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 transfer
function takes in an Object<Account>
. This assumes you know the object address somehow, e.g. from an API based on indexing. You could store the Object (which is essentially a reference) in a resource on chain attached to your account (e.g. MyObjectPointerStore
) instead if you wanted.
You can see the full code for this example here: https://github.com/banool/move-examples/tree/main/object_account.