Move_to_sender() but with a specified address

Hi there

I’ve got a question. How do I move a new resource to an address other than the sender?
Like move_to_sender() but with a specified address instead of the sender’s.

I was thinking about using borrow_global() to get hold of mutable reference, but it reverts if the resource for the address doesn’t already exist.

Thanks,
Peter Emil Jensen

3 Likes

Hi Peter,
Move does not allow you to move a resource to an address other than the sender’s. The reason for this is that publishing a resource under your account is a privileged operation. Letting someone else publish a resource under your account would be like letting someone else install an app on your phone. Restricting this privilege to the transaction sender ensures that Libra users have control over the content of their own accounts.

If you have a module that requires multiple accounts to hold a resource of a given type, you can achieve this using a “pull” pattern. The module here has an example of this (see the create procedure).

1 Like

Thanks. I see that.

But I can borrow a mutable reference to a resource owned by a different address. Doesn’t that go against the idea of the resource being privileged?

1 Like

Good question! The answer is no, but for a somewhat subtle reason: because BorrowGlobal<T> can only be used inside the module where the resource T is declared.

The idea is that before choosing to publish a resource T under your account, you should look over the code for the module and make sure you are ok with the API that the declaring module of T exposes. If a module lets anyone acquire a reference to a T under your account, that is probably too permissive!

The LibraAccount module here is a useful example to study in order to understand how to restrict access to a published resource with BorrowGlobal. This module:

  • Allows anyone to get a reference to the payee’s LibraAccount.T resource, but only temporarily, and for the purpose of putting Libra into the payee’s balance.
  • Allows the sender to get a reference to her own LibraAccount.T resource, but only temporarily, to perform a withdrawal of Libra from the sender’s account.
1 Like

Roger. Makes sense.

If I’ve declared a resource inside the module, shouldn’t I also be able to publish the resource on behalf of an address if I can mutate its content when it already exists? Or am I missing something central?

I’m creating a custom coin, and I want to be able to transfer funds to an address that hasn’t created a coin/resource yet.

If I’ve declared a resource inside the module, shouldn’t I also be able to publish the resource on behalf of an address if I can mutate its content when it already exists?

In our thinking, you should never be able to publish a resource under someone else’s account. The account owner should be in control of what data gets published under their account; no one should be able to clutter their account storage with resources the owner doesn’t want.

However: once you agree to publish a resource T under your account, you are implicitly agreeing to all of the rules for mutating T, acquiring references to T, and destroying T that the procedures of T’s declaring module encode.

I’m creating a custom coin, and I want to be able to transfer funds to an address that hasn’t created a coin/resource yet.

The pattern I would recommend for doing this is as follows:

module CustomCoin {
  resource T { value: u64 }

  public zero(): R#Self.T {
    return T { value: 0 };
  }

  public publish() {
    let zero_coin: R#Self.T;

    zero_coin = Self.zero();
    move_to_sender<T>(move(zero_coin));

    return;
  }

  public deposit(coin: R#Self.T, recipient: address) {
    // do BorrowGlobal<T>(move(recipient)), call logic for merging T's
  }

  // ... remainder of the logic for the custom coin, including splitting/merging T's
}

If the owner of account A wants to accept CustomCoin, it should send a transaction script that calls CustomCoin.publish(). After that, anyone can send CustomCoin's to A by calling CustomCoin.deposit(move(some_coin), move(address_of_A)).

3 Likes

Perfect. That’s the pattern I derived to as well :slight_smile:

Thank you very much for taking time to answer.
Have a great day!

1 Like

Hi Sam,
is there any document about each function in MOVE, e.g. move_from, get_txn_sender, etc…
or I can only read all mvir in testsuite to go through all of them?

Hi Wen.

This source in the Libra implementation specifies the parser. See line 110:
https://github.com/libra/libra/blob/master/language/compiler/src/parser/mod.rs#L110

2 Likes

This sounds like a rather dangerous assumption to make on the general user of Libra. What if someone make a module that allows certain address to mutate (i.e. withdraw) T and sell/market T as valuable custom coin?

I would characterize this as dangerous in the same way that it is dangerous to allow a user to decide which apps to install on their phone. It is indeed a lot of responsibility, but in practice most users will probably not choose to make this decision based on their own research (e.g., their wallet app may decide or advise which resources are safe to publish and which modules are safe to interact with). However, if you want to allow an open system, you have to give someone the autonomy to decide this.

What if someone make a module that allows certain address to mutate (i.e. withdraw) T and sell/market T as valuable custom coin?

I didn’t understand the scenario; could you clarify?

I would characterize this as dangerous in the same way that it is dangerous to allow a user to decide which apps to install on their phone. It is indeed a lot of responsibility, but in practice most users will probably not choose to make this decision based on their own research (e.g., their wallet app may decide or advise which resources are safe to publish and which modules are safe to interact with).

Is the vision for wallets to be more like app stores, with army of staff to review, test, and possibly curate each and every app it makes available? I suppose that could work. I was under the impress that a wallet is just another app that lives alongside with other apps, and only gets invoked at time of transaction.

I didn’t understand the scenario; could you clarify?

Never mind, I suppose it’s no more problematic than smart contracts on Ethereum or EOS or whatnot. However I’m still not comfortable offloading this responsibility to random wallet/end user especially if we’re talking about unbanked, non-tech savvy, non-English speaking population who really depend on the reputation of the Libra Association and (vague/false understanding of) the promised properties of blockchain.

But then again I don’t really have any good solutions.