Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PE-6941 add description and keywords #25

Merged
merged 10 commits into from
Oct 22, 2024
2 changes: 1 addition & 1 deletion .github/workflows/ant.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on: [push, workflow_dispatch]

jobs:
unit:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
name: Check out repository code
Expand Down
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,24 @@ Sets the ticker symbol for the ANT.
| Action | string | "Set-Ticker" | true | Action tag for triggering handler |
| Ticker | string | N/A | true | New ticker symbol for ANT. |

#### `Set-Description`

Sets the description for the ANT.

| Tag Name | Type | Pattern | Required | Description |
| ----------- | ------ | ------------------ | -------- | --------------------------------- |
| Action | string | "Set-Description" | true | Action tag for triggering handler |
| Description | string | Max 512 characters | true | New description for ANT. |

#### `Set-Keywords`

Sets the keywords for the ANT.
Copy link
Contributor

Choose a reason for hiding this comment

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

worth mentioned max table size of 16 and min of 1

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated this to include that detail.


| Tag Name | Type | Pattern | Required | Description |
| -------- | ------ | ---------------------------------------------------------------- | -------- | --------------------------------- |
| Action | string | "Set-Keywords" | true | Action tag for triggering handler |
| Keywords | table | "^[%w-_#@]+$", max 32 characters, max 16 keywords, min 1 keyword | true | New keywords for ANT. |

#### `Set-Controller`

