diff --git a/spec/epochs_spec.lua b/spec/epochs_spec.lua index d4c2bc82..21c0ec15 100644 --- a/spec/epochs_spec.lua +++ b/spec/epochs_spec.lua @@ -457,9 +457,15 @@ describe("epochs", function() for i = 1, 5 do local gateway = { operatorStake = gar.getSettings().operators.minStake, - totalDelegatedStake = 0, + totalDelegatedStake = 100000000, vaults = {}, - delegates = {}, + delegates = { + ["this-is-a-delegate"] = { + delegatedStake = 100000000, + startTimestamp = 0, + vaults = {}, + }, + }, startTimestamp = 0, stats = { prescribedEpochCount = 0, @@ -479,7 +485,7 @@ describe("epochs", function() autoStake = false, -- TODO: validate autostake behavior label = "test", properties = "", - delegateRewardShareRatio = 20, + delegateRewardShareRatio = 10, }, status = "joined", observerAddress = "test-this-very-valid-observer-wallet-addr-" .. i, @@ -508,7 +514,7 @@ describe("epochs", function() end -- set the protocol balance to 5 million IO local totalEligibleRewards = math.floor(protocolBalance * 0.0025) - local expectedGatewaryReward = math.floor(totalEligibleRewards * 0.95 / 5) + local expectedGatewayReward = math.floor(totalEligibleRewards * 0.95 / 5) local expectedObserverReward = math.floor(totalEligibleRewards * 0.05 / 5) -- clear the balances for the gateways Balances["test-this-is-valid-arweave-wallet-address-1"] = 0 @@ -577,37 +583,53 @@ describe("epochs", function() -- check balances assert.are.equal(0, balances.getBalance("test-this-is-valid-arweave-wallet-address-1")) assert.are.equal( - math.floor(expectedGatewaryReward * 0.75), + math.floor(expectedGatewayReward * 0.75) * 0.90, -- 10% is given to delegates balances.getBalance("test-this-is-valid-arweave-wallet-address-2") ) - assert.are.equal(expectedObserverReward, balances.getBalance("test-this-is-valid-arweave-wallet-address-3")) - assert.are.equal(expectedObserverReward, balances.getBalance("test-this-is-valid-arweave-wallet-address-3")) assert.are.equal( - expectedGatewaryReward + expectedObserverReward, + math.floor(expectedObserverReward * 0.90), -- 10% is given to delegates + balances.getBalance("test-this-is-valid-arweave-wallet-address-3") + ) + assert.are.equal( + math.floor(expectedObserverReward * 0.90), -- 10% is given to delegates + balances.getBalance("test-this-is-valid-arweave-wallet-address-3") + ) + assert.are.equal( + math.floor((expectedGatewayReward + expectedObserverReward) * 0.90), -- 10% is given to delegates balances.getBalance("test-this-is-valid-arweave-wallet-address-4") ) assert.are.equal( - expectedGatewaryReward + expectedObserverReward, + (expectedGatewayReward + expectedObserverReward) * 0.90, -- 10% is given to delegates balances.getBalance("test-this-is-valid-arweave-wallet-address-5") ) -- check the epoch was updated local distributions = epochs.getEpoch(epochIndex).distributions local expectedTotalDistribution = 0 -- gateway 1 did not get any rewards - + math.floor(expectedGatewaryReward * 0.75) -- gateway 2 got 75% of the gateway reward + + math.floor(expectedGatewayReward * 0.75) -- gateway 2 got 75% of the gateway reward + expectedObserverReward * 3 -- gateway 3, 4, 5 got observer rewards - + expectedGatewaryReward * 2 -- gateway 4, 5 got gateway rewards + + expectedGatewayReward * 2 -- gateway 4, 5 got gateway rewards assert.are.same({ totalEligibleRewards = totalEligibleRewards, totalDistributedRewards = expectedTotalDistribution, distributedTimestamp = epochDistributionTimestamp, rewards = { ["test-this-is-valid-arweave-wallet-address-1"] = 0, - ["test-this-is-valid-arweave-wallet-address-2"] = math.floor(expectedGatewaryReward * 0.75), - ["test-this-is-valid-arweave-wallet-address-3"] = expectedObserverReward, - ["test-this-is-valid-arweave-wallet-address-4"] = expectedGatewaryReward + expectedObserverReward, - ["test-this-is-valid-arweave-wallet-address-5"] = expectedGatewaryReward + expectedObserverReward, + ["test-this-is-valid-arweave-wallet-address-2"] = math.floor(expectedGatewayReward * 0.75 * 0.90), + ["test-this-is-valid-arweave-wallet-address-3"] = expectedObserverReward * 0.90, + ["test-this-is-valid-arweave-wallet-address-4"] = (expectedGatewayReward + expectedObserverReward) + * 0.90, + ["test-this-is-valid-arweave-wallet-address-5"] = (expectedGatewayReward + expectedObserverReward) + * 0.90, + -- the delegate that got rewards + ["this-is-a-delegate"] = math.floor( + (expectedGatewayReward * 0.10 * 2) -- recevied by two passing gateways + + (expectedGatewayReward * 0.10 * 0.75) -- recevied by one passing gateway that did not observe + + (expectedObserverReward * 0.10 * 3) -- recevied by three observer gateways + ), }, }, distributions) + -- assert that the balance withdrawn from the protocol balance matches the total distributed rewards + assert.are.equal(protocolBalance - expectedTotalDistribution, balances.getBalance(ao.id)) end) end) end) diff --git a/spec/gar_spec.lua b/spec/gar_spec.lua index 0205d3f2..d4ae8f13 100644 --- a/spec/gar_spec.lua +++ b/spec/gar_spec.lua @@ -119,6 +119,7 @@ describe("gar", function() startTimestamp ) assert.is_true(status) + assert.are.equal(Balances["test-this-is-valid-arweave-wallet-address-1"], 0) assert.are.same(expectation, result) assert.are.same(expectation, gar.getGateway("test-this-is-valid-arweave-wallet-address-1")) end) @@ -224,6 +225,7 @@ describe("gar", function() observerAddress = "observerAddress", } local result, err = gar.increaseOperatorStake("test-this-is-valid-arweave-wallet-address-1", 1000) + assert.are.equal(Balances["test-this-is-valid-arweave-wallet-address-1"], 0) assert.are.same(result, { operatorStake = gar.getSettings().operators.minStake + 1000, totalDelegatedStake = 0, @@ -398,6 +400,7 @@ describe("gar", function() gar.getSettings().delegates.minStake, startTimestamp ) + assert.are.equal(Balances["test-this-is-valid-arweave-wallet-address-2"], 0) assert.are.same(result, { operatorStake = gar.getSettings().operators.minStake, totalDelegatedStake = gar.getSettings().delegates.minStake, diff --git a/src/epochs.lua b/src/epochs.lua index a7e236e0..48ca6470 100644 --- a/src/epochs.lua +++ b/src/epochs.lua @@ -483,10 +483,10 @@ function epochs.distributeRewardsForEpoch(currentTimestamp) if remaingOperatorReward > 0 and gateway.settings.autoStake then gar.increaseOperatorStake(gatewayAddress, remaingOperatorReward) end - epochDistributions[gatewayAddress] = remaingOperatorReward + epochDistributions[gatewayAddress] = (epochDistributions[gatewayAddress] or 0) + remaingOperatorReward else -- mark it as zero rewards - epochDistributions[gatewayAddress] = 0 + epochDistributions[gatewayAddress] = epochDistributions[gatewayAddress] or 0 end -- increment the total distributed diff --git a/src/main.lua b/src/main.lua index 67295282..2ec3242e 100644 --- a/src/main.lua +++ b/src/main.lua @@ -60,6 +60,8 @@ local ActionMap = { Gateways = "Gateways", GatewayRegistrySettings = "Gateway-Registry-Settings", -- writes + Vault = "Vault", + Vaults = "Vaults", CreateVault = "Create-Vault", VaultedTransfer = "Vaulted-Transfer", ExtendVault = "Extend-Vault", @@ -838,6 +840,46 @@ Handlers.add( end ) +Handlers.add("totalTokenSupply", utils.hasMatchingTag("Action", "Total-Token-Supply"), function(msg) + -- add all the balances + local totalSupply = 0 + local balances = balances.getBalances() + for _, balance in pairs(balances) do + totalSupply = totalSupply + balance + end + -- gateways and delegates + local gateways = gar.getGateways() + for _, gateway in pairs(gateways) do + totalSupply = totalSupply + gateway.operatorStake + gateway.totalDelegatedStake + for _, delegate in pairs(gateway.delegates) do + -- check vaults + for _, vault in pairs(delegate.vaults) do + totalSupply = totalSupply + vault.balance + end + end + -- iterate through vaults + for _, vault in pairs(gateway.vaults) do + totalSupply = totalSupply + vault.balance + end + end + + -- vaults + local vaults = vaults.getVaults() + for _, vaultsForAddress in pairs(vaults) do + -- they may have several vaults iterate through them + for _, vault in pairs(vaultsForAddress) do + totalSupply = totalSupply + vault.balance + end + end + + ao.send({ + Target = msg.From, + Action = "Total-Token-Supply-Notice", + ["Total-Token-Supply"] = totalSupply, + Data = json.encode(totalSupply), + }) +end) + -- TICK HANDLER Handlers.add("tick", utils.hasMatchingTag("Action", "Tick"), function(msg) -- assert this is a write interaction and we have a timetsamp @@ -1116,7 +1158,7 @@ end) Handlers.add(ActionMap.Epochs, utils.hasMatchingTag("Action", ActionMap.Epochs), function(msg) local epochs = epochs.getEpochs() - ao.send({ Target = msg.From, Action = "Epochs-Notice", Data = json.encode(epochs) }) + ao.send({ Target = msg.From, Action = "Epochs-Notice", Data = epochs }) end) Handlers.add(ActionMap.PrescribedObservers, utils.hasMatchingTag("Action", ActionMap.PrescribedObservers), function(msg) @@ -1230,6 +1272,21 @@ Handlers.add(ActionMap.ReservedName, utils.hasMatchingTag("Action", ActionMap.Re }) end) +Handlers.add(ActionMap.Vaults, utils.hasMatchingTag("Action", ActionMap.Vaults), function(msg) + local vaults = vaults.getVaults() + ao.send({ Target = msg.From, Action = "Vaults-Notice", Data = json.encode(vaults) }) +end) + +Handlers.add(ActionMap.Vault, utils.hasMatchingTag("Action", ActionMap.Vault), function(msg) + local vault = vaults.getVault(msg.Tags.Address or msg.From) + ao.send({ + Target = msg.From, + Action = "Vault-Notice", + Address = msg.Tags.Address or msg.From, + Data = json.encode(vault), + }) +end) + -- END READ HANDLERS -- UTILITY HANDLERS USED FOR MIGRATION @@ -1325,51 +1382,6 @@ Handlers.add("paginatedBalances", utils.hasMatchingTag("Action", "Paginated-Bala end end) -Handlers.add("fixGateways", utils.hasMatchingTag("Action", "Fix-Gateways"), function(msg) - -- if msg.From ~= Owner then - -- ao.send({ Target = msg.From, Data = "Unauthorized" }) - -- return - -- end - - local fixGateways = function() - -- reset any gateways marked as leaving - local gateways = gar.getGateways() - for address, gateway in pairs(gateways) do - if gateway ~= nil and gateway.status == "leaving" then - gateway.status = "joined" - gateway.endTimestamp = nil - local totalOperatorStake = 0 - for _, vault in pairs(gateway.vaults) do - totalOperatorStake = totalOperatorStake + vault.balance - end - gateway.operatorStake = totalOperatorStake - gateway.vaults = {} - -- move the delegated vaults back - for delegateAddress, delegate in pairs(gateway.delegates) do - for _, vault in pairs(delegate.vaults) do - -- if the vault is delegated to the gateway, move it back - gateway.totalDelegatedStake = gateway.totalDelegatedStake + vault.balance - gateway.delegates[delegateAddress].delegatedStake = ( - gateway.delegates[delegateAddress].delegatedStake or 0 - ) + vault.balance - end - gateway.delegates[delegateAddress].vaults = {} - end - -- now update the actual registry - gar.addGateway(address, gateway) - end - end - end - - local status, result = pcall(fixGateways) - if not status then - ao.send({ Target = msg.From, Action = "Fix-Gateways-Error-Notice", Data = json.encode(result) }) - else - ao.send({ Target = msg.From, Action = "Fix-Gateways-Notice", Data = json.encode(result) }) - end - -- end -end) - -- END UTILITY HANDLERS USED FOR MIGRATION return process