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}")
|