Adds a new controller to the ANT.
Expand Down
71 changes: 71 additions & 0 deletions spec/ant_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ local fake_address = "1111111111111111111111111111111111111111111"
local originalState = {
name = "Arweave Name Token",
ticker = "ANT",
description = "ANT's description",
keywords = { "KEYWORD-1", "KEYWORD-2", "KEYWORD-3" },
controllers = { fake_address },
records = { ["@"] = { transactionId = fake_address, ttlSeconds = 900 } },
balances = { [fake_address] = 1 },
Expand All @@ -22,6 +24,8 @@ describe("Arweave Name Token", function()
_G.Controllers = { fake_address }
_G.Name = "Arweave Name Token"
_G.Ticker = "ANT"
_G.Description = "ANT's description"
_G.Keywords = { "KEYWORD-1", "KEYWORD-2", "KEYWORD-3" }
_G.Denomination = 1
end)

Expand All @@ -33,6 +37,8 @@ describe("Arweave Name Token", function()
assert.are.same(_G.Controllers, originalState.controllers)
assert.are.same(_G.Name, originalState.name)
assert.are.same(_G.Ticker, originalState.ticker)
assert.are.same(_G.Description, originalState.description)
assert.are.same(_G.Keywords, originalState.keywords)
end)

it("Transfers tokens between accounts", function()
Expand Down Expand Up @@ -96,4 +102,69 @@ describe("Arweave Name Token", function()

assert.are.same(_G.Ticker, newTicker)
end)

it("sets the description", function()
local newDescription = "NEW DESCRIPTION"
balances.setDescription(newDescription) -- happy path

assert.are.same(_G.Description, newDescription)
end)

it("sets the keywords", function()
local newKeywords = { "NEW-KEYWORD-1", "NEW-KEYWORD-2", "NEW-KEYWORD-3" }
balances.setKeywords(newKeywords) -- setKeywords now handles JSON string

assert.are.same(_G.Keywords, newKeywords)
end)

-- Test when too many keywords are provided
it("throws an error if keywords exceed 16 elements", function()
local tooManyKeywords = {}
for i = 1, 17 do -- 17 keywords, exceeds limit
table.insert(tooManyKeywords, "keyword" .. i)
end
assert.has_error(function()
balances.setKeywords(tooManyKeywords)
end, "There must not be more than 16 keywords")
end)

-- Test when any keyword is too long
it("throws an error if any keyword is too long", function()
local keywordsWithLongEntry = { "valid", string.rep("a", 33) } -- Second keyword is 33 characters long
assert.has_error(function()
balances.setKeywords(keywordsWithLongEntry)
end, "Each keyword must not be longer than 32 characters")
end)

-- Test when any keyword contains spaces
it("throws an error if any keyword contains spaces", function()
local keywordsWithSpace = { "valid", "invalid keyword" } -- Contains a space
assert.has_error(function()
balances.setKeywords(keywordsWithSpace)
end, "Keywords must not contain spaces")
end)

-- Test when keywords contain invalid characters
it("throws an error if keywords contain invalid characters", function()
local keywordsWithSpecialChars = { "valid", "inva!lid" } -- Contains special character '!'
assert.has_error(function()
balances.setKeywords(keywordsWithSpecialChars)
end, "Keywords must only contain alphanumeric characters, dashes, underscores, #, or @")
end)

-- Test when any keyword is duplicated
it("throws an error if any keyword is duplicated", function()
local keywordsWithDuplicates = { "keyword", "keyword" } -- Duplicate keyword
assert.has_error(function()
balances.setKeywords(keywordsWithDuplicates)
end, "Duplicate keyword detected: keyword")
end)

-- Test when the keywords array is not actually an array
it("throws an error if the keywords array is not actually an array", function()
local notAnArray = "not-an-array"
assert.has_error(function()
balances.setKeywords(notAnArray)
end, "Keywords must be an array")
end)
end)
14 changes: 14 additions & 0 deletions src/common/balances.lua
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,18 @@ function balances.setTicker(ticker)
return json.encode({ ticker = Ticker })
end

function balances.setDescription(description)
assert(type(description) == "string", "Description must be a string")
assert(#description <= 512, "Description must not be longer than 512 characters")
Description = description
return json.encode({ description = Description })
end

function balances.setKeywords(keywords)
utils.validateKeywords(keywords)

Keywords = keywords
return json.encode({ keywords = Keywords })
end

return balances
10 changes: 10 additions & 0 deletions src/common/initialize.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ function initialize.initializeANTState(state)
local records = encoded.records
local name = encoded.name
local ticker = encoded.ticker
local description = encoded.description
local keywords = encoded.keywords
local owner = encoded.owner
assert(type(name) == "string", "name must be a string")
assert(type(ticker) == "string", "ticker must be a string")
assert(type(description) == "string", "description must be a string")
assert(#description <= 512, "Description must not be longer than 512 characters")
assert(type(balances) == "table", "balances must be a table")
for k, v in pairs(balances) do
balances[k] = tonumber(v)
Expand All @@ -26,8 +30,12 @@ function initialize.initializeANTState(state)
utils.validateTTLSeconds(v.ttlSeconds)
end

utils.validateKeywords(keywords)

Name = name
Ticker = ticker
Description = description
Keywords = keywords
Balances = balances
Controllers = controllers
Records = records
Expand All @@ -37,6 +45,8 @@ function initialize.initializeANTState(state)
return json.encode({
name = Name,
ticker = Ticker,
description = Description,
keywords = Keywords,
balances = Balances,
controllers = Controllers,
records = Records,
Expand Down
75 changes: 75 additions & 0 deletions src/common/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ function ant.init()
Name = Name or "Arweave Name Token"
Ticker = Ticker or "ANT"
Logo = Logo or "Sie_26dvgyok0PZD_-iQAFOhOd5YxDTkczOLoqTTL_A"
Description = Description or "A brief description of this ANT."
Keywords = Keywords or {}
Denomination = Denomination or 0
TotalSupply = TotalSupply or 1
Initialized = Initialized or false
Expand All @@ -34,6 +36,8 @@ function ant.init()
RemoveRecord = "Remove-Record",
SetName = "Set-Name",
SetTicker = "Set-Ticker",
SetDescription = "Set-Description",
SetKeywords = "Set-Keywords",
--- initialization method for bootstrapping the contract from other platforms ---
InitializeState = "Initialize-State",
-- read
Expand Down Expand Up @@ -160,6 +164,8 @@ function ant.init()
Ticker = Ticker,
["Total-Supply"] = tostring(TotalSupply),
Logo = Logo,
Description = Description,
Keywords = Keywords,
Denomination = tostring(Denomination),
Owner = Owner,
Handlers = utils.getHandlerNames(Handlers),
Expand Down Expand Up @@ -392,6 +398,75 @@ function ant.init()
ao.send({ Target = msg.From, Action = "Set-Ticker-Notice", Data = tickerRes })
end)

Handlers.add(
camel(ActionMap.SetDescription),
utils.hasMatchingTag("Action", ActionMap.SetDescription),
function(msg)
local assertHasPermission, permissionErr = pcall(utils.assertHasPermission, msg.From)
if assertHasPermission == false then
return ao.send({
Target = msg.From,
Action = "Invalid-Set-Description-Notice",
Data = permissionErr,
Error = "Set-Description-Error",
["Message-Id"] = msg.Id,
})
end
local descriptionStatus, descriptionRes = pcall(balances.setDescription, msg.Tags.Description)
if not descriptionStatus then
ao.send({
Target = msg.From,
Action = "Invalid-Set-Description-Notice",
Data = descriptionRes,
Error = "Set-Description-Error",
["Message-Id"] = msg.Id,
})
return
end

ao.send({ Target = msg.From, Action = "Set-Description-Notice", Data = descriptionRes })
end
)

Handlers.add(camel(ActionMap.SetKeywords), utils.hasMatchingTag("Action", ActionMap.SetKeywords), function(msg)
local assertHasPermission, permissionErr = pcall(utils.assertHasPermission, msg.From)
if assertHasPermission == false then
return ao.send({
Target = msg.From,
Action = "Invalid-Set-Keywords-Notice",
Data = permissionErr,
Error = "Set-Keywords-Error",
["Message-Id"] = msg.Id,
})
end

-- Decode JSON from the tag
local success, keywords = pcall(json.decode, msg.Tags.Keywords)
if not success or type(keywords) ~= "table" then
return ao.send({
Target = msg.From,
Action = "Invalid-Set-Keywords-Notice",
Data = "Invalid JSON format for keywords",
Error = "Set-Keywords-Error",
["Message-Id"] = msg.Id,
})
end

local keywordsStatus, keywordsRes = pcall(balances.setKeywords, keywords)
if not keywordsStatus then
ao.send({
Target = msg.From,
Action = "Invalid-Set-Keywords-Notice",
Data = keywordsRes,
Error = "Set-Keywords-Error",
["Message-Id"] = msg.Id,
})
return
end

ao.send({ Target = msg.From, Action = "Set-Keywords-Notice", Data = keywordsRes })
end)

Handlers.add(
camel(ActionMap.InitializeState),
utils.hasMatchingTag("Action", ActionMap.InitializeState),
Expand Down
22 changes: 22 additions & 0 deletions src/common/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,8 @@ function utils.notices.notifyState(msg, target)
Name = Name,
Ticker = Ticker,
Logo = Logo,
Description = Description,
Keywords = Keywords,
Denomination = Denomination,
TotalSupply = TotalSupply,
Initialized = Initialized,
Expand All @@ -340,4 +342,24 @@ function utils.getHandlerNames(handlers)
return names
end

function utils.validateKeywords(keywords)
assert(type(keywords) == "table", "Keywords must be an array")
assert(#keywords <= 16, "There must not be more than 16 keywords")

local seenKeywords = {} -- Table to track seen keywords

for _, keyword in ipairs(keywords) do
assert(type(keyword) == "string", "Each keyword must be a string")
assert(#keyword <= 32, "Each keyword must not be longer than 32 characters")
assert(not keyword:find("%s"), "Keywords must not contain spaces")
assert(
keyword:match("^[%w-_#@]+$"),
"Keywords must only contain alphanumeric characters, dashes, underscores, #, or @"
)
-- Check for duplicates
assert(not seenKeywords[keyword], "Duplicate keyword detected: " .. keyword)
seenKeywords[keyword] = true
end
end

return utils
Loading
Loading