Skip to content

Commit

Permalink
feat: AO plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
ppedziwiatr committed Mar 29, 2024
1 parent e969a7b commit 29f1591
Show file tree
Hide file tree
Showing 48 changed files with 161,300 additions and 2,118 deletions.
147,191 changes: 147,191 additions & 0 deletions .yarn/releases/yarn-1.19.0.cjs

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions .yarnrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


yarn-path ".yarn/releases/yarn-1.19.0.cjs"
109 changes: 109 additions & 0 deletions examples/data/ao.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
function handle(state, message) {
if (!state.hasOwnProperty('balances')) {
state.balances = {};
state.balances[ao.id] = 100000000000000;
}

if (state.name != 'Points Coin') {
state.name = 'Points Coin';
}

if (state.ticker != 'Points') {
state.ticker == 'PNTS';
}

if (state.denomination != 10) {
state.denomination = 10;
}

if (!state.hasOwnProperty('logo')) {
state.logo = 'SBCCXwwecBlDqRLUjb8dYABExTJXLieawf7m2aBJ-KY';
}

if (message.tags['Action'] == 'info') {
ao.result({
target: ao.id,
tags: {
name: state.name,
ticker: state.ticker,
logo: state.logo,
denomination: state.denomination.toString(),
},
});
return;
}

if (message.tags['Action'] == 'balances') {
ao.result({
target: ao.id,
data: state.balances,
});
return;
}

if (message.tags['Action'] == 'transfer') {
if (typeof message.tags['Recipient'] != 'string') {
throw new ProcessError('Recipient is required!');
}

if (typeof message.tags['Quantity'] != 'string') {
throw new ProcessError('Quantity is required!');
}

if (!state.balances[message.from]) {
state.balances[message.from] = 0;
}

if (!state.balances[message.tags['Recipient']]) {
state.balances[message.tags['Recipient']] = 0;
}

const qty = Number(message.tags['Quantity']);
if (!qty) {
throw new ProcessError('qty must must be a number');
}

if (state.balances[message.from] >= qty) {
state.balances[message.from] = state.balances[message.from] - qty;
state.balances[message.tags['Recipient']] =
state.balances[message.tags['Recipient']] + qty;

if (!message.tags['Cast']) {
ao.send({
target: message.from,
tags: [
{ name: 'Action', value: 'Debit-Notice' },
{ name: 'Recipient', value: message.tags['Recipient'] },
{ name: 'Quantity', value: qty.toString() },
],
});

ao.send({
target: message.from,
tags: [
{ name: 'Action', value: 'Credit-Notice' },
{ name: 'Sender', value: message.tags['Recipient'] },
{ name: 'Quantity', value: qty.toString() },
],
});

return;
}

return;
} else {
ao.send({
target: message.from,
tags: [
{ name: 'Action', value: 'Transfer-Error' },
{ name: 'MessageId', value: message.id },
{ name: 'Error', value: 'Insufficient balance' },
],
});

return;
}
}

throw new ProcessError('unknown action');
}
139 changes: 139 additions & 0 deletions examples/data/ao.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
--[[
This module implements the ao Standard Token Specification.
Terms:
Sender: the wallet or Process that sent the Message
It will first initialize the internal state, and then attach handlers,
according to the ao Standard Token Spec API:
- Info(): return the token parameters, like Name, Ticker, Logo, and Denomination
- Balance(Target?: string): return the token balance of the Target. If Target is not provided, the Sender
is assumed to be the Target
- Balances(): return the token balance of all participants
- Transfer(Target: string, Quantity: number): if the Sender has a sufficient balance, send the specified Quantity
to the Target. It will also issue a Credit-Notice to the Target and a Debit-Notice to the Sender
- Mint(Quantity: number): if the Sender matches the Process Owner, then mint the desired Quantity of tokens, adding
them the Processes' balance
]] --
local json = require('json')

--[[
Initialize State
ao.id is equal to the Process.Id
]] --
if not Balances then Balances = { [ao.id] = 100000000000000 } end

if Name ~= 'Points Coin' then Name = 'Points Coin' end

if Ticker ~= 'Points' then Ticker = 'PNTS' end

if Denomination ~= 10 then Denomination = 10 end

if not Logo then Logo = 'SBCCXwwecBlDqRLUjb8dYABExTJXLieawf7m2aBJ-KY' end

--[[
Add handlers for each incoming Action defined by the ao Standard Token Specification
]] --

--[[
Info
]] --
handlers.add('info', handlers.utils.hasMatchingTag('Action', 'Info'), function(msg)
ao.send(
{ Target = msg.From, Tags = { Name = Name, Ticker = Ticker, Logo = Logo, Denomination = tostring(Denomination) } })
end)

--[[
Balance
]] --
handlers.add('balance', handlers.utils.hasMatchingTag('Action', 'Balance'), function(msg)
local bal = '0'

-- If not Target is provided, then return the Senders balance
if (msg.Tags.Target and Balances[msg.Tags.Target]) then
bal = tostring(Balances[msg.Tags.Target])
elseif Balances[msg.From] then
bal = tostring(Balances[msg.From])
end

ao.send({
Target = msg.From,
Tags = { Target = msg.From, Balance = bal, Ticker = Ticker, Data = json.encode(tonumber(bal)) }
})
end)

--[[
Balances
]] --
handlers.add('balances', handlers.utils.hasMatchingTag('Action', 'Balances'),
function(msg) ao.send({ Target = msg.From, Data = json.encode(Balances) }) end)

