Get the calling module

I’m aware that Move has a GetTxnSender built-in that returns the sender of the current transaction. From the description, it seems like the behaviour of this is akin to tx.origin on Ethereum - it gives the address of the entity that submitted the transaction to the blockchain. Is this correct?

If so, is there an equivalent of Ethereum’s msg.sender in Move? In particular, if a transaction triggers a chain of module calls e.g. A -> B -> C, is there anyway of telling within module C that module B is the direct caller?

Hi Tom, good questions!

I’m aware that Move has a GetTxnSender built-in that returns the sender of the current transaction. From the description, it seems like the behaviour of this is akin to tx.origin on Ethereum - it gives the address of the entity that submitted the transaction to the blockchain. Is this correct?

This is correct.

If so, is there an equivalent of Ethereum’s msg.sender in Move?

Move does not have an equivalent of msg.sender that gives the name or address of the calling module. We have considered implementing such a construct, but (a) we have not seen compelling use-cases that require this feature, and (b) there are several gotchas in implementing such as feature. For example: what should the type of get_caller_module be? Another question is what get_caller_module should return when the caller is a transaction script instead of anoither module

1 Like

Hi @sam - thanks for the response! I wrote up a blogpost describing a use-case of this: https://medium.com/magmo/generalized-state-channels-with-move-2b3b2509d93b. It might be that I’ve missed some other way of handling this, so would be keen to hear your thoughts!

I’m guessing the type would need to be a Maybe(ModuleID) or something - but it doesn’t seem like you have a Maybe yet. For my purposes, I’d need to be able to convert a ModuleID into something comparable with a user-provided string.

I took a look at the blog post. I think there are a number of ways you could encode this sort of pattern in Move without introducing a get_calling_module() construct.

  • The Adjudicator.respond procedure could take the address a of an Adjudicator.T resource as input and then do borrow_global<T>(move(a)) on that address
  • If there is only one global Adjudicator.T resource stored at address 0xb0b, Adjudicator.respond could use borrow_global<T>(0xbob)
  • A resource declared in an application module could include a field that holds an Adjudicator resource and pass a reference to that resource to Adjudicator.respond

As far as I understand, borrow_global<T>(a) fetches the resource of type T stored at the address a. I can see that I probably need to use borrow_global to fix the move code I wrote in the blogpost but can’t see how that alone accomplishes what I’m trying to do.

I’m going to try and produce a simplified example of the functionality I’m aiming for. Let’s suppose I want to run something I’ll call the “Pre-image game” (PIG). The PIG works as follows:

  1. I lock X coins in a special PIG-adjudicator on-chain, which stores my address as the owner.
  2. I issue tickets of the form (target, functionAddress, signature) off-chain.
  3. The PIG-adjudicator has a claim(target, functionAddress, signature, preImage) function. This function will release the X coins to the sender if:
    • The signature is the owner’s signature on hash(target, functionAddress), and
    • If target = f(preImage) where f is calculated by calling the apply method on the contract stored at functionAddress.

The important feature here is that I can create and issue tickets off-chain, specifying the function I want at issue time (providing the function contract adheres to the expected interface, in this case having an apply method). This is the essence of the pattern required to build generalized state channels.

In solidity, the contract for this game would look something like:

interface PIGFunction {
    function apply(uint preImage) public pure returns (uint);
}

contract PIGAdjudicator {
    address owner;

    constructor() public payable {
        owner = msg.sender;
    }

   function claim(uint target, address functionAddress, bytes signature, uint preImage) public {
        // check ticket is valid
        assert(owner == recoverSigner(hash(target, functionAddress), signature));
        // check that preImage is correct
        assert(target == PIGFunction(functionAddress).apply(preImage));
        // send the coins
        msg.sender.send(address(this).balance);
    }
}

I know that this approach doesn’t apply directly in Move, due to the lack of dynamic calls.

What’s the best way to accomplish this sort of behaviour?

1 Like