Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
92fc25c
chore(patch balances): add patch balances work
atticusofsparta Oct 7, 2025
0d0f527
fix(patch): patch balances at end of handler wrapper
atticusofsparta Oct 7, 2025
19d4361
fix(git): ignore mac pointer files
atticusofsparta Oct 7, 2025
43a7a28
fix(patch): simplify balance patching
atticusofsparta Oct 7, 2025
271d965
fix(notes): remove handler balance modification notes
atticusofsparta Oct 7, 2025
4d3c53a
fix(patch): add patch balances hydration handler
atticusofsparta Oct 7, 2025
ceb7a21
fix(events): dont add affected address to the event
atticusofsparta Oct 7, 2025
4d915e0
fix(types): update luadoc types
atticusofsparta Oct 7, 2025
6af1b0d
fix(balances): use a save size checking method
atticusofsparta Oct 7, 2025
8aea00b
fix(patch): add patch file and move patchBalances to its own file to …
atticusofsparta Oct 7, 2025
3fd06b6
fix(balances): revert change to walletHasSufficientQUantity
atticusofsparta Oct 7, 2025
1ff76a3
fix(patching): remove token supply from patch message and fix tests
atticusofsparta Oct 7, 2025
4d2c7b1
fix(tests): add live memory test
atticusofsparta Oct 8, 2025
69350a2
fix(tests): auth issue
atticusofsparta Oct 8, 2025
6b11edd
fix(tests): add configuration for live process testing
atticusofsparta Oct 8, 2025
26b4e44
fix(comments): remove extraneous type
atticusofsparta Oct 8, 2025
68b0fc7
fix(tests): update tests
atticusofsparta Oct 8, 2025
e098651
fix(tests): update integration tests with new patch messages that off…
atticusofsparta Oct 8, 2025
271b6cb
fix(hb): update patchBalances to directly use Balances
atticusofsparta Oct 8, 2025
660739c
fix(test): cleanup unused variables
atticusofsparta Oct 8, 2025
f744578
fix(hb patch): fix pattern function on PatchHyperbeamBalances handler
atticusofsparta Oct 8, 2025
2bcb16c
fix(tests): add tests for patch hyperbeam balances
atticusofsparta Oct 8, 2025
122ffa8
fix(patch file): update hb patch device patch file
atticusofsparta Oct 8, 2025
16e05a5
fix(tests): adjust error handling in patch test
atticusofsparta Oct 8, 2025
377dd8b
fix(tests): add comment on different module id for live memory testing
atticusofsparta Oct 8, 2025
2cd0b34
fix(patch): update patch file to hydrate balances on hb at end of eval
atticusofsparta Oct 8, 2025
faa95de
fix(patch): stringify balances on egress to hb patch device
atticusofsparta Oct 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions handlers-that-modify-balances.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Handlers That Modify Balances

## Direct Balance Modification Handlers

### 1. Transfer

**Handler**: `ActionMap.Transfer`
**Action**: Transfers tokens from sender to recipient
**Balance Changes**: Sender balance ↓, Recipient balance ↑

### 2. CreateVault

**Handler**: `ActionMap.CreateVault`
**Action**: Locks tokens in a time-locked vault for the sender
**Balance Changes**: Sender balance ↓

### 3. VaultedTransfer

**Handler**: `ActionMap.VaultedTransfer`
**Action**: Creates a time-locked vault for a recipient
**Balance Changes**: Sender balance ↓

### 4. RevokeVault

**Handler**: `ActionMap.RevokeVault`
**Action**: Controller revokes a vaultedTransfer before it matures
**Balance Changes**: Controller balance ↑

### 5. IncreaseVault

**Handler**: `ActionMap.IncreaseVault`
**Action**: Adds more tokens to an existing vault
**Balance Changes**: Sender balance ↓

## Gateway/Staking Handlers

### 6. JoinNetwork

**Handler**: `ActionMap.JoinNetwork`
**Action**: Gateway joins the network with operator stake
**Balance Changes**: Operator balance ↓

### 7. IncreaseOperatorStake

**Handler**: `ActionMap.IncreaseOperatorStake`
**Action**: Increases gateway operator stake
**Balance Changes**: Operator balance ↓

### 8. DecreaseOperatorStake

**Handler**: `ActionMap.DecreaseOperatorStake`
**Action**: Decreases operator stake (with optional instant withdrawal)
**Balance Changes**: Operator balance ↑ (if instant withdrawal with penalty)

### 9. DelegateStake

**Handler**: `ActionMap.DelegateStake`
**Action**: Delegates stake to a gateway
**Balance Changes**: Delegator balance ↓

### 10. DecreaseDelegateStake

