1import smartpy as sp
2
3
4@sp.module
5def main():
6 set_f_type: type = sp.lambda_(sp.int, sp.int, with_storage="read-write")
7
8 @sp.effects(with_storage="read-write")
9 def set_f(x):
10 sp.cast(x, sp.int)
11 self.data.x = x
12 return x * 100
13
14 class Library(sp.Contract):
15 def __init__(self):
16 self.data.x = 0
17
18 @sp.onchain_view()
19 def get_set_f(self):
20 return set_f
21
22 # Same as Library, but different storage.
23 class Library2(sp.Contract):
24 def __init__(self):
25 self.data.y = "abc"
26
27 @sp.onchain_view()
28 def get_set_f(self):
29 return set_f
30
31 class Main(sp.Contract):
32 def __init__(self):
33 self.data.x = 0
34
35 @sp.entrypoint
36 def run(self, f, x):
37 sp.cast(f, set_f_type)
38 _ = f(x)
39
40 @sp.entrypoint
41 def save(self, f, x):
42 sp.cast(f, set_f_type)
43 self.data.x = f(x)
44
45 class Remote(sp.Contract):
46 @sp.entrypoint
47 def call(self, lib, main, x):
48 remote_set_f = sp.view("get_set_f", lib, (), set_f_type).unwrap_some()
49 main_run = sp.contract(
50 sp.record(f=set_f_type, x=sp.int), main, entrypoint="run"
51 ).unwrap_some()
52 sp.transfer(sp.record(f=remote_set_f, x=x), sp.mutez(0), main_run)
53
54
55@sp.add_test()
56def test():
57 s = sp.test_scenario("Effects", main)
58 lib = main.Library()
59 lib2 = main.Library2()
60 main_ = main.Main()
61 remote = main.Remote()
62 s += lib
63 s += lib2
64 s += main_
65 s += remote
66
67 # Using a storage-modifying lambda from another contract with the
68 # same storage:
69 main_.run(f=lib.get_set_f(), x=5)
70 s.verify(main_.data.x == 5)
71 s.verify(lib.data.x == 0)
72
73 # Same, but with Library2:
74 main_.run(f=lib2.get_set_f(), x=5)
75 s.verify(main_.data.x == 5)
76 s.verify(lib.data.x == 0)
77
78 # Same, but overwrite the storage immediately:
79 main_.save(f=lib.get_set_f(), x=5)
80 s.verify(main_.data.x == 500)
81 s.verify(lib.data.x == 0)
82
83 # Complicate things a little by doing it via a remote contract
84 # that doesn't have any state:
85 remote.call(lib=lib.address, main=main_.address, x=7)
86 s.verify(main_.data.x == 7)
87 s.verify(lib.data.x == 0)
88
89 # We can also define effectful lambdas outside contracts, but then
90 # we have to specify a tstorage:
91 def f(self, x):
92 self.data.x = 2 * x
93 sp.result(0)
94
95 my_f = sp.build_lambda(
96 f, with_storage="read-write", tstorage=sp.record(x=sp.int_or_nat)
97 )
98 main_.run(f=my_f, x=42)
99 s.verify(main_.data.x == 84)