Token Issue
This is an example for token system. It show how to build dApp
------------------------------------------------------------------------------
-- Safe maths
------------------------------------------------------------------------------
local M = {}
function M.add(a, b)
if a == nil then a = 0 end
if b == nil then b = 0 end
local c = a + b
assert(c >= a, "number overflow")
return c
end
function M.sub(a, b)
if a == nil then a = 0 end
if b == nil then b = 0 end
assert(b <= a, "first value must be bigger than second one")
local c = a - b
return c
end
function M.mul(a, b)
if a == nil then a = 0 end
if b == nil then b = 0 end
local c = a * b
assert(a == 0 or c/a == b, "number overflow")
return c
end
function M.div(a, b)
if a == nil then a = 0 end
if b == nil then b = 0 end
assert(b > 0, "second value must be bigger than 0")
c = a / b
return c
end
Mixer = {}
MixerMetatable = { __index = Mixer }
setmetatable(Mixer, {
__call = function(cls, ...)
return cls.new(...)
end
})
function Mixer.new(...)
local r = {}
for k, v in ipairs{...} do
r = v.new(r)
end
return r
end
Sequence = {}
SequenceMetatable = { __index = Sequence }
setmetatable(Sequence, {
__call = function(cls, ...)
return cls.new(...)
end
})
function Sequence.new(name)
return setmetatable({name = 'sequence-' .. name}, SequenceMetatable)
end
function Sequence:next()
local currentSequence = system.getItem(self.name)
if (nil == currentSequence) then
currentSequence = 0
end
local nextSequence = currentSequence + 1
system.setItem(self.name, nextSequence)
return nextSequence;
end
--- mint.lua
MintService = { }
MintServiceMetatable = { __index = MintService }
setmetatable(MintService, {
__call = function(cls, ...)
return cls.new(...)
end
})
function MintService.new(parent)
return setmetatable({ parent = parent },
MintServiceMetatable)
end
function MintService:totalAmount(assetSymbol)
if AssetTypes.exists(assetSymbol) then
local mintInfo = system.getItem('mint-' .. assetSymbol)
return mintInfo.amount or -1
else
return -1
end
end
function MintService:issue(assetSymbol, amount)
amount = tonumber(amount)
assert(0 < amount)
if not AssetTypes.exists(assetSymbol) then
AssetTypes.register(assetSymbol)
end
local issuer = system.getSender()
local mintInfo = system.getItem('mint-' .. assetSymbol) or { issuer = issuer, amount = 0 }
assert(mintInfo.issuer == issuer, 'no authority')
mintInfo.amount = M.add(mintInfo.amount, amount)
system.setItem('mint-' .. assetSymbol, mintInfo)
if self.parent and self.parent.balanceService then
self.parent.balanceService:receiveFromExternal(issuer, assetSymbol, amount)
end
end
MintServiceComponent = {}
MintServiceComponentMetatable = { __index = MintServiceComponent }
setmetatable(MintServiceComponent, {
__call = function(cls, ...)
return cls.new(...)
end
})
function MintServiceComponent.new(o)
local data = o or {}
data.mintService = MintService(data)
return setmetatable(data, MintServiceMetatable)
end
--- balance.lua
BalanceService = { }
BalanceServiceMetatable = { __index = BalanceService }
setmetatable(BalanceService, {
__call = function(cls, ...)
return cls.new(...)
end
})
function BalanceService.new(parent)
return setmetatable({ parent = parent }, BalanceServiceMetatable)
end
function BalanceService:getAmount(address, assetSymbol)
assert(nil ~= address)
local account = system.getItem('account-' .. address)
if nil == account then
return 0
else
return account[assetSymbol] or 0
end
end
function BalanceService:receiveFromExternal(receiverAddress, assetSymbol, amount)
amount = tonumber(amount)
local receiverAccount = system.getItem('account-' .. receiverAddress) or { balance = 0 }
assert(0 < amount)
assert(nil ~= receiverAddress)
local key = assetSymbol
receiverAccount[key] = M.add(receiverAccount[key] or 0, amount)
system.setItem('account-' .. receiverAddress, receiverAccount)
if nil ~= self.parent and nil ~= self.parent.historyService then
local tx = Transaction(2, nil, receiverAddress, assetSymbol, amount)
self.parent.historyService:record(tx)
end
end
function BalanceService:transfer(receiverAddress, assetSymbol, amount)
amount = tonumber(amount)
local senderAddress = system.getSender()
local senderAccount = system.getItem('account-' .. senderAddress)
local receiverAccount = system.getItem('account-' .. receiverAddress) or { balance = 0 }
assert(0 < amount)
assert(nil ~= receiverAddress)
assert(nil ~= senderAccount)
local key = assetSymbol
assert(amount <= senderAccount[key], 'insufficient balance')
senderAccount[key] = M.sub(senderAccount[key] or 0, amount)
receiverAccount[key] = M.add(receiverAccount[key] or 0, amount)
system.setItem('account-' .. senderAddress, senderAccount)
system.setItem('account-' .. receiverAddress, receiverAccount)
if nil ~= self.parent and nil ~= self.parent.historyService then
local tx = Transaction(1, senderAddress, receiverAddress, assetSymbol, amount)
self.parent.historyService:record(tx)
end
end
BalanceServiceComponent = {}
BalanceServiceComponentMetatable = { __index = BalanceServiceMetatable }
setmetatable(BalanceServiceComponent, {
__call = function(cls, ...)
return cls.new(...)
end
})
function BalanceServiceComponent.new(o)
local data = o or {}
data.balanceService = BalanceService(data)
return setmetatable(data, BalanceServiceComponentMetatable)
end
Transaction = { }
TransactionMetatable = { __index = Transaction }
setmetatable(Transaction, {
__call = function(cls, ...)
return cls.new(...)
end
})
function Transaction.new(type, sender, receiver, assetType, amount)
setmetatable({
type = type,
sender = sender,
receiver = receiver,
assetType = assetType,
amount = amount
}, TransactionMetatable)
end
HistoryService = {}
HistoryServiceMetatable = { __index = HistoryService }
setmetatable(HistoryService, {
__call = function(cls, ...)
return cls.new(...)
end
})
function HistoryService.new(parent)
return setmetatable(
{ parent = parent, sequence = Sequence('history') },
HistoryServiceMetatable)
end
function HistoryService:record(transaction)
system.setItem('history-' .. self.sequence:next(), transaction)
end
HistoryServiceComponent = {}
HistoryServiceComponentMetatable = { __index = HistoryServiceComponent }
setmetatable(HistoryServiceComponent, {
__call = function(cls, ...)
return cls.new(...)
end
})
function HistoryServiceComponent.new(o)
local data = o or {}
data.historyService = HistoryService(data)
return setmetatable(data, HistoryServiceComponentMetatable)
end
--- asset.lua
AssetType = { }
AssetTypeMetatable = { __index = AssetType }
setmetatable(AssetType, {
__call = function(cls, ...)
return cls.new(...)
end
})
AssetTypes = {}
function AssetTypes.exists(symbol)
return nil ~= system.getItem('symbol-' .. symbol)
end
function AssetTypes.register(symbol)
assert(not AssetTypes.exists(symbol))
system.setItem('symbol-' .. symbol, symbol)
end
local tokenSystem = Mixer(MintServiceComponent, BalanceServiceComponent, HistoryServiceComponent)
function constructor()
tokenSystem.mintService:issue('bds1-token', 300000000)
end
function transfer(receiver, amount)
tokenSystem.balanceService:transfer(receiver, 'bds1-token', amount)
end
function getAmount(address)
return tokenSystem.balanceService:getAmount(address, 'bds1-token')
end
abi.register(transfer, getAmount)Last updated