summaryrefslogtreecommitdiff
path: root/test/scripts/e2e_subs/app-inner-calls.py
blob: a027747b287025578044f04d192c25ea52cd8528 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#!/usr/bin/env python

import os
import sys
from goal import Goal
import algosdk.logic as logic

from datetime import datetime

stamp = datetime.now().strftime("%Y%m%d_%H%M%S")
print(f"{os.path.basename(sys.argv[0])} start {stamp}")

goal = Goal(sys.argv[1], autosend=True)

joe = goal.new_account()

txinfo, err = goal.pay(goal.account, joe, amt=500_000)
assert not err, err

# Turn off rewards for precise balance checking
txinfo, err = goal.keyreg(joe, nonpart=True)
assert not err, err
joeb = goal.balance(joe)

# When invoked, this app funds the app that was created in the txn
# before it and invokes its start(asset) method.  Of course, this app must
# be prefunded to do so. And in real life, would want to check its
# sender as access control
fund_previous = """
#pragma version 6
 txn ApplicationID
 bz end

 itxn_begin
  int pay
  itxn_field TypeEnum

  txn GroupIndex
  int 1
  -
  gtxns CreatedApplicationID
  dup
  store 0
  app_params_get AppAddress
  assert
  itxn_field Receiver

  int 1000000
  itxn_field Amount

 itxn_next

  int appl
  itxn_field TypeEnum

  load 0
  itxn_field ApplicationID

  txn GroupIndex
  int 2
  -
  gtxns CreatedAssetID
  itxn_field Assets

  method "start(asset)"
  itxn_field ApplicationArgs

  byte 0x00
  itxn_field ApplicationArgs
 itxn_submit


end:
 int 1
"""

txinfo, err = goal.app_create(joe, goal.assemble(fund_previous))
assert not err, err
funder = txinfo['application-index']
assert funder

# Fund the funder
txinfo, err = goal.pay(goal.account, goal.app_address(funder), amt=4_000_000)
assert not err, err

# Construct a group that creates an ASA and an app, then "starts" the
# new app by funding and invoking "start(asset)" on it. Inside the new
# app's start() method, there will be yet another inner transaction:
# it opts into the supplied asset.

goal.autosend = False
create_asa = goal.asset_create(joe, total=10_000, unit_name="oz", asset_name="Gold")
app_teal = """
#pragma version 6
 txn ApplicationID
 bz end
 txn ApplicationArgs 0
 method "start(asset)"
 ==
 bz next0

 itxn_begin

 int axfer
 itxn_field TypeEnum

 txn ApplicationArgs 1
 btoi
 txnas Assets
 itxn_field XferAsset

 global CurrentApplicationAddress
 itxn_field AssetReceiver

 itxn_submit

next0:

end:
 int 1
"""
create_app = goal.app_create(joe, goal.assemble(app_teal))
start_app = goal.app_call(joe, funder)

[asa_info, app_info, start_info], err = goal.send_group([create_asa, create_app, start_app])
assert not err, err

goal.autosend = True

import json

asa_id = asa_info['asset-index']
app_id = app_info['application-index']
assert asa_id+1 == app_id
app_account = logic.get_application_address(app_id)

# Check balance on app account is right (1m - 1 optin fee)
assert 1_000_000-1000 == goal.balance(app_account), goal.balance(app_account)
assert 0 == goal.balance(app_account, asa_id)
# Check min-balance on app account is right (base + 1 asa)
assert 200_000 == goal.min_balance(app_account), goal.min_balance(app_account)

# Ensure creator can send asa to app
txinfo, err = goal.axfer(joe, app_account, 10, asa_id)
assert not err, err
assert 10 == goal.balance(app_account, asa_id)


print(f"{os.path.basename(sys.argv[0])} OK {stamp}")