**Handler**: `ActionMap.DecreaseDelegateStake`
**Action**: Decreases delegated stake (with optional instant withdrawal)
**Balance Changes**: Delegator balance ↑ (if instant withdrawal with penalty)

### 11. InstantWithdrawal

**Handler**: `ActionMap.InstantWithdrawal`
**Action**: Instantly withdraws from a pending withdrawal vault with penalty
**Balance Changes**: Withdrawer balance ↑, Protocol balance ↑ (penalty fee)

### 12. CancelWithdrawal

**Handler**: `ActionMap.CancelWithdrawal`
**Action**: Cancels a withdrawal and returns to staked status
**Balance Changes**: No direct balance change (stake → vault → stake)

## ArNS Name Handlers

### 13. BuyName

**Handler**: `ActionMap.BuyName`
**Action**: Purchases an ArNS name (lease or permabuy)
**Balance Changes**: Buyer balance ↓ (via funding plan), Protocol balance ↑, Returned name initiator balance ↑ (if applicable)

### 14. ExtendLease

**Handler**: `ActionMap.ExtendLease`
**Action**: Extends an ArNS name lease
**Balance Changes**: Owner balance ↓ (via funding plan), Protocol balance ↑

### 15. IncreaseUndernameLimit

**Handler**: `ActionMap.IncreaseUndernameLimit`
**Action**: Increases undername limit for an ArNS name
**Balance Changes**: Owner balance ↓ (via funding plan), Protocol balance ↑

### 16. UpgradeName

**Handler**: `ActionMap.UpgradeName`
**Action**: Upgrades a leased name to permabuy
**Balance Changes**: Owner balance ↓ (via funding plan), Protocol balance ↑

## Primary Name Handlers

### 17. RequestPrimaryName

**Handler**: `ActionMap.RequestPrimaryName`
**Action**: Creates a primary name request
**Balance Changes**: Requester balance ↓ (via funding plan), Protocol balance ↑

## System/Automatic Operations

### 18. Epoch Distribution

**Handler**: Automatic via `distributeEpoch`
**Action**: Distributes rewards to gateways and delegates
**Balance Changes**: Protocol balance ↓, Gateway operator balances ↑ (or stakes ↑ if auto-stake), Delegate stakes ↑

### 19. Vault Pruning

**Handler**: Automatic via `vaults.pruneVaults`
**Action**: Releases matured balance vaults
**Balance Changes**: Vault owner balance ↑

### 20. Gateway Vault Pruning

**Handler**: Automatic via gateway pruning
**Action**: Releases matured gateway exit/withdrawal vaults
**Balance Changes**: Gateway operator balance ↑, Delegate balances ↑

### 21. Slashing

**Handler**: Via `gar.slashOperatorStake`
**Action**: Slashes operator stake for repeated failures
**Balance Changes**: Gateway operator stake ↓, Protocol balance ↑

---

**Note**: Handlers with "funding plan" support can draw from multiple sources (balance, delegated stakes, vaults) using `gar.applyFundingPlan()`, which orchestrates the necessary balance reductions across different sources.
13 changes: 13 additions & 0 deletions src/balances.lua
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,17 @@ function balances.walletHasSufficientBalance(wallet, quantity)
return Balances[wallet] ~= nil and Balances[wallet] >= quantity
end

---@param addresses table<string> A table of addresses and their balances
function balances.patchBalances(addresses)
assert(type(addresses) == "table", "Addresses must be a table")
--- For simplicity we always include the protocol balance in the patch message
local patchMessage = { device = "[email protected]", balances = { [ao.id] = Balances[ao.id] or 0 } }
for _, address in pairs(addresses) do
assert(type(address) == "string", "Address must be a string")
patchMessage.balances[address] = Balances[address] or 0
end

ao.send(patchMessage)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to refresh my memory on how large this can actually scale in HB...

end

return balances
7 changes: 7 additions & 0 deletions src/gar.lua
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,8 @@ end
--- @param msgId string The message ID
--- @return PruneGatewaysResult # The result containing the pruned gateways, slashed gateways, and other stats
function gar.pruneGateways(currentTimestamp, msgId)
local affectedAddresses = {}