--[[
Transfer
]] --
handlers.add('transfer', handlers.utils.hasMatchingTag('Action', 'Transfer'), function(msg)
assert(type(msg.Tags.Recipient) == 'string', 'Recipient is required!')
assert(type(msg.Tags.Quantity) == 'string', 'Quantity is required!')

if not Balances[msg.From] then Balances[msg.From] = 0 end

if not Balances[msg.Tags.Recipient] then Balances[msg.Tags.Recipient] = 0 end

local qty = tonumber(msg.Tags.Quantity)
assert(type(qty) == 'number', 'qty must be number')

if Balances[msg.From] >= qty then
Balances[msg.From] = Balances[msg.From] - qty
Balances[msg.Tags.Recipient] = Balances[msg.Tags.Recipient] + qty

--[[
Only send the notifications to the Sender and Recipient
if the Cast tag is not set on the Transfer message
]] --
if not msg.Tags.Cast then
-- Send Debit-Notice to the Sender
ao.send({
Target = msg.From,
Tags = { Action = 'Debit-Notice', Recipient = msg.Tags.Recipient, Quantity = tostring(qty) }
})
-- Send Credit-Notice to the Recipient
ao.send({
Target = msg.Tags.Recipient,
Tags = { Action = 'Credit-Notice', Sender = msg.From, Quantity = tostring(qty) }
})
end
else
ao.send({
Target = msg.Tags.From,
Tags = { Action = 'Transfer-Error', ['Message-Id'] = msg.Id, Error = 'Insufficient Balance!' }
})
end
end)

--[[
Mint
]] --
handlers.add('mint', handlers.utils.hasMatchingTag('Action', 'Mint'), function(msg, env)
assert(type(msg.Tags.Quantity) == 'string', 'Quantity is required!')

if msg.From == env.Process.Id then
-- Add tokens to the token pool, according to Quantity
local qty = tonumber(msg.Tags.Quantity)
Balances[env.Process.Id] = Balances[env.Process.Id] + qty
else
ao.send({
Target = msg.Tags.From,
Tags = {
Action = 'Mint-Error',
['Message-Id'] = msg.Id,
Error = 'Only the Process Owner can mint new ' .. Ticker .. ' tokens!'
}
})
end
end)
22 changes: 22 additions & 0 deletions examples/data/counter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
function handle(state, message) {
console.log('handle', message, state);
const { input } = message;

if (!state.hasOwnProperty('counter')) {
state.counter = 0;
}

if (input.function == 'increment') {
console.log('inside increment', state.counter);
state.counter++;
return;
}

if (input.function == 'currentValue') {
return {
result: state.counter,
};
}

throw new ProcessError('unknown action');
}
38 changes: 24 additions & 14 deletions examples/deploy/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,16 @@ import Arweave from 'arweave';
import fs from 'fs';
import path from 'path';
import { JWKInterface } from 'arweave/node/lib/wallet';
import { DeployPlugin, ArweaveSigner, EthereumSigner } from 'warp-contracts-plugin-deploy';
import { defaultCacheOptions, LoggerFactory, WarpFactory } from 'warp-contracts';
import {
DeployPlugin,
ArweaveSigner,
EthereumSigner,
} from 'warp-contracts-plugin-deploy';
import {
defaultCacheOptions,
LoggerFactory,
WarpFactory,
} from 'warp-contracts';

async function main() {
let wallet: JWKInterface = readJSON('.secrets/jwk.json');
Expand All @@ -19,21 +27,23 @@ async function main() {
});

try {
const warp = WarpFactory.forMainnet({ ...defaultCacheOptions, inMemory: true }).use(new DeployPlugin());
const warp = WarpFactory.forMainnet({
...defaultCacheOptions,
inMemory: true,
}).use(new DeployPlugin());

const jsContractSrc = fs.readFileSync(path.join(__dirname, '../data/token-pst.js'), 'utf8');
const wasmContractSrc = fs.readFileSync(path.join(__dirname, '../data/rust/rust-pst_bg.wasm'));
const jsContractSrc = fs.readFileSync(
path.join(__dirname, '../data/counter.js'),
'utf8'
);
const wasmContractSrc = fs.readFileSync(
path.join(__dirname, '../data/rust/rust-pst_bg.wasm')
);
const walletAddress = await warp.arweave.wallets.jwkToAddress(wallet);
const initialState = {
ticker: 'EXAMPLE_PST_TOKEN',
owner: 'uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M',
canEvolve: true,
balances: {
'uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M': 10000000,
'33F0QHcb22W7LwWR1iRC8Az1ntZG09XQ03YWuw2ABqA': 23111222,
[walletAddress]: 1000000,
},
wallets: {},
name: 'test',
ticker: 'test ticker',
logo: 'test',
};

// case 1 - full deploy, js contract
Expand Down
10 changes: 4 additions & 6 deletions warp-contracts-plugin-ethers/.eslintrc
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint",
"prettier"
],
"plugins": ["@typescript-eslint", "prettier"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"rules": {
"no-console": 1, // warning
"no-console": 1, // warning
"multiline-ternary": "off",
"no-nested-ternary": "error",
"no-multiple-empty-lines": "off",
"prettier/prettier": 2 // error
"prettier/prettier": 2, // error
"@typescript-eslint/no-explicit-any": "off"
}
}
10 changes: 2 additions & 8 deletions warp-contracts-plugin-ethers/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,11 @@
"outDir": "./lib/cjs",
"isolatedModules": false,
"esModuleInterop": true,
"suppressImplicitAnyIndexErrors": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"baseUrl": "./src",
"allowJs": true,
"allowJs": true
},
"include": ["src"],
"exclude": [
"node_modules",
"tools",
"**/__tests__/*",
"_scripts"
]
"exclude": ["node_modules", "tools", "**/__tests__/*", "_scripts"]
}
3 changes: 3 additions & 0 deletions warp-contracts-plugin-quickjs/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
lib
src/__tests__/integration/data
Loading

0 comments on commit 29f1591

Please sign in to comment.