templates.inter_contract_calls

  1import smartpy as sp
  2
  3
  4@sp.module
  5def main():
  6    # Worker contract that our Main contract is going to call entrypoints on.
  7    # Stores a single string ('message'), with entrypoints to allow the string
  8    # to be overwritten or appended to.
  9    class Worker(sp.Contract):
 10        def __init__(self):
 11            self.data.message = ""
 12
 13        @sp.entrypoint
 14        def set_message(self, message):
 15            self.data.message = message
 16
 17        @sp.entrypoint
 18        def append_message(self, message, separator):
 19            # Only use the separator if the message is currently empty ("")
 20            if sp.len(self.data.message) == 0:
 21                self.data.message = message
 22            else:
 23                self.data.message = sp.concat([self.data.message, separator, message])
 24
 25    # the expected args type for the set_message entrypoint
 26    set_message_args_type: type = sp.string
 27
 28    # the expected args type for the append_message entrypoint
 29    append_message_args_type: type = sp.record(message=sp.string, separator=sp.string)
 30
 31    # The main contract.
 32    # Calls through to the Worker contract passed by address on init.
 33    class Main(sp.Contract):
 34        def __init__(self, worker_contract_address):
 35            self.data.worker_contract_address = worker_contract_address
 36
 37        @sp.entrypoint
 38        def store_single_message(self, message):
 39            # Prepare the full entrypoint signature.
 40            # Note that we have to call `.unwrap_some()` in order to open the sp.option[...],
 41            # as the contract may not exist.
 42            set_message_entrypoint = sp.contract(
 43                set_message_args_type, self.data.worker_contract_address, "set_message"
 44            ).unwrap_some()
 45
 46            # call the `set_message` entrypoint on the worker contract
 47            sp.transfer(message, sp.tez(0), set_message_entrypoint)
 48
 49        @sp.entrypoint
 50        def append_multiple_messages(self, params):
 51            sp.cast(params, sp.record(messages=sp.list[sp.string], separator=sp.string))
 52
 53            # Prepare the full entrypoint signature.
 54            # Note that, as above, we have to call `.unwrap_some()` in order to open the sp.option[...],
 55            # as the contract may not exist.
 56            append_message_entrypoint = sp.contract(
 57                append_message_args_type,
 58                self.data.worker_contract_address,
 59                "append_message",
 60            ).unwrap_some()
 61
 62            # call the `append_message` entrypoint on the worker contract once for
 63            # each string in params.messages
 64            for message in params.messages:
 65                append_message_args = sp.record(
 66                    message=message, separator=params.separator
 67                )
 68                sp.transfer(append_message_args, sp.tez(0), append_message_entrypoint)
 69
 70
 71@sp.add_test()
 72def test():
 73    scenario = sp.test_scenario("InterContractCallsExample", main)
 74    scenario.h1("Inter-Contract Calls - example")
 75
 76    # originate the Worker contract and directly invoke it
 77    scenario.h2("Worker")
 78    worker_contract = main.Worker()
 79    scenario += worker_contract
 80    scenario.h3("Call the Worker contract entrypoints directly")
 81    scenario.h4("set_message")
 82    worker_contract.set_message("Directly set a message")
 83    scenario.verify(worker_contract.data.message == "Directly set a message")
 84    scenario.h4("append_message")
 85    worker_contract.append_message(message="and append another", separator=", ")
 86    scenario.verify(
 87        worker_contract.data.message == "Directly set a message, and append another"
 88    )
 89
 90    # originate the Main contract
 91    scenario.h2("Main")
 92    main_contract = main.Main(worker_contract.address)
 93    scenario += main_contract
 94    # the main contract calls through to the Worker contract methods
 95    scenario.h3(
 96        "Call the Main contract entrypoints, which in turn call through to the Worker contract entrypoints"
 97    )
 98    scenario.h4("store_single_message")
 99    main_contract.store_single_message("Indirectly set a message")
100    scenario.verify(worker_contract.data.message == "Indirectly set a message")
101    scenario.h4("append_multiple_messages")
102    main_contract.append_multiple_messages(
103        messages=["and", "append", "some", "more"], separator=", "
104    )
105    scenario.verify(
106        worker_contract.data.message
107        == "Indirectly set a message, and, append, some, more"
108    )