# FLP Token HyperBeam Patches In order to be able for frontends to get the token states regarding Whitelist Module and Batch Transfer functionality, token processes are required to PATCH details about those. # Step 1: Configure Your State Message This is required for all tokens to enable balances and details resolution from HyperBeam nodes. To get started, you must login to your AOS process. Once the connection is established, we must create new submessages in our process state: 1. Save the snippet into a file called `patch_state.lua`: ```lua Send({ device="patch@1.0", balances = { device = "trie@1.0" }, ["token-info"] = { name = Name, ticker = Ticker, logo = Logo, denomination = tostring(Denomination), supply = TotalSupply } }) ``` 2. Connect via AOS to your FLP token process: `aos --wallet OWNER_WALLET PROCESS_ID` 3. Load the patch snippet into the process (inside the AOS console): `.load ./patch_state.lua` You may see a `**WARN: No target specified for message...` notification in response. This warning is harmless and can be safely ignored. # Step 2: Configure Patch for token transfer 1. Save the snippet into a file called `patch_transfers.lua`: ```lua local handlerExists = function(handlerName) if not Handlers or not Handlers.list then return false end for _, handler in ipairs(Handlers.list) do if handler.name == handlerName then return true end end return false end -- 1. ensure we don't duplicate while handlerExists('Patch-Transfers') do Handlers.remove('Patch-Transfers') end -- 2. add handler Handlers.after("transfer").add("Patch-Transfers", function(msg) if msg.Tags.Action == "Transfer" then return "continue" end return 0 end, function(msg) local patchMsg = { device = "patch@1.0", balances = {} } patchMsg.balances[msg.Sender] = Balances[msg.Sender] patchMsg.balances[msg.Recipient] = Balances[msg.Recipient] Send(patchMsg) end ) ``` 2. Connect via AOS to your FLP token process: `aos --wallet OWNER_WALLET PROCESS_ID` 3. Load the patch snippet into the process (inside the AOS console): `.load ./patch_transfers.lua` # Batch Transfer To expose Batch Transfer functionality `one-time patching` is required on the token process: 1. Save the following snippet to a file called `patch_bt.lua`: ```lua filename=patch_bt.lua local bint = require ".bint" (256) local token_lib = require "token.token_lib" 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 } -- Send Patch message for info token and discovery local patchMsg = { device = 'patch@1.0', ['token-info'] = { ['batch-transfer'] = true, }, balances = Balances } Send(patchMsg) local handlerExists = function(handlerName) if not Handlers or not Handlers.list then return false end for _, handler in ipairs(Handlers.list) do if handler.name == handlerName then return true end end return false end -- 1. ensure we don't duplicate while handlerExists('batchTransfer') do Handlers.remove('batchTransfer') end Handlers.add('batchTransfer', Handlers.utils.hasMatchingTag("Action", "Batch-Transfer"), function(msg) --[[ Simple CSV parser that splits input by newlines and commas to create a 2D table of values. ]] local function parseCSV(csvText) local result = {} -- Split by newlines and process each line for line in csvText:gmatch("[^\r\n]+") do local row = {} -- Split line by commas and add each value to the row for value in line:gmatch("[^,]+") do table.insert(row, value) end table.insert(result, row) end return result end -- Parse CSV data and validate entries local rawRecords = parseCSV(msg.Data) assert(rawRecords and #rawRecords > 0, 'No transfer entries found in CSV') local transferEntries = {} local totalQuantity = "0" -- Validate each entry and calculate total transfer amount for i, record in ipairs(rawRecords) do local recipient = record[1] local quantity = record[2] assert(recipient and quantity, 'Invalid entry at line ' .. i .. ': recipient and quantity required') assert(string.match(quantity, "^%d+$"), 'Invalid quantity format at line ' .. i .. ': must contain only digits') assert(bint.ispos(bint(quantity)), 'Quantity must be greater than 0 at line ' .. i) table.insert(transferEntries, { Recipient = recipient, Quantity = quantity }) totalQuantity = utils.add(totalQuantity, quantity) end -- Step 2: Check if sender has sufficient balance if not Balances[msg.From] then Balances[msg.From] = "0" end local balance = token_lib.calculateAvailableBalance(msg.From, msg.Timestamp) if not (bint(totalQuantity) <= bint(balance.Available)) then msg.reply({ Action = 'Transfer-Error', ['Message-Id'] = msg.Id, Error = 'Insufficient Balance!' }) return end -- Step 3: Prepare the balance updates local balanceUpdates = {} local patchMsg = { device = 'patch@1.0', balances = {} } for _, entry in ipairs(transferEntries) do local recipient = entry.Recipient local quantity = entry.Quantity if not Balances[recipient] then Balances[recipient] = "0" end -- Aggregate multiple transfers to the same recipient if not balanceUpdates[recipient] then balanceUpdates[recipient] = utils.add(Balances[recipient], quantity) else balanceUpdates[recipient] = utils.add(balanceUpdates[recipient], quantity) end end -- Step 4: Apply the balance changes atomically Balances[msg.From] = utils.subtract(Balances[msg.From], totalQuantity) for recipient, newBalance in pairs(balanceUpdates) do Balances[recipient] = newBalance patchMsg.balances[recipient] = Balances[recipient] end patchMsg.balances[msg.From] = Balances[msg.From] -- Step 5: Always send a batch debit notice to the sender local batchDebitNotice = { Action = 'Batch-Debit-Notice', Count = tostring(#transferEntries), Total = totalQuantity, ['Batch-Transfer-Init-Id'] = msg.Id, } -- Forward any X- tags to the debit notice for tagName, tagValue in pairs(msg.Tags) do if string.sub(tagName, 1, 2) == "X-" then batchDebitNotice[tagName] = tagValue end end msg.reply(batchDebitNotice) ao.send(patchMsg) -- Step 6: Send individual credit notices if Cast tag is not set if not msg.Cast then for _, entry in ipairs(transferEntries) do local creditNotice = { Target = entry.Recipient, Action = 'Credit-Notice', Sender = msg.From, Quantity = entry.Quantity, Data = "You received " .. entry.Quantity .. " from " .. msg.From } -- Forward any X- tags to the credit notices for tagName, tagValue in pairs(msg.Tags) do if string.sub(tagName, 1, 2) == "X-" then creditNotice[tagName] = tagValue end end ao.send(creditNotice) end end end ) ``` 2. Connect via AOS to your FLP token process: `aos --wallet OWNER_WALLET PROCESS_ID` 3. Load the patch snippet into the process (inside the AOS console): `.load ./patch_bt.lua` # Whitelist Module To expose Whitelist Module functionality `one-time patching` is required on the token process: 1. Save the following snippet to a file called `patch_whitelist.lua`: ```lua -- Send Patch message for info token and discovery local patchMsg = { device = 'patch@1.0', ['token-info'] = { ['whitelist-module'] = WhitelistModule and true or false } } Send(patchMsg) ``` 2. Connect via AOS to your FLP token process: `aos --wallet OWNER_WALLET PROCESS_ID` 3. Load the patch snippet into the process (inside the AOS console): `.load ./patch_whitelist.lua`