Resolved merge conflicts with master

This commit is contained in:
SkylarHew
2022-01-23 16:01:44 -07:00
31 changed files with 1525 additions and 291 deletions

View File

@ -28,7 +28,6 @@ function add_child_org_consent:initiate(result)
modpol.interactions.org_dashboard(
self.initiator, self.org.name)
self.org:delete_process(self.id)
if result then result() end
return
elseif modpol.orgs.get_org(input) then
modpol.interactions.message(
@ -45,7 +44,7 @@ function add_child_org_consent:initiate(result)
self.initiator,
"Proposed child org: " .. input)
-- initiate consent process
self.org:call_module(
self:call_module(
"consent",
self.initiator,
{
@ -70,7 +69,8 @@ function add_child_org_consent:create_child_org()
modpol.interactions.message_org(
self.initiator,
self.org.name,
"Child org created: "..self.data.child_name)
"Consent reached: created child org "
..self.data.child_name)
if self.data.result then self.data.result() end
self.org:delete_process(self.id)
end

View File

@ -0,0 +1,169 @@
--- change_modules
-- @module change_modules
-- Depends on consent
local change_modules = {
name = "Change modules (consent)",
slug = "change_modules",
desc = "Add or remove modules from the org with member consent",
hide = false;
}
change_modules.data = {
result = nil
}
change_modules.config = {
}
function change_modules:initiate(result)
self.data.result = result
-- Step 1: add or remove?
modpol.interactions.dropdown_query(
self.initiator, "Module change options:",
{"Add module","Remove module"},
function(input)
if input == "Add module" then
self:add_module()
elseif input == "Remove module" then
self:remove_module()
end
end
)
end
function change_modules:add_module()
-- prepare module options
local available_modules = modpol.util.copy_table(modpol.modules)
for k,org_mod in pairs(self.org.modules) do
if available_modules[org_mod.slug] then
available_modules[org_mod.slug] = nil
end end
-- present module options
local modules_list = {}
for k,v in pairs(available_modules) do
table.insert(modules_list,v.name)
end
if #modules_list == 0 then
modpol.interactions.message(
self.initiator, "Org has all modules")
modpol.interactions.org_dashboard(
self.initiator, self.org.id)
if self.data.result then self.data.result() end
self.org:delete_process(self.id)
return
end
table.sort(modules_list)
-- now ask which to add
modpol.interactions.dropdown_query(
self.initiator, "Choose a module to add:",
modules_list,
function(mod_choice)
-- confirm choice
modpol.interactions.binary_poll_user(
self.initiator,
"Confirm: propose to add module \"" ..
mod_choice .. "\"?",
function(input)
if input == "Yes" then
self:propose_change("add",mod_choice)
modpol.interactions.org_dashboard(
self.initiator, self.org.id)
else
self:add_module()
end
end
)
end
)
end
function change_modules:remove_module()
-- prepare module options
local available_modules = {}
for k,org_mod in pairs(self.org.modules) do
if not org_mod.hide then
available_modules[org_mod.slug] = modpol.util.copy_table(org_mod)
end end
local modules_list = {}
local modules_count = 0
for k,v in pairs(available_modules) do
table.insert(modules_list,v.name)
modules_count = modules_count + 1
end
-- abort if no modules to remove
if modules_count == 0 then
modpol.interactions.message(
self.initiator, "Org has no modules")
modpol.interactions.org_dashboard(
self.initiator, self.org.id)
if self.data.result then self.data.result() end
self.org:delete_process(self.id)
return
end
table.sort(modules_list)
-- now ask which to remove
modpol.interactions.dropdown_query(
self.initiator, "Choose a module to remove:",
modules_list,
function(mod_choice)
-- confirm choice
modpol.interactions.binary_poll_user(
self.initiator,
"Confirm: propose to remove module \"" .. mod_choice .. "\"?",
function(input)
if input == "Yes" then
self:propose_change("remove",mod_choice)
modpol.interactions.org_dashboard(
self.initiator, self.org.id)
else
self:remove_module()
end
end
)
end
)
end
--- propose_change
-- @field type "add" or "remove"
function change_modules:propose_change(type, mod_text)
self:call_module(
"consent",self.initiator,
{
prompt = "Do you consent to "..type..
" this module in org "..self.org.name..
":\n"..mod_text,
votes_required = #self.org.members
},
function()
if type == "add" then
for k,v in pairs(modpol.modules) do
if v.name == mod_text then
table.insert(self.org.modules,v)
end
end
modpol.interactions.message_org(
self.initiator,self.org.id,
"Consent reached:\nAdding \""
..mod_text.."\" to org "..self.org.name)
elseif type == "remove" then
local i = 0
for k,v in pairs(self.org.modules) do
i = i + 1
if v.name == mod_text then
self.org.modules[k] = nil
end
end
modpol.interactions.message_org(
self.initiator,self.org.id,
"Consent reached:\nRemoving \""
..mod_text.."\" from org "..self.org.name)
end
end)
if self.data.result then self.data.result() end
self.org:delete_process(self.id)
end
--- (Required) Add to module table
modpol.modules.change_modules = change_modules

View File

@ -10,7 +10,10 @@ local change_modules = {
}
change_modules.data = {
result = nil
result = nil,
modules_before = {},
modules_after = {},
summary = "",
}
change_modules.config = {
@ -21,151 +24,93 @@ change_modules.config = {
-- @function change_modules:initiate
function change_modules:initiate(result)
self.data.result = result
-- Step 1: add or remove?
modpol.interactions.dropdown_query(
self.initiator, "Module change options:",
{"Add module","Remove module"},
self.data.add_modules = {}
self.data.remove_modules = {}
local modules_before = {}
local modules_after = {}
-- generate self.config.modules table
for k, module in pairs(modpol.modules) do
if not modpol.modules[module.slug].hide then
local in_org = false
if self.org.modules[module.slug] then
in_org = true
end
table.insert(
modules_before,
{module.name.." ["..module.slug.."]", in_org})
end
end
-- send query to user
modpol.interactions.checkbox_query(
self.initiator,
"Check the modules to activate in this org:",
modules_before,
function(input)
if input == "Add module" then
self:add_module()
elseif input == "Remove module" then
self:remove_module()
end
end
)
end
function change_modules:add_module()
-- prepare module options
local available_modules = modpol.util.copy_table(modpol.modules)
for k,org_mod in pairs(self.org.modules) do
if available_modules[org_mod.slug] then
available_modules[org_mod.slug] = nil
end end
-- present module options
local modules_list = {}
for k,v in pairs(available_modules) do
table.insert(modules_list,v.name)
end
if #modules_list == 0 then
modpol.interactions.message(
self.initiator, "Org has all modules")
modpol.interactions.org_dashboard(
self.initiator, self.org.id)
if self.data.result then self.data.result() end
self.org:delete_process(self.id)
return
end
table.sort(modules_list)
-- now ask which to add
modpol.interactions.dropdown_query(
self.initiator, "Choose a module to add:",
modules_list,
function(mod_choice)
-- confirm choice
modpol.interactions.binary_poll_user(
self.initiator,
"Confirm: propose to add module \"" ..
mod_choice .. "\"?",
function(input)
if input == "Yes" then
self:propose_change("add",mod_choice)
modpol.interactions.org_dashboard(
self.initiator, self.org.id)
-- identify changes
modules_after = input
for i,v in ipairs(modules_after) do
if v[2] ~= modules_before[i][2] then
if v[2] then
table.insert(self.data.add_modules, v[1])
else
self:add_module()
table.insert(self.data.remove_modules, v[1])
end
end
)
end
)
end
function change_modules:remove_module()
-- prepare module options
local available_modules = {}
for k,org_mod in pairs(self.org.modules) do
if not org_mod.hide then
available_modules[org_mod.slug] = modpol.copy_table(org_mod)
end end
local modules_list = {}
local modules_count = 0
for k,v in pairs(available_modules) do
table.insert(modules_list,v.name)
modules_count = modules_count + 1
end
-- abort if no modules to remove
if modules_count == 0 then
modpol.interactions.message(
self.initiator, "Org has no modules")
modpol.interactions.org_dashboard(
self.initiator, self.org.id)
if self.data.result then self.data.result() end
self.org:delete_process(self.id)
return
end
table.sort(modules_list)
-- now ask which to remove
modpol.interactions.dropdown_query(
self.initiator, "Choose a module to remove:",
modules_list,
function(mod_choice)
-- confirm choice
modpol.interactions.binary_poll_user(
self.initiator,
"Confirm: propose to remove module \"" .. mod_choice .. "\"?",
function(input)
if input == "Yes" then
self:propose_change("remove",mod_choice)
modpol.interactions.org_dashboard(
self.initiator, self.org.id)
else
self:remove_module()
end
end
)
end
)
end
--- propose_change
-- @field type "add" or "remove"
function change_modules:propose_change(type, mod_text)
self.org:call_module(
"consent",self.initiator,
{
prompt = "Do you consent to "..type..
" this module in org "..self.org.name..
":\n"..mod_text,
votes_required = #self.org.members
},
function()
if type == "add" then
for k,v in pairs(modpol.modules) do
if v.name == mod_text then
table.insert(self.org.modules,v)
end
end
modpol.interactions.message_org(
self.initiator,self.org.id,
"Consent reached:\nAdding \""
..mod_text.."\" to org "..self.org.name)
elseif type == "remove" then
modpol.msg("Removing!")
local i = 0
for k,v in pairs(self.org.modules) do
i = i + 1
if v.name == mod_text then
modpol.msg("got it!")
self.org.modules[k] = nil
end
end
modpol.interactions.message_org(
self.initiator,self.org.id,
"Consent reached:\nRemoving \""
..mod_text.."\" from org "..self.org.name)
end
-- abort if no changes
if #self.data.add_modules == 0
and #self.data.remove_modules == 0 then
modpol.interactions.message(
self.initiator, "No module changes proposed")
modpol.interactions.org_dashboard(
self.initiator, self.org.id)
self.org:delete_process(self.id)
return
end
-- proceed with consent
local query = "Accept module changes in org "..
self.org.name.."?"
self.data.summary = ""
if #self.data.add_modules > 0 then
self.data.summary = self.data.summary.."\nAdd: "..
table.concat(self.data.add_modules,", ")
elseif #self.data.remove_modules > 0 then
self.data.summary = "\nRemove: "..
table.concat(self.data.remove_modules,", ")
end
self:call_module(
"consent",
self.initiator,
{
prompt = query..self.data.summary,
votes_required = #self.org.members
},
function()
self:implement_change()
end)
modpol.interactions.org_dashboard(
self.initiator, self.org.id)
end)
end
function change_modules:implement_change()
for i,v in ipairs(self.data.add_modules) do
local slug = string.match(v,"%[(.+)%]")
self.org.modules[slug] =
modpol.util.copy_table(modpol.modules[slug])
table.sort(self.org.modules)
end
for i,v in ipairs(self.data.remove_modules) do
local slug = string.match(v,"%[(.+)%]")
self.org.modules[slug] = nil
table.sort(self.org.modules)
end
-- announce and shut down
modpol.interactions.message_org(
self.initiator,
self.org.id,
"Module changes applied to org "..self.org.name..":"..
self.data.summary)
if self.data.result then self.data.result() end
self.org:delete_process(self.id)
end

View File

@ -2,9 +2,9 @@
-- @module consent
local consent = {
name = "Consent process utility",
name = "Consent process",
slug = "consent",
desc = "A module other modules use for consent decisions",
desc = "A utility module other modules use for consent decisions",
hide = true
}
@ -26,7 +26,7 @@ function consent:initiate(result)
if self.org:get_member_count() == 0 then
if self.data.result then
self.data.result() end
self.org:wipe_pending_actions(self.id)
self.org:delete_process(self.id)
else
-- otherwise, create poll
for id, member in pairs(self.org.members) do
@ -47,14 +47,19 @@ function consent:callback(member)
if resp == "Yes" then
self.data.votes = self.data.votes + 1
end
modpol.interactions.message_org(
"consent", self.org.id,
member.." decided "..resp.." on: "..
self.config.prompt.." ("..self.data.votes..
"/"..self.config.votes_required..")"
)
if self.data.votes >= self.config.votes_required then
if self.data.result then
self.data.result() end
self.org:wipe_pending_actions(self.id)
self.org:delete_process(self.id)
end
modpol.interactions.org_dashboard(
member, self.org.name)
member, self.org.id)
end
)
end

View File

@ -0,0 +1,53 @@
--- create_token
-- @module create_token
-- depends on tokenomics
local create_token = {
name = "Create a token (consent)",
slug = "create_token",
desc = "With org consent, creates an org token",
hide = false;
}
--- (Required) Data for module
-- Variables that module uses during the course of a process
-- Can be blank
create_token.data = {
}
create_token.config = {
token_name = ""
}
--- (Required): initiate function
-- @param result (optional) Callback if this module is embedded in other modules
-- @function initiate
function create_token:initiate(result)
modpol.interactions.text_query(
self.initiator,
"Token name (alpha-numeric, no spaces):",
function(input)
self.config.token_name = input
self:call_module(
"tokenomics",
self.initiator,
{
consent = true,
token_slug = self.config.token_name
},
function(input2)
modpol.interactions.org_dashboard(
self.initiator, self.org.name)
if result then result() end
-- call this wherever process might end:
self.org:delete_process(self.id)
end
)
modpol.interactions.org_dashboard(
self.initiator, self.org.name)
end
)
end
--- (Required) Add to module table
modpol.modules.create_token = create_token

View File

@ -0,0 +1,57 @@
--- defer_consent
-- @module defer_consent
--- (Required): data table containing name and description of the module
-- @field name "Human-readable name (parens OK, no brackets)"
-- @field slug "Same as module class name"
-- @field desc "Description of the module"
-- @field hide "Whether this is a hidden utility module"
local defer_consent = {
name = "Defer consent",
slug = "defer_consent",
desc = "Defers consent on a decision to another org",
hide = true;
}
--- (Required) Data for module
-- Variables that module uses during the course of a process
-- Can be blank
defer_consent.data = {
}
--- (Required): config for module
-- @field defer_org Name or ID of target org
-- @field votes_required Threshold passed on to `consent`
-- @field prompt String passed on to `consent`
defer_consent.config = {
defer_org = "Root",
votes_required = 1,
prompt = "Do you consent?"
}
--- (Required): initiate function
-- @param result (optional) Callback if this module is embedded in other modules
-- @function initiate
function defer_consent:initiate(result)
local defer_org = modpol.orgs.get_org(self.config.defer_org)
if not defer_org then
modpol.interactions.message(
self.initiator, "Target org not found, aborting")
self.org:delete_process(self.id)
else
defer_org:call_module(
"consent", self.initiator,
{
votes_required = self.config.votes_required,
prompt = self.config.prompt
},
function()
if result then result() end
end)
end
if result then result() end
self.org:delete_process(self.id)
end
--- (Required) Add to module table
modpol.modules.defer_consent = defer_consent

View File

@ -0,0 +1,70 @@
--- display_processes
-- @module display_processes
local display_processes = {
name = "Display processes",
slug = "display_processes",
desc = "Presents a detailed list of org processes",
hide = false;
}
--- (Required) Data for module
-- Variables that module uses during the course of a process
-- Can be blank
display_processes.data = {
}
display_processes.config = {
}
--- (Required): initiate function
-- @param result (optional) Callback if this module is embedded in other modules
-- @function initiate
function display_processes:initiate(result)
local display_table = {}
for k,v in pairs(self.org.processes) do
if v ~= "deleted" then
local input = v.id..": "..v.slug
table.insert(display_table, input)
input = "Org: "..v.org.name..
", initiator: "..v.initiator
table.insert(display_table, input)
if v.config
and modpol.util.num_pairs(v.config) > 0 then
table.insert(display_table, "Policies:")
for k2,v2 in pairs(v.config) do
local v2_string = ""
if type(v2) ~= "string"
and type(v2) ~= "table" then
v2_string = tostring(v2)
elseif type(v2) == "table" then
v2_string = tostring(v2)
else
v2_string = "Could not render"
end
input = k2..": "..v2_string
table.insert(display_table, input)
end
end
table.insert(display_table, "\n")
end
end
local output = table.concat(display_table,"\n")
if #display_table == 0 then
output = "No processes found"
end
modpol.interactions.display(
self.initiator,
"Processes in org "..self.org.name,
output,
function()
modpol.interactions.org_dashboard(
self.initiator, self.org.id)
if result then result() end
self.org:delete_process(self.id)
end
)
end
--- (Required) Add to module table
modpol.modules.display_processes = display_processes

View File

@ -28,7 +28,7 @@ function join_org_consent:initiate(result)
self.org:delete_process(self.id)
else
self.data.result = result
self.org:call_module(
self:call_module(
"consent",
self.initiator,
{

View File

@ -0,0 +1,49 @@
--- @module randomizer
-- A utility module that outputs a random result from a set of options
local randomizer = {
name = "Randomizer",
slug = "randomizer",
desc = "A utility module other modules use for random decisions",
hide = true
}
randomizer.data = {
}
-- options_table should be a table of strings
randomizer.config = {
options_table = {},
num_results = 1,
result_table = {}
}
function randomizer:initiate(result)
self.data.result = result
self.data.options_table = modpol.util.copy_table(self.config.options_table)
-- if options table is empty, randomizer returns that
if #self.data.options_table == 0 or self.config.num_results == 0 then
if self.data.result then
self.data.result({}) end
self.org:delete_process(self.id)
else
-- otherwise, choose a random result
self.random_loop()
end
end
-- returns result_table
function randomizer:random_loop()
self.data.results = 0
if results == self.config.num_results then
self.data.result(self.data.result_table)
else
math.randomseed(os.time())
local index = math.random(self.data.options_table)
table.insert(self.data.result_table, self.data.options_table[index])
table.remove(self.data.options_table, index)
self.data.results = self.data.results + 1
end
end
modpol.modules.randomizer = randomizer

View File

@ -42,7 +42,7 @@ function remove_child_consent:initiate(result)
children,
function(input)
self.data.child_to_remove = modpol.orgs.get_org(input)
self.org:call_module(
self:call_module(
"consent",
self.initiator,
{

View File

@ -35,7 +35,7 @@ function remove_member_consent:initiate(result)
self.org.members,
function(input)
self.data.member_to_remove = input
self.org:call_module(
self:call_module(
"consent",
self.initiator,
{

View File

@ -28,14 +28,14 @@ function remove_org_consent:initiate(result)
self.org:delete_process(self.id)
else
self.data.result = result
self.org:call_module(
self:call_module(
"consent",
self.initiator,
{
prompt = "Remove org " .. self.org.name .. "?",
votes_required = #self.org.members
},
function ()
function()
self:complete()
end
)

View File

@ -0,0 +1,113 @@
--- remove_process
-- @module remove_process
local remove_process = {
name = "Remove process",
slug = "remove_process",
desc = "User can remove own processes, consent required for those of others",
hide = false;
}
--- (Required) Data for module
-- Variables that module uses during the course of a process
-- Can be blank
remove_process.data = {
}
remove_process.config = {
}
--- (Required): initiate function
-- @param result (optional) Callback if this module is embedded in other modules
-- @function initiate
function remove_process:initiate(result)
-- prepare process options
local available_processes = {}
for k,process in pairs(self.org.processes) do
if process ~= "deleted" then
available_processes[process.id] = process
end
end
local process_list = {}
local process_count = 0
for k,v in pairs(available_processes) do
local mine = ""
if v.initiator == self.initiator then mine = "*" end
table.insert(process_list,"["..v.id.."] "..v.slug..mine)
process_count = process_count + 1
end
-- abort if no processes to remove
if process_count == 0 then
modpol.interactions.message(
self.initiator, "Org has no modules")
modpol.interactions.org_dashboard(
self.initiator, self.org.id)
if result then result() end
self.org:delete_process(self.id)
return
end
table.sort(process_list)
-- now ask which to remove
modpol.interactions.dropdown_query(
self.initiator, "Choose a process to remove (* marks yours, no consent required):",
process_list,
function(process_choice)
-- confirm choice
local process_id = tonumber(
string.match(process_choice, "%d+"))
local process_mine = string.match(process_choice,
"%*")
modpol.interactions.binary_poll_user(
self.initiator,
"Confirm: Remove process \""..
process_choice .. "\"?",
function(input)
if input == "Yes" then
if process_mine then
self.org:delete_process_tree(process_id)
modpol.interactions.message(
self.initiator,
"Removed process: "..process_choice)
modpol.interactions.org_dashboard(
self.initiator, self.org.id)
if result then result() end
self.org:delete_process(self.id)
else
self:call_module(
"consent",
self.initiator,
{
prompt = "Approve removal of process "..process_choice.."?",
votes_required = #self.org.members
},
function(input)
modpol.interactions.message_org(
self.initiator,
self.org.id,
"Removing process: "..
process_choice)
self.org:delete_process_tree(process_id)
modpol.interactions.org_dashboard(
self.initiator, self.org.id)
if result then result() end
self.org:delete_process(self.id)
end
)
end
modpol.interactions.org_dashboard(
self.initiator, self.org.id)
else
modpol.interactions.org_dashboard(
self.initiator, self.org.id)
if result then result() end
self.org:delete_process(self.id)
end
end
)
end
)
end
--- (Required) Add to module table
modpol.modules.remove_process = remove_process

View File

@ -49,7 +49,7 @@ function rename_org_consent:initiate(result)
"Proposed to change name of org " ..
self.org.name .. " to " .. input)
-- initiate consent process
self.org:call_module(
self:call_module(
"consent",
self.initiator,
{

View File

@ -0,0 +1,77 @@
--- send_token
-- @module send_token
-- depends on tokenomics
local send_token = {
name = "Send tokens",
slug = "send_token",
desc = "Send tokens to another user",
hide = false;
}
--- (Required) Data for module
-- Variables that module uses during the course of a process
-- Can be blank
send_token.data = {
}
send_token.config = {
token_name = ""
}
--- (Required): initiate function
-- @param result (optional) Callback if this module is embedded in other modules
-- @function initiate
function send_token:initiate(result)
local token_list = {}
if self.org.tokens then
for k,v in pairs(self.org.tokens) do
table.insert(token_list, k)
end
end
if token_list == {} then
modpol.interactions.message(
self.initiator,
"No tokens in org")
modpol.interactions.org_dashboard(
self.initiator, self.org.name)
self.org:delete_process(self.id)
return
else
modpol.interactions.dropdown_query(
self.initiator,
"Which token do you want to send?",
token_list,
function(input_token)
modpol.interactions.dropdown_query(
self.initiator,
"Who do you want to send to?",
modpol.util.copy_table(self.org.members),
function(input_recipient)
modpol.interactions.text_query(
self.initiator,
"How much do you want to give (a number)?",
function(input_amount)
modpol.modules.tokenomics.transfer(
self.org.id,
input_token,
self.initiator,
input_recipient,
input_amount
)
modpol.interactions.org_dashboard(
self.initiator, self.org.name)
-- close process
if result then result() end
self.org:delete_process(self.id)
end
)
end
)
end
)
end
end
--- (Required) Add to module table
modpol.modules.send_token = send_token

View File

@ -43,10 +43,13 @@ function module_template:initiate(result)
-- call interaction functions here!
-- concluding functions:
-- call these wherever process might end;
-- first, where appropriate, return users to dashboards.
-- second, result:
-- may need to put result in self.data.result
-- if process ends in another function
-- call this when module is successful (not for abort):
if result then result() end
-- third, delete the process
-- call this wherever process might end:
self.org:delete_process(self.id)
end

View File

@ -0,0 +1,213 @@
--- tokenomics
-- @module tokenomics
-- Depends on consent
local tokenomics = {
name = "Tokenomics",
slug = "tokenomics",
desc = "A simple library for token economics",
hide = true;
}
--- (Required) Data for module
-- Variables that module uses during the course of a process
-- Can be blank
tokenomics.data = {
result = nil
}
--- (Required): config for module
-- @field consent Require consent to create?
-- @field token_variables the data that goes into the token
-- @field token_slug A no-spaces slug for the token
-- @field initial_treasury Quantity in org treasury
-- @field negative_spend Boolean: can users spend negative tokens? (for mutual credit)
-- @field balances Table of user balances
tokenomics.config = {
consent = false,
token_slug = "token",
token_variables = {
treasury = 0,
negative_spend = true,
balances = {}
}
}
--- (Required): initiate function: creates a token in an org
-- set up the token data structure
-- create an org treasury
-- @param result (optional) Callback if this module is embedded in other modules
-- @function initiate
function tokenomics:initiate(result)
-- TODO need to create a series of interactions to get the info from users
self.data.result = result
if self.org.tokens and self.org.tokens[slug] then
modpol.interactions.message(
self.initiator, "Token slug taken, aborting")
self.org:delete_process(self.id)
else
if self.config.consent then
self:call_module(
"consent",
self.initiator,
{
prompt = "Create token "..
self.config.token_slug.."?",
votes_required = #self.org.members
},
function()
modpol.interactions.message_org(
self.initiator, self.org.id,
"Consent reached: creating token "..
self.config.token_slug)
self:create_token()
end
)
else
self:create_token()
end
end
end
function tokenomics:create_token()
if not self.org.tokens then self.org.tokens = {} end
self.org.tokens[self.config.token_slug] =
self.config.token_variables
self.org:record("Created token "..self.config.token_slug,
self.slug)
modpol.interactions.message_org(
self.initiator, self.org.id,
"Created token "..self.config.token_slug)
if self.data.result then self.data.result() end
-- call this wherever process might end:
self.org:delete_process(self.id)
end
-----------------------------------------
-- Utility functions
-- all need to account for the fact that some users may not yet have balances
-- all need to write to persistent data
-- amount can be positive or negative (except transfer)
-- returns balance
-- if no user, get treasury balance
-- @param org Name (string) or id (num)
-- @param token Slug (string)
-- @param user Name (string)
function tokenomics.balance(org, token, user)
local this_org = modpol.orgs.get_org(org)
if not this_org[token] then return nil, "Token not found" end
if not user then
return this_org[token].treasury
end
if not this_org[user] then
return nil, "User not found"
else
local user_balance = this_org[token].balances[user]
if user_balance then
return user_balance
else
return 0
end
end
end
-- @param org Org name (string) or id (number)
-- @param token Token slug (string)
function tokenomics.change_balance(org, token, user, amount)
local this_org = modpol.orgs.get_org(org)
if not this_org then
return nil, "Cannot change balance: Org not found"
elseif not this_org.tokens then
return nil, "Cannot change balance: no tokens found"
elseif not this_org.tokens[token] then
return nil, "Cannot change balance: token not found"
elseif not this_org.members[user] then
return nil, "Cannot change balance: user not in org"
elseif not tonumber(amount) then
return nil, "Cannot change balance: invalid amount"
else
local old_balance = this_org.tokens[token].balances[user]
if not old_balance then old_balance = 0 end
local new_balance = old_balance + amount
this_org.tokens[token].balances[user] = new_balance
local msg = "Your balance of token "..token..
" changed from "..old_balance.." to "..new_balance
modpol.interactions.message(user, msg)
self.org:record(
"Changed token balance for "..user,self.slug)
end
end
-- @param amount Positive number
function tokenomics.transfer(org, token, sender, recipient, amount)
local sender_balance = tokenomics.balance(org, token, sender)
local recipient_balance = tokenomics.balance(org, token, recipient)
if not sender_balance or recipient_balance then
return nil, "Transfer failed, user not found"
else
sender_balance = sender_balance - amount
recipient_balance = recipient_balance + amount
local neg_spend = modpol.orgs.get_org(org).tokens[token].negative_spend
if sender_balance < 0 and not neg_spend then
return nil, "Transfer failed, negative spend not allowed"
else
tokenomics.change_balance(
org, token, sender, sender_balance)
tokenomics.change_balance(
org, token, recipient, recipient_balance)
return "Transfer complete"
end
end
end
-- @param amount Can be positive or negative, assumes flow from treasury to recipient
function tokenomics.treasury_transfer(org, token, recipient, amount)
local this_org = modpol.orgs.get_org(org)
if not this_org then
return nil, "Cannot transfer treasury: Org not found"
elseif not this_org.tokens then
return nil, "Cannot transfer treasury: no tokens found"
elseif not this_org.tokens[token] then
return nil, "Cannot transfer treasury: token not found"
elseif not this_org.members[user] then
return nil, "Cannot transfer treasury: user not in org"
elseif not tonumber(amount) then
return nil, "Cannot change balance: invalid amount"
else
local new_treasury = this_org.tokens[token].treasury - amount
local new_recipient_balance = tokenomics.balance(org, token, recipient) + amount
if new_treasury < 0 and not this_org.tokens[token].negative_spend then
return nil, "Transfer failed, negative spend not allowed"
elseif new_recipient_balance < 0 and not this_org.tokens[token].negative_spend then
return nil, "Transfer failed, negative spend not allowed"
else
this_org.tokens[token].treasury = new_treasury
self.org:record("Treasury payment",self.slug)
tokenomics.change_balance(org, token, recipient, amount)
end
end
end
-- creates new tokens in the org treasury
function tokenomics.issue(org, token, amount)
local this_org = modpol.orgs.get_org(org)
if not this_org then
return nil, "Cannot transfer treasury: Org not found"
elseif not this_org.tokens then
return nil, "Cannot transfer treasury: no tokens found"
elseif not this_org.tokens[token] then
return nil, "Cannot transfer treasury: token not found"
elseif not tonumber(amount) then
return nil, "Cannot change balance: invalid amount"
else
this_org.tokens[token].treasury =
this_org.tokens[token].treasury + amount
self.org:record("Issued tokes to treasury","tokenomics")
end
end
------------------------------------------
--- (Required) Add to module table
modpol.modules.tokenomics = tokenomics