--- @type PruneGatewaysResult
local result = {
prunedGateways = {},
Expand Down Expand Up @@ -1067,6 +1069,11 @@ function gar.pruneGateways(currentTimestamp, msgId)

result.gatewayObjectTallies = gatewayObjectTallies

for _, gateway in pairs(result.prunedGateways) do
table.insert(affectedAddresses, gateway)
end
balances.patchBalances(affectedAddresses)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not seem to be in the spirit of "do the patches at the end". I'd prefer we be calling a global function on balances to reset the affected balance addresses at handlers start, update the addresses via global call during routine operations, and then patch at the end of all handling presuming there have been no errors.


return result
end

Expand Down
38 changes: 27 additions & 11 deletions src/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,7 @@ addEventingHandler(ActionMap.Transfer, utils.hasMatchingTag("Action", ActionMap.
msg.ioEvent:addField("RecipientFormatted", recipient)

local result = balances.transfer(recipient, msg.From, quantity, allowUnsafeAddresses)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove

if result ~= nil then
local senderNewBalance = result[msg.From]
local recipientNewBalance = result[recipient]
Expand Down Expand Up @@ -680,6 +681,7 @@ addEventingHandler(ActionMap.Transfer, utils.hasMatchingTag("Action", ActionMap.
Send(msg, debitNotice)
Send(msg, creditNotice)
end
balances.patchBalances({ msg.From, recipient })
end)

addEventingHandler(ActionMap.CreateVault, utils.hasMatchingTag("Action", ActionMap.CreateVault), function(msg)
Expand Down Expand Up @@ -715,6 +717,7 @@ addEventingHandler(ActionMap.CreateVault, utils.hasMatchingTag("Action", ActionM
},
Data = json.encode(vault),
})
balances.patchBalances({ msg.From })
end)

addEventingHandler(ActionMap.VaultedTransfer, utils.hasMatchingTag("Action", ActionMap.VaultedTransfer), function(msg)
Expand Down Expand Up @@ -782,6 +785,8 @@ addEventingHandler(ActionMap.VaultedTransfer, utils.hasMatchingTag("Action", Act
},
Data = json.encode(vault),
})
-- might not need recipient here
balances.patchBalances({ msg.From, recipient })
end)

addEventingHandler(ActionMap.RevokeVault, utils.hasMatchingTag("Action", ActionMap.RevokeVault), function(msg)
Expand Down Expand Up @@ -820,6 +825,7 @@ addEventingHandler(ActionMap.RevokeVault, utils.hasMatchingTag("Action", ActionM
Tags = { Action = ActionMap.RevokeVault .. "-Notice", ["Vault-Id"] = vaultId },
Data = json.encode(vault),
})
balances.patchBalances({ msg.From, recipient })
end)

addEventingHandler(ActionMap.ExtendVault, utils.hasMatchingTag("Action", ActionMap.ExtendVault), function(msg)
Expand Down Expand Up @@ -873,6 +879,7 @@ addEventingHandler(ActionMap.IncreaseVault, utils.hasMatchingTag("Action", Actio
Tags = { Action = ActionMap.IncreaseVault .. "-Notice" },
Data = json.encode(vault),
})
balances.patchBalances({ msg.From })
end)

addEventingHandler(ActionMap.BuyName, utils.hasMatchingTag("Action", ActionMap.BuyName), function(msg)
Expand Down Expand Up @@ -946,6 +953,7 @@ addEventingHandler(ActionMap.BuyName, utils.hasMatchingTag("Action", ActionMap.B
}),
})
end
balances.patchBalances({ msg.From })
end)

addEventingHandler("upgradeName", utils.hasMatchingTag("Action", ActionMap.UpgradeName), function(msg)
Expand Down Expand Up @@ -976,6 +984,7 @@ addEventingHandler("upgradeName", utils.hasMatchingTag("Action", ActionMap.Upgra
type = record.type,
}),
})
balances.patchBalances({ msg.From })
end)

addEventingHandler(ActionMap.ExtendLease, utils.hasMatchingTag("Action", ActionMap.ExtendLease), function(msg)
Expand All @@ -1001,6 +1010,7 @@ addEventingHandler(ActionMap.ExtendLease, utils.hasMatchingTag("Action", ActionM
Tags = { Action = ActionMap.ExtendLease .. "-Notice", Name = name },
Data = json.encode(fundFrom and result or recordResult),
})
balances.patchBalances({ msg.From })
end)

addEventingHandler(
Expand Down Expand Up @@ -1034,6 +1044,8 @@ addEventingHandler(
},
Data = json.encode(fundFrom and result or recordResult),
})
-- TODO patch other ARIO locations based on FUND
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove

balances.patchBalances({ msg.From })
end
)

Expand Down Expand Up @@ -1185,6 +1197,7 @@ addEventingHandler(ActionMap.JoinNetwork, utils.hasMatchingTag("Action", ActionM
Tags = { Action = ActionMap.JoinNetwork .. "-Notice" },
Data = json.encode(gateway),
})
balances.patchBalances({ msg.From })
end)

addEventingHandler(ActionMap.LeaveNetwork, utils.hasMatchingTag("Action", ActionMap.LeaveNetwork), function(msg)
Expand Down Expand Up @@ -1272,6 +1285,7 @@ addEventingHandler(
Tags = { Action = ActionMap.IncreaseOperatorStake .. "-Notice" },
Data = json.encode(gateway),
})
balances.patchBalances({ msg.From })
end
)

