From 2ad08e9874af290cf86a88ef75499d3ddbf6c4f2 Mon Sep 17 00:00:00 2001 From: Jack Frain Date: Tue, 3 Sep 2024 15:42:05 -0400 Subject: [PATCH] fix(cookbook): update token blueprint code with latest version #191 --- src/guides/aos/blueprints/token.md | 161 ++++++++++++++++++++--------- 1 file changed, 114 insertions(+), 47 deletions(-) diff --git a/src/guides/aos/blueprints/token.md b/src/guides/aos/blueprints/token.md index a3a96564..38b1c233 100644 --- a/src/guides/aos/blueprints/token.md +++ b/src/guides/aos/blueprints/token.md @@ -16,6 +16,10 @@ The Token Blueprint is a predesigned template that helps you quickly build a tok - **Mint Handler**: The `mint` handler allows processes to mint new tokens. +- **Total Supply Handler**: The `totalSupply` handler allows processes to retrieve the total supply of the token. + +- **Burn Handler**: The `burn` handler allows processes to burn tokens. + ### How To Use: 1. Open your preferred text editor. @@ -31,7 +35,6 @@ Type in `Handlers.list` to see the newly loaded handlers. ```lua local bint = require('.bint')(256) -local ao = require('ao') --[[ This module implements the ao Standard Token Specification. @@ -57,21 +60,43 @@ local ao = require('ao') -- local json = require('json') +--[[ + utils helper functions to remove the bint complexity. +]] +-- + + +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 bint.tonumber(a) + end +} + + --[[ Initialize State ao.id is equal to the Process.Id ]] -- -if not Balances then Balances = { [ao.id] = tostring(bint(10000 * 1e12)) } end - -if Name ~= 'Points Coin' then Name = 'Points Coin' end +Variant = "0.0.3" -if Ticker ~= 'Points' then Ticker = 'PNTS' end - -if Denomination ~= 12 then Denomination = 12 end - -if not Logo then Logo = 'SBCCXwwecBlDqRLUjb8dYABExTJXLieawf7m2aBJ-KY' end +-- token should be idempotent and not change previous state updates +Denomination = Denomination or 12 +Balances = Balances or { [ao.id] = utils.toBalanceValue(10000 * 10 ^ Denomination) } +TotalSupply = TotalSupply or utils.toBalanceValue(10000 * 10 ^ Denomination) +Name = Name or 'Points Coin' +Ticker = Ticker or 'PNTS' +Logo = Logo or 'SBCCXwwecBlDqRLUjb8dYABExTJXLieawf7m2aBJ-KY' --[[ Add handlers for each incoming Action defined by the ao Standard Token Specification @@ -82,9 +107,8 @@ if not Logo then Logo = 'SBCCXwwecBlDqRLUjb8dYABExTJXLieawf7m2aBJ-KY' end Info ]] -- -Handlers.add('info', Handlers.utils.hasMatchingTag('Action', 'Info'), function(msg) - ao.send({ - Target = msg.From, +Handlers.add('info', "Info", function(msg) + msg.reply({ Name = Name, Ticker = Ticker, Logo = Logo, @@ -96,21 +120,24 @@ end) Balance ]] -- -Handlers.add('balance', Handlers.utils.hasMatchingTag('Action', 'Balance'), function(msg) +Handlers.add('balance', "Balance", function(msg) local bal = '0' - -- If not Target is provided, then return the Senders balance - if (msg.Tags.Target and Balances[msg.Tags.Target]) then + -- If not Recipient is provided, then return the Senders balance + if (msg.Tags.Recipient) then + if (Balances[msg.Tags.Recipient]) then + bal = Balances[msg.Tags.Recipient] + end + elseif msg.Tags.Target and Balances[msg.Tags.Target] then bal = Balances[msg.Tags.Target] elseif Balances[msg.From] then bal = Balances[msg.From] end - ao.send({ - Target = msg.From, + msg.reply({ Balance = bal, Ticker = Ticker, - Account = msg.Tags.Target or msg.From, + Account = msg.Tags.Recipient or msg.From, Data = bal }) end) @@ -119,14 +146,14 @@ end) Balances ]] -- -Handlers.add('balances', Handlers.utils.hasMatchingTag('Action', 'Balances'), - function(msg) ao.send({ Target = msg.From, Data = json.encode(Balances) }) end) +Handlers.add('balances', "Balances", + function(msg) msg.reply({ Data = json.encode(Balances) }) end) --[[ Transfer ]] -- -Handlers.add('transfer', Handlers.utils.hasMatchingTag('Action', 'Transfer'), function(msg) +Handlers.add('transfer', "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') @@ -134,11 +161,9 @@ Handlers.add('transfer', Handlers.utils.hasMatchingTag('Action', 'Transfer'), fu if not Balances[msg.From] then Balances[msg.From] = "0" end if not Balances[msg.Recipient] then Balances[msg.Recipient] = "0" end - local qty = bint(msg.Quantity) - local balance = bint(Balances[msg.From]) - if bint.__le(qty, balance) then - Balances[msg.From] = tostring(bint.__sub(balance, qty)) - Balances[msg.Recipient] = tostring(bint.__add(Balances[msg.Recipient], qty)) + 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 @@ -146,26 +171,41 @@ Handlers.add('transfer', Handlers.utils.hasMatchingTag('Action', 'Transfer'), fu ]] -- if not msg.Cast then - -- Send Debit-Notice to the Sender - ao.send({ - Target = msg.From, + -- Debit-Notice message template, that is sent to the Sender of the transfer + local debitNotice = { Action = 'Debit-Notice', Recipient = msg.Recipient, - Quantity = tostring(qty), - Data = Colors.gray .. "You transferred " .. Colors.blue .. msg.Quantity .. Colors.gray .. " to " .. Colors.green .. msg.Recipient .. Colors.reset - }) - -- Send Credit-Notice to the Recipient - ao.send({ + 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 = tostring(qty), - Data = Colors.gray .. "You received " .. Colors.blue .. msg.Quantity .. Colors.gray .. " from " .. Colors.green .. msg.From .. Colors.reset - }) + 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 + msg.reply(debitNotice) + Send(creditNotice) end else - ao.send({ - Target = msg.From, + msg.reply({ Action = 'Transfer-Error', ['Message-Id'] = msg.Id, Error = 'Insufficient Balance!' @@ -177,27 +217,54 @@ end) Mint ]] -- -Handlers.add('mint', Handlers.utils.hasMatchingTag('Action', 'Mint'), function (msg) +Handlers.add('mint', "Mint", function(msg) assert(type(msg.Quantity) == 'string', 'Quantity is required!') - assert(bint.__lt(0, msg.Quantity), 'Quantity must be greater than zero!') + 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] = tostring(bint.__add(Balances[Owner], msg.Quantity)) - ao.send({ - Target = msg.From, + Balances[msg.From] = utils.add(Balances[msg.From], msg.Quantity) + TotalSupply = utils.add(TotalSupply, msg.Quantity) + msg.reply({ Data = Colors.gray .. "Successfully minted " .. Colors.blue .. msg.Quantity .. Colors.reset }) else - ao.send({ - Target = msg.From, + msg.reply({ Action = 'Mint-Error', ['Message-Id'] = msg.Id, - Error = 'Only the Process Owner can mint new ' .. Ticker .. ' tokens!' + Error = 'Only the Process Id can mint new ' .. Ticker .. ' tokens!' }) end end) +--[[ + Total Supply + ]] +-- +Handlers.add('totalSupply', "Total-Supply", function(msg) + assert(msg.From ~= ao.id, 'Cannot call Total-Supply from the same process!') + + msg.reply({ + Action = 'Total-Supply', + Data = TotalSupply, + Ticker = Ticker + }) +end) + +--[[ + Burn +]] -- +Handlers.add('burn', 'Burn', function(msg) + assert(type(msg.Quantity) == 'string', 'Quantity is required!') + assert(bint(msg.Quantity) <= bint(Balances[msg.From]), 'Quantity must be less than or equal to the current balance!') + + Balances[msg.From] = utils.subtract(Balances[msg.From], msg.Quantity) + TotalSupply = utils.subtract(TotalSupply, msg.Quantity) + + msg.reply({ + Data = Colors.gray .. "Successfully burned " .. Colors.blue .. msg.Quantity .. Colors.reset + }) +end) ```