Skip to content

Commit

Permalink
chore: auto validate read-only calls (vechain#161)
Browse files Browse the repository at this point in the history
* chore: auto validate read-only calls

* feat: auto add name, decimals and symbol

* fix: validate provided info

* revert readme

* Update README.md

* Update script.js

* Update contract.js

---------

Co-authored-by: libotony <[email protected]>
  • Loading branch information
darrenvechain and libotony authored Apr 4, 2024
1 parent b6a9721 commit d1174ee
Show file tree
Hide file tree
Showing 18 changed files with 305 additions and 50 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ Token-registry is a platform where you can submit the token. Token-registry will
## Requirements
1. Make sure the contract address is correct (main/test)
2. Token image is required
3. Folder name must be the same as the contract address
4. Clear and simple description
3. Folder name must be the same as the contract address in lowercase
4. Clear and simple description
5. Comply with directory & contents rules

## Getting Ready for Submission
Expand Down
178 changes: 178 additions & 0 deletions abis.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
const totalSupply = {
constant: true,
inputs: [],
name: "totalSupply",
outputs: [
{
name: "",
type: "uint256",
},
],
payable: false,
stateMutability: "view",
type: "function",
};

const balanceOf = {
constant: true,
inputs: [
{
name: "_owner",
type: "address",
},
],
name: "balanceOf",
outputs: [
{
name: "balance",
type: "uint256",
},
],
payable: false,
stateMutability: "view",
type: "function",
};

const allowance = {
constant: true,
inputs: [
{
name: "_owner",
type: "address",
},
{
name: "_spender",
type: "address",
},
],
name: "allowance",
outputs: [
{
name: "remaining",
type: "uint256",
},
],
payable: false,
stateMutability: "view",
type: "function",
};

const decimals = {
constant: true,
inputs: [],
name: "decimals",
outputs: [
{
name: "",
type: "uint8",
},
],
payable: false,
stateMutability: "view",
type: "function",
};

const name = {
constant: true,
inputs: [],
name: "name",
outputs: [
{
name: "",
type: "string",
},
],
payable: false,
stateMutability: "view",
type: "function",
};

const symbol = {
constant: true,
inputs: [],
name: "symbol",
outputs: [
{
name: "",
type: "string",
},
],
payable: false,
stateMutability: "view",
type: "function",
};

const transfer = {
constant: false,
inputs: [
{
name: "_to",
type: "address",
},
{
name: "_value",
type: "uint256",
},
],
name: "transfer",
outputs: [],
payable: false,
stateMutability: "nonpayable",
type: "function",
};

const transferFrom = {
constant: false,
inputs: [
{
name: "_from",
type: "address",
},
{
name: "_to",
type: "address",
},
{
name: "_value",
type: "uint256",
},
],
name: "transferFrom",
outputs: [],
payable: false,
stateMutability: "nonpayable",
type: "function",
};

const approve = {
constant: false,
inputs: [
{
name: "_spender",
type: "address",
},
{
name: "_value",
type: "uint256",
},
],
name: "approve",
outputs: [],
payable: false,
stateMutability: "nonpayable",
type: "function",
};

const abis = {
totalSupply,
balanceOf,
allowance,
decimals,
name,
symbol,
transfer,
transferFrom,
approve,
};

module.exports = abis;
86 changes: 86 additions & 0 deletions contract.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
const abis = require("./abis");
const { abi, address } = require("thor-devkit");
const axios = require("axios");

const totalSupplyAbi = new abi.Function(abis.totalSupply);
const balanceOfAbi = new abi.Function(abis.balanceOf);
const allowanceAbi = new abi.Function(abis.allowance);
const decimalsAbi = new abi.Function(abis.decimals);
const nameAbi = new abi.Function(abis.name);
const symbolAbi = new abi.Function(abis.symbol);

const verifyCalls = [
balanceOfAbi.encode("0xf077b491b355E64048cE21E3A6Fc4751eEeA77fa"),
allowanceAbi.encode(
"0xf077b491b355E64048cE21E3A6Fc4751eEeA77fa",
"0x435933c8064b4Ae76bE665428e0307eF2cCFBD68",
),
];
const verifyContract = async (address, url) => {
try {
const clauses = verifyCalls.map((data) => ({
to: address,
data,
value: "0x0",
}));

const resp = await axios.post(`${url}/accounts/*`, {
clauses,
});

if (resp.data.some((r) => r.reverted)) {
throw new Error("Some contract calls reverted");
}

if (resp.data.length !== verifyCalls.length) {
throw new Error("Invalid contract response");
}
} catch (error) {
console.log(error);
throw new Error("unable to verify contract methods");
}
};

const contractDetailsClauses = [
totalSupplyAbi.encode(),
decimalsAbi.encode(),
nameAbi.encode(),
symbolAbi.encode(),
];

const getContractDetails = async (address, url) => {
const clauses = contractDetailsClauses.map((data) => ({
to: address,
data,
value: "0x0",
}));

const resp = await axios.post(`${url}/accounts/*`, {
clauses,
});

if (resp.data.some((r) => r.reverted)) {
throw new Error("Some contract calls reverted");
}

if (resp.data.length !== contractDetailsClauses.length) {
throw new Error("Invalid contract response");
}

const totalSupply = totalSupplyAbi.decode(resp.data[0].data);
const decimals = decimalsAbi.decode(resp.data[1].data);
const name = nameAbi.decode(resp.data[2].data);
const symbol = symbolAbi.decode(resp.data[3].data);

return {
totalSupply: totalSupply["0"],
decimals: parseInt(decimals["0"]),
name: name["0"],
symbol: symbol["0"],
};
};

module.exports = {
verifyContract,
getContractDetails,
};
59 changes: 25 additions & 34 deletions script.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const { abi } = require('thor-devkit')
const { getTokens, redFont, greenFont, yellowFont } = require('./utils')

const { NETS: NET_FOLDERS, NODES } = require('./const')
const abis = require('./abis')
const { verifyContract, getContractDetails } = require('./contract')

const DIST = path.join(__dirname, './dist')
const ASSETS = path.join(DIST, 'assets')
Expand Down Expand Up @@ -52,16 +54,34 @@ async function packToken(net) {

file.mkdirSync(ASSETS)

for (const item of listJson) {
for (let i = 0; i < listJson.length; i++) {
const item = listJson[i]

const {
name,
symbol,
decimals,
totalSupply
} = await getContractDetails(item.address, NODES[net])

if (name !== item.name)
throw new Error(`name does not match contract name (info=${item.name}, contract=${name})`)
if (symbol !== item.symbol)
throw new Error(`symbol does not match contract symbol (info=${item.symbol}, contract=${symbol})`)
if (decimals !== item.decimals)
throw new Error(`decimals does not match contract decimals (info=${item.decimals}, contract=${decimals})`)

await verifyContract(item.address, NODES[net])

file.copyFileSync(item.img, path.join(ASSETS, `${item.imgName}`))
result.push({
name: item.name,
symbol: item.symbol,
decimals: item.decimals,
name,
symbol,
decimals,
address: item.address,
desc: item.desc,
icon: item.imgName,
totalSupply: item.symbol === 'VTHO' ? 'Infinite' : await getTotalSupply(NODES[net], item.address),
totalSupply: item.symbol === 'VTHO' ? 'Infinite' : totalSupply,
...item.extra
})
}
Expand Down Expand Up @@ -172,35 +192,6 @@ async function getCreateTimeFromGit(dirPath) {
})
})
}
const TSabi = {
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
}
async function getTotalSupply(url, address) {
const resp = await axios.post(`${url}/accounts/*`, {
clauses: [
{
to: address,
value: '0',
data: '0x18160ddd'
}
]
})
let tsf = new abi.Function(TSabi)
const decoded = tsf.decode(resp.data[0]['data'])

return decoded[0]
}

module.exports = {
clean: clear,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "OceanEx",
"name": "OceanEx Token",
"symbol": "OCE",
"decimals": 18,
"desc": "OceanEx Token (OCE) is OceanEx's platform token"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "Decent.bet",
"name": "Decent.bet Token",
"symbol": "DBET",
"decimals": 18,
"desc": "DECENT.bet is an open-source p2p gaming platform built on the VeChain blockchain"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "UNION token",
"name": "UNION",
"symbol": "UNION",
"decimals":18,
"desc": "Utility token for NoNerdsInc"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "Jur",
"name": "JUR",
"symbol": "JUR",
"decimals": 18,
"desc": "JUR Token is the token of justice. Access a decentralized legal ecosystem for professionals and enterprises."
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "Safe Haven",
"name": "Safe Haven Token",
"symbol": "SHA",
"decimals": 18,
"desc": "Asset Management & Inheritance Solutions"
Expand Down
Loading

0 comments on commit d1174ee

Please sign in to comment.