Expand Down Expand Up @@ -1343,6 +1357,7 @@ addEventingHandler(
},
Data = json.encode(decreaseOperatorStakeResult.gateway),
})
balances.patchBalances({ msg.From })
end
)

Expand Down Expand Up @@ -1376,6 +1391,7 @@ addEventingHandler(ActionMap.DelegateStake, utils.hasMatchingTag("Action", Actio
Tags = { Action = ActionMap.DelegateStake .. "-Notice", Gateway = gatewayTarget },
Data = json.encode(delegateResult),
})
balances.patchBalances({ msg.From })
end)

addEventingHandler(ActionMap.CancelWithdrawal, utils.hasMatchingTag("Action", ActionMap.CancelWithdrawal), function(msg)
Expand Down Expand Up @@ -1455,6 +1471,7 @@ addEventingHandler(
Data = json.encode(result),
})
end
balances.patchBalances({ msg.From })
end
)

Expand Down Expand Up @@ -1526,6 +1543,7 @@ addEventingHandler(
},
Data = json.encode(result and result.updatedDelegate or {}),
})
balances.patchBalances({ msg.From })
end
)

Expand Down Expand Up @@ -1782,6 +1800,7 @@ end, function(msg)
]]
--
print("Ticking from " .. lastCreatedEpochIndex .. " to " .. targetCurrentEpochIndex)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove

for epochIndexToTick = lastCreatedEpochIndex, targetCurrentEpochIndex do
local tickResult = tick.tickEpoch(msg.Timestamp, blockHeight, hashchain, msgId, epochIndexToTick)
if tickResult.pruneGatewaysResult ~= nil then
Expand Down Expand Up @@ -2137,17 +2156,12 @@ end)
-- Pagination handlers

addEventingHandler("paginatedRecords", function(msg)
return msg.Action == "Paginated-Records" or msg.Action == ActionMap.Records
return msg.Action == "Paginated-Records" or msg.Action == ActionMap.Records
end, function(msg)
local page = utils.parsePaginationTags(msg)
local result = arns.getPaginatedRecords(
page.cursor,
page.limit,
page.sortBy or "startTimestamp",
page.sortOrder,
page.filters
)
Send(msg, { Target = msg.From, Action = "Records-Notice", Data = json.encode(result) })
local page = utils.parsePaginationTags(msg)
local result =
arns.getPaginatedRecords(page.cursor, page.limit, page.sortBy or "startTimestamp", page.sortOrder, page.filters)
Send(msg, { Target = msg.From, Action = "Records-Notice", Data = json.encode(result) })
end)

addEventingHandler("paginatedGateways", function(msg)
Expand Down Expand Up @@ -2454,6 +2468,8 @@ addEventingHandler(ActionMap.RedelegateStake, utils.hasMatchingTag("Action", Act
},
Data = json.encode(redelegationResult),
})

balances.patchBalances({ ao.id })
end)

addEventingHandler(ActionMap.RedelegationFee, utils.hasMatchingTag("Action", ActionMap.RedelegationFee), function(msg)
Expand Down Expand Up @@ -2521,7 +2537,7 @@ addEventingHandler("requestPrimaryName", utils.hasMatchingTag("Action", ActionMa
assertValidFundFrom(fundFrom)

local primaryNameResult = primaryNames.createPrimaryNameRequest(name, initiator, msg.Timestamp, msg.Id, fundFrom)

balances.patchBalances({ msg.From })
addPrimaryNameRequestData(msg.ioEvent, primaryNameResult)

--- if the from is the new owner, then send an approved notice to the from
Expand Down
4 changes: 4 additions & 0 deletions src/vaults.lua
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ end
--- @param currentTimestamp number The current timestamp
--- @return Vault[] The pruned vaults
function vaults.pruneVaults(currentTimestamp)
local affectedAddresses = {}

if not NextBalanceVaultsPruneTimestamp or currentTimestamp < NextBalanceVaultsPruneTimestamp then
-- No known pruning work to do
return {}
Expand All @@ -248,12 +250,14 @@ function vaults.pruneVaults(currentTimestamp)
for id, nestedVault in pairs(ownersVaults) do
if currentTimestamp >= nestedVault.endTimestamp then
balances.increaseBalance(owner, nestedVault.balance)
table.insert(affectedAddresses, owner)
prunedVaults[id] = vaults.removeVault(owner, id)
else
vaults.scheduleNextVaultsPruning(nestedVault.endTimestamp)
end
end
end
balances.patchBalances(affectedAddresses)
return prunedVaults
end

Expand Down
Loading