templates.create_contract

  1import smartpy as sp
  2
  3
  4@sp.module
  5def main():
  6    class Created(sp.Contract):
  7        def __init__(self):
  8            self.private.px = 10
  9            self.private.py = 0
 10            self.data.a = sp.int(0)
 11            self.data.b = sp.nat(0)
 12
 13        @sp.entrypoint
 14        def myEntryPoint(self, params):
 15            self.data.a += params.x + self.private.px
 16            self.data.b += params.y + self.private.py
 17
 18    class CreatedWithViews(sp.Contract):
 19        def __init__(self):
 20            self.data.a = sp.int(1)
 21            self.data.b = sp.nat(2)
 22
 23        @sp.entrypoint
 24        def myEntryPoint(self, params):
 25            self.data.a += params.x
 26            self.data.b += params.y
 27
 28        @sp.onchain_view()
 29        def myView(self, a):
 30            return self.data.a * a
 31
 32        @sp.offchain_view()
 33        def myOffchainView(self, b):
 34            return self.data.b * b
 35
 36    class CreatedWithParamInit(sp.Contract):
 37        def __init__(self, ab):
 38            self.private.px = 10
 39            self.private.py = ab.a + ab.b
 40            self.data.a = ab.a
 41            self.data.b = ab.b
 42
 43        @sp.entrypoint
 44        def myEntryPoint(self, params):
 45            self.data.a += params.x + self.private.px
 46            self.data.b += params.y + self.private.py
 47
 48    class CreatedWithParentClass(Created):
 49        def __init__(self):
 50            Created.__init__(self)
 51            self.private.px1 = 100
 52            self.private.py1 = 1
 53            self.data.a1 = sp.int(10)
 54            self.data.b1 = sp.nat(0)
 55
 56        @sp.entrypoint
 57        def myEntryPoint2(self, params):
 58            self.data.a1 += params.x + self.private.px1
 59            self.data.b1 += params.y + self.private.py1
 60
 61    def opopop(x):
 62        return sp.create_contract_operation(
 63            Created,
 64            None,
 65            sp.mutez(0),
 66            sp.record(a=x, b=15),
 67            private_=sp.record(px=20, py=13),
 68        )
 69
 70    class Creator(sp.Contract):
 71        def __init__(self, baker):
 72            self.private.baker = baker
 73            self.data.x = None
 74            self.data.l = opopop
 75
 76        @sp.entrypoint
 77        def create1(self):
 78            self.data.x = sp.Some(
 79                sp.create_contract(
 80                    Created,
 81                    None,
 82                    sp.mutez(123),
 83                    sp.record(a=12, b=15),
 84                    private_=sp.record(px=20, py=13),
 85                )
 86            )
 87
 88        @sp.entrypoint
 89        def create2(self):
 90            _ = sp.create_contract(
 91                Created,
 92                None,
 93                sp.tez(2),
 94                sp.record(a=12, b=15),
 95                private_=sp.record(px=20, py=13),
 96            )
 97            _ = sp.create_contract(
 98                Created,
 99                None,
100                sp.tez(2),
101                sp.record(a=12, b=16),
102                private_=sp.record(px=20, py=13),
103            )
104
105        @sp.entrypoint
106        def create3(self):
107            self.data.x = sp.Some(
108                sp.create_contract(
109                    Created,
110                    self.private.baker,
111                    sp.tez(0),
112                    sp.record(a=12, b=15),
113                    private_=sp.record(px=20, py=13),
114                )
115            )
116
117        @sp.entrypoint
118        def create4(self, l):
119            for x in l:
120                _ = sp.create_contract(
121                    Created,
122                    None,
123                    sp.mutez(0),
124                    sp.record(a=x, b=15),
125                    private_=sp.record(px=20, py=13),
126                )
127
128        @sp.entrypoint
129        def create5(self):
130            _ = sp.create_contract(
131                CreatedWithViews, self.private.baker, sp.mutez(10), sp.record(a=1, b=2)
132            )
133
134        @sp.entrypoint
135        def create6(self):
136            _ = sp.create_contract_operation(
137                CreatedWithViews, None, sp.mutez(0), sp.record(a=1, b=2)
138            )
139
140        @sp.entrypoint
141        def create_op(self):
142            record(operation, address).match = self.data.l(42)
143            sp.operations.push(operation)
144            self.data.x = sp.Some(address)
145
146        @sp.entrypoint
147        def create7(self):
148            _ = sp.create_contract(
149                CreatedWithParamInit,
150                None,
151                sp.mutez(0),
152                sp.record(a=1, b=15),
153                private_=sp.record(px=20, py=13),
154            )
155
156        @sp.entrypoint
157        def create8(self):
158            _ = sp.create_contract(
159                CreatedWithParentClass,
160                None,
161                sp.mutez(0),
162                sp.record(a=1, b=15, a1=10, b1=0),
163                private_=sp.record(px=20, py=13, px1=30, py1=130),
164            )
165
166
167@sp.add_test()
168def test():
169    scenario = sp.test_scenario("Create", main)
170    scenario.h1("Create Contract")
171    baker = sp.test_account("My baker")
172    scenario.h2("make the factory contract")
173    c = main.Creator(sp.Some(baker.public_key_hash))  # id = 0
174    c.set_initial_balance(sp.tez(10))
175    scenario += c
176    scenario.h2("make some dynamic contracts")
177    c.create1()  # id = 1
178    c.create2()  # id = 2, 3
179    c.create3()  # id = 4
180    c.create4([1, 2])  # id = 5, 6
181    c.create6()  # id = 7
182    c.create5()  # id = 8
183
184    scenario.h2(
185        "make another static contract - should be skipped in dyn contract offset calc"
186    )
187    c2 = main.CreatedWithViews()  # id = 9
188    c2.set_initial_balance(sp.tez(1))
189    scenario += c2
190
191    scenario.h2("references the contract that was dynamically created N times ago")
192    # ie c.create4([***1***, 2]) <-- the '1' one
193    dyn0 = scenario.dynamic_contract(main.Created, offset=-4)
194
195    scenario.h2("can call entrypoints via the handle")
196    dyn0.myEntryPoint(sp.record(x=1, y=16))
197    scenario.verify(dyn0.data.a == 22)  # 1 + 1 + 20
198    scenario.verify(dyn0.data.b == 44)  # 15 + 16 + 13
199    scenario.verify(dyn0.private.px == 20)
200    scenario.verify(dyn0.private.py == 13)
201    scenario.verify(dyn0.baker == None)
202    scenario.verify(dyn0.balance == sp.tez(0))
203
204    scenario.h2("call entrypoint again but change balance")
205    dyn0.myEntryPoint(sp.record(x=1, y=15), _amount=sp.tez(2))
206    scenario.verify(dyn0.data.a == 43)  # 22 + 1 + 20
207    scenario.verify(dyn0.data.b == 72)  # 44 + 15 + 13
208    scenario.verify(dyn0.private.px == 20)
209    scenario.verify(dyn0.private.py == 13)
210    scenario.verify(dyn0.baker == None)
211    scenario.verify(dyn0.balance == sp.tez(2))
212
213    scenario.h2("defaults to the last one created if offset is not given, ie create5()")
214    dyn1 = scenario.dynamic_contract(main.CreatedWithViews)
215    dyn1.myEntryPoint(sp.record(x=10, y=10))
216    scenario.verify(dyn1.data.a == 11)  # 1 + 10
217    scenario.verify(dyn1.data.b == 12)  # 2 + 10
218    scenario.h2("this one was created with a balance and baker")
219    scenario.verify(
220        dyn1.baker == sp.Some(sp.key_hash("tz1cWFxVfWdEXMk1HwXqXahXK6RQQw1rvZRP"))
221    )
222    scenario.verify(dyn1.balance == sp.mutez(10))
223    scenario.h2("this one did not have any private data")
224    scenario.verify(dyn1.private == sp.unit)
225
226    scenario.h2("can also call views")
227    scenario.verify(dyn1.myView(3) == 33)  # 3 * 11
228    scenario.verify(dyn1.myOffchainView(4) == 48)  # 4 * 12
229
230    scenario.h2("the static CreatedWithViews contract is a separate instance")
231    scenario.verify(c2.data.a == 1)
232    scenario.verify(c2.data.b == 2)
233    scenario.verify(c2.myView(3) == 3)
234    scenario.verify(c2.baker == None)
235    scenario.verify(c2.balance == sp.tez(1))
236
237    scenario.h2("can inject the CREATE_CONTRACT operation")
238    c.create_op()
239    scenario.show(c.data.x)
240    scenario.verify(
241        c.data.x
242        == sp.Some(sp.address("KT1Tezoo1ozzSmartPyzzSTATiCzzzw8CmuY"))  # 10th one
243    )
244    scenario.h2("can refer to that contract too")
245    dyn2 = scenario.dynamic_contract(main.Created)
246    scenario.verify(dyn2.data.a == 42)
247    scenario.verify(dyn2.data.b == 15)
248    scenario.verify(dyn2.private.px == 20)
249    scenario.verify(dyn2.private.py == 13)
250    scenario.verify(dyn2.baker == None)
251    scenario.verify(dyn2.balance == sp.tez(0))
252
253    scenario.h2("references are type checked at runtime")
254    try:
255        _ = scenario.dynamic_contract(main.CreatedWithViews)
256    except sp.RuntimeException as e:
257        print(e)
258    else:
259        assert False
260
261    scenario.h2("can dynamically create contract with parameterised init")
262    c.create7()
263    dyn3 = scenario.dynamic_contract(main.CreatedWithParamInit)
264    scenario.verify(dyn3.data.a == 1)
265    scenario.verify(dyn3.data.b == 15)
266    scenario.verify(dyn3.private.px == 20)
267    scenario.verify(dyn3.private.py == 13)
268    scenario.verify(dyn3.baker == None)
269    scenario.verify(dyn3.balance == sp.tez(0))
270
271    scenario.h2("can dynamically create contract with parent class")
272    c.create8()
273    dyn4 = scenario.dynamic_contract(main.CreatedWithParentClass)
274    scenario.verify(dyn4.data.a == 1)
275    scenario.verify(dyn4.data.a1 == 10)
276    scenario.verify(dyn4.data.b == 15)
277    scenario.verify(dyn4.data.b1 == 0)
278    scenario.verify(dyn4.private.px == 20)
279    scenario.verify(dyn4.private.px1 == 30)
280    scenario.verify(dyn4.private.py == 13)
281    scenario.verify(dyn4.private.py1 == 130)
282    scenario.verify(dyn4.baker == None)
283    scenario.verify(dyn4.balance == sp.tez(0))
284
285
286# a module that errors correctly - private data cannot be non-const at compile time
287@sp.module
288def errors():
289    class A(sp.Contract):
290        def __init__(self):
291            self.private = None
292            self.data.a = sp.int(0)
293            self.data.b = sp.nat(0)
294
295        @sp.entrypoint
296        def myEntryPoint(self, params):
297            if self.private.is_some():
298                self.data.a += params.x
299                self.data.b += params.y
300
301    class CreateBad(sp.Contract):
302        @sp.entrypoint
303        def createA(self):
304            _ = sp.create_contract(
305                A, None, sp.mutez(123), sp.record(a=12, b=15), private_=sp.Some(sp.now)
306            )
307
308
309@sp.add_test()
310def testErrors():
311    try:
312        _ = sp.test_scenario("CreateBad", errors)
313    except sp.TypeError_ as e:
314        print(e)
315    else:
316        assert False
317
318
319# a module set that errors incorrectly
320@sp.module
321def parentChild():
322    class Parent(sp.Contract):
323        @sp.private()
324        def private_(self):
325            return False
326
327        @sp.entrypoint()
328        def ov(self):
329            _ = self.private_()
330
331    class C(Parent):
332        def __init__(self):
333            Parent.__init__(self)
334
335
336@sp.module
337def factory():
338    class Factory(sp.Contract):
339        def __init__(self):
340            self.data.created = None
341
342        @sp.entrypoint
343        def create(self):
344            self.data.created = sp.Some(
345                sp.create_contract(parentChild.C, None, sp.mutez(0), ())
346            )
347
348
349@sp.add_test()
350def testHierarchy():
351    sc = sp.test_scenario("Factory", [parentChild, factory])
352    f = factory.Factory()
353    sc += f