-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtoken.lua
221 lines (187 loc) · 6.64 KB
/
token.lua
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
local bint = require('.bint')(256)
--[[
This module implements the ao Standard Token Specification.
Terms:
Sender: the wallet or Process that sent the Message
It will first initialize the internal state, and then attach handlers,
according to the ao Standard Token Spec API:
- Info(): return the token parameters, like Name, Ticker, Logo, and Denomination
- Balance(Target?: string): return the token balance of the Target. If Target is not provided, the Sender
is assumed to be the Target
- Balances(): return the token balance of all participants
- Transfer(Target: string, Quantity: number): if the Sender has a sufficient balance, send the specified Quantity
to the Target. It will also issue a Credit-Notice to the Target and a Debit-Notice to the Sender
- Mint(Quantity: number): if the Sender matches the Process Owner, then mint the desired Quantity of tokens, adding
them the Processes' balance
]]
--
local json = require('json')
local utils = {
add = function(a, b)
return tostring(bint(a) + bint(b))
end,
subtract = function(a, b)
return tostring(bint(a) - bint(b))
end,
toBalanceValue = function(a)
return tostring(bint(a))
end,
toNumber = function(a)
return tonumber(a)
end
}
--[[
Initialize State
ao.id is equal to the Process.Id
]]
--
if Name ~= '0rbit Points' then Name = '0rbit Points' end
if Ticker ~= '0RBT' then Ticker = '0RBT' end
if Denomination ~= 12 then Denomination = 12 end
if not Logo then Logo = 'nvx7DgTR8ws_k6VNCSe8vhwbZLx5jNbfNLJS0IKTTHA' end
Balances = Balances or { [ao.id] = utils.toBalanceValue(10000 * 1e12) }
--[[
Add handlers for each incoming Action defined by the ao Standard Token Specification
]]
--
--[[
Info
]]
--
Handlers.add('info', Handlers.utils.hasMatchingTag('Action', 'Info'), function(msg)
Send({
Target = msg.From,
Name = Name,
Ticker = Ticker,
Logo = Logo,
Denomination = tostring(Denomination)
})
end)
--[[
Balance
]]
--
Handlers.add('balance', Handlers.utils.hasMatchingTag('Action', 'Balance'), function(msg)
local bal = '0'
-- If not Recipient is provided, then return the Senders balance
if (msg.Tags.Recipient and Balances[msg.Tags.Recipient]) then
bal = Balances[msg.Tags.Recipient]
elseif Balances[msg.From] then
bal = Balances[msg.From]
end
Send({
Target = msg.From,
Balance = bal,
Ticker = Ticker,
Account = msg.Tags.Recipient or msg.From,
Data = bal
})
end)
--[[
Balances
]]
--
Handlers.add('balances', Handlers.utils.hasMatchingTag('Action', 'Balances'),
function(msg) Send({ Target = msg.From, Data = json.encode(Balances) }) end)
--[[
Transfer
]]
--
Handlers.add('transfer', Handlers.utils.hasMatchingTag('Action', 'Transfer'), function(msg)
assert(type(msg.Recipient) == 'string', 'Recipient is required!')
assert(type(msg.Quantity) == 'string', 'Quantity is required!')
assert(bint.__lt(0, bint(msg.Quantity)), 'Quantity must be greater than 0')
if not Balances[msg.From] then Balances[msg.From] = "0" end
if not Balances[msg.Recipient] then Balances[msg.Recipient] = "0" end
if bint(msg.Quantity) <= bint(Balances[msg.From]) then
Balances[msg.From] = utils.subtract(Balances[msg.From], msg.Quantity)
Balances[msg.Recipient] = utils.add(Balances[msg.Recipient], msg.Quantity)
--[[
Only send the notifications to the Sender and Recipient
if the Cast tag is not set on the Transfer message
]]
--
if not msg.Cast then
-- Debit-Notice message template, that is sent to the Sender of the transfer
local debitNotice = {
Target = msg.From,
Action = 'Debit-Notice',
Recipient = msg.Recipient,
Quantity = msg.Quantity,
Data = Colors.gray ..
"You transferred " ..
Colors.blue .. msg.Quantity .. Colors.gray .. " to " .. Colors.green .. msg.Recipient .. Colors
.reset
}
-- Credit-Notice message template, that is sent to the Recipient of the transfer
local creditNotice = {
Target = msg.Recipient,
Action = 'Credit-Notice',
Sender = msg.From,
Quantity = msg.Quantity,
Data = Colors.gray ..
"You received " ..
Colors.blue .. msg.Quantity .. Colors.gray .. " from " .. Colors.green .. msg.From .. Colors.reset
}
-- Add forwarded tags to the credit and debit notice messages
for tagName, tagValue in pairs(msg) do
-- Tags beginning with "X-" are forwarded
if string.sub(tagName, 1, 2) == "X-" then
debitNotice[tagName] = tagValue
creditNotice[tagName] = tagValue
end
end
-- Send Debit-Notice and Credit-Notice
Send(debitNotice)
Send(creditNotice)
end
else
Send({
Target = msg.From,
Action = 'Transfer-Error',
['Message-Id'] = msg.Id,
Error = 'Insufficient Balance!'
})
end
end)
--[[
Mint
]]
--
Handlers.add('mint', Handlers.utils.hasMatchingTag('Action', 'Mint'), function(msg)
assert(type(msg.Quantity) == 'string', 'Quantity is required!')
assert(bint(0) < bint(msg.Quantity), 'Quantity must be greater than zero!')
if not Balances[ao.id] then Balances[ao.id] = "0" end
if msg.From == ao.id then
-- Add tokens to the token pool, according to Quantity
Balances[msg.From] = utils.add(Balances[msg.From], msg.Quantity)
Send({
Target = msg.From,
Data = Colors.gray .. "Successfully minted " .. Colors.blue .. msg.Quantity .. Colors.reset
})
else
Send({
Target = msg.From,
Action = 'Mint-Error',
['Message-Id'] = msg.Id,
Error = 'Only the Process Id can mint new ' .. Ticker .. ' tokens!'
})
end
end)
--[[
Total Supply
]]
--
Handlers.add('totalSupply', Handlers.utils.hasMatchingTag('Action', 'Total-Supply'), function(msg)
assert(msg.From ~= ao.id, 'Cannot call Total-Supply from the same process!')
local totalSupply = bint(0)
for _, balance in pairs(Balances) do
totalSupply = utils.add(totalSupply, balance)
end
Send({
Target = msg.From,
Action = 'Total-Supply',
Data = tostring(totalSupply),
Ticker = Ticker
})
end)