CTO linkcard.app 💸 Web3 Researcher & Investor
CTO linkcard.app 💸 Web3 Researcher & Investor

Subscribe to Fabrizio G

Subscribe to Fabrizio G
Share Dialog
Share Dialog


<100 subscribers
<100 subscribers
Managing a gaming guild with many scholars can be a challenging operational task given that we need to manage a lot of valuable assets (tokens and axies) and at the same time worry about security of our private keys which makes it impossible to give access to collaborators without delegating control of the assets.
We are going to be interacting with RONIN blockchain through the Web3js library. We are going to create a discord bot that interprets wallets via their aliases and then verifies discord user’s privileges to run different commands like claims, transfers and reading information.
What we will learn:
Set up discord bot
Obtain SLP balance
Get information about a scholar
Transfer axies
Transfer tokens
Claim SLP
Get discord application token
First we need to create a discord application for interacting with our bot. We can read discord documentation. After that we can get out TOKEN what we will be using for running our bot on localhost

After that we need to create a /Data/config.json file inside the Data folder of the repo and inside it copy our token. You cannot share this token with anyone so protect it and that’s why I hide it in the .gitignore so you can’t commit it to git.
{
"token": "DISCORD_TOKEN",
"prefix": "!"
}
Find the contract ABI’s
For managing different assets in the ronin blockchain we are going to need 2 ABI. One for the tokens and one for the Axies. There may be others for land or other assets but not needed in the context of this tutorial.
Ronin is an Ethereum sidechain, it’s EVM compatible and uses the same standard ERC20 for its tokens. We ERC20 ABI to manage AXS, SLP, WETH or RON. For managing AXIES, the contract is not fully compliant with the ERC721 standard. This is because it was deployed before the standard had become finalized.

Still we can get the ABI which we can get from the contract creator and still has all the needed methods. This ABI’s are already in the repo witch filenames axie_abi.json and token_abi.json
Setting up wallet aliases
First we need to create a secrets.json file containing all our private keys, each one with its own descriptive alias. This alias may be a number or a descriptive name we use in our wallets. For example main wallet could be were we make the breeding of axies or were we store high value assets.
DO NOT SHARE THIS PRIVATE KEYS EVER.
{
"breed_old": "PRIVATE KEY",
"buenos": "PRIVATE KEY",
"main":"PRIVATE KEY",
"acc2": "PRIVATE KEY",
"acc_admin": "PRIVATE KEY",
"acc_tri": "PRIVATE KEY",
"account1": "PRIVATE KEY",
"account2": "PRIVATE KEY",
"account3": "PRIVATE KEY",
"account69": "PRIVATE KEY"
}
Once we have our secrets file ready we can star writing and running commands by only mentioning this aliases instead of the public keys. For example for transferring certain axie from one account to another should be very easy!
async getWalletByAlias(alias){
let from_private = secrets[alias]
const web3 = await new Web3(new Web3.providers.HttpProvider(RONIN_PROVIDER_FREE));
if(from_private){
const signer = web3.eth.accounts.privateKeyToAccount(from_private)
let wallet=signer.address//.replace('0x','ronin:')
return wallet
}
return false
}
!transfer axie_123 account1 account2
Set up roles
Through discord, we are going to allow other collaborators of the guild to manage Ronin assets. We only need to protect the private keys by uploading them to a private server. After these are done we can allow certain roles in discord to run certain commands.
For the example we are going to create the Manager role in discord and then get the ID on Server settings → Roles

Then we can call a method that verifies the Role of the incoming message to see if allows the command to execute or not.
isManager:function(message){
if(message.author.bot)return true
let r1=message.guild.roles.cache.find(r => r.name === "Manager")
//we can also filter with channel names using message.channel.name
if(r1 && message.member.roles.cache.has(r1.id))return true
return false
}
2- Obtain SLP balance
Let’s start with the commands. We are going to start simple by checking the token balances of a wallet, for example of main wallet.

We first need to identify which token or assets we need to check the balance of and then identify the contract address
const web3 = await new Web3(new Web3.providers.HttpProvider(RONIN_PROVIDER));
from_acc=await this.getWalletByAlias(from_acc)
let contract_add=''
if(token == 'slp') contract_add = SLP_CONTRACT
else if(token == 'axs') contract_add = AXS_CONTRACT
else if(token == "axies")contract_add = AXIE_CONTRACT
else if(token == "weth")contract_add = WETH_CONTRACT
else if(token == "ron") return await web3.eth.getBalance(from_acc)
else return message.channel.send("Message send")
let contract = new web3.eth.Contract(token_abi,web3.utils.toChecksumAddress(contract_add))
let balance = await contract.methods.balanceOf( web3.utils.toChecksumAddress(from_acc)).call()
4- Get information about a scholar
With the command report we can get information about SLP, MMR, list the Axies and much more.

For this to work we need to check out Axie Infinity API’s which we can found on their discord server.
getSLP:async function(from_acc,message=null,cache=false){
try{
let data={}
let url = "https://game-api.axie.technology/api/v2/"+from_acc.replace('0x','ronin:') ;
data= await fetch(url, { method: "Get" }).then(res => res.json()).then((json) => { return json});
return data
}catch(e){
this.log("ERROR: "+e.message,message)
}
}
Also using GraphQL we can get the information about the particular Axies inside the wallet
getAxiesIds:async function (wallet){
if(!wallet)return
wallet=wallet.replace('ronin:','0x')
let url = `https://graphql-gateway.axieinfinity.com/graphql`;
let query = `
{
"operationName": "GetAxieBriefList",
"variables": {
"owner":"${wallet}"
},
"query": "query GetAxieBriefList($auctionType: AuctionType, $criteria: AxieSearchCriteria, $from: Int, $sort: SortBy, $size: Int, $owner: String) { axies(auctionType: $auctionType, criteria: $criteria, from: $from, sort: $sort, size: $size, owner: $owner) { total results { ...AxieBrief __typename } __typename }}fragment AxieBrief on Axie { id name stage class breedCount image title battleInfo { banned __typename } auction { currentPrice currentPriceUSD __typename } parts { id name class type specialGenes __typename } __typename}"
}`
let response=await fetch(url, { method: 'post',headers: { 'Content-Type': 'application/json'},body: JSON.stringify(JSON.parse(query))}).then(response => response.json()).then(data => { return data});
if(!response || !response.data || !response.data.axies)return null
let dev= {count:response.data.axies.total,axies:response.data.axies.results}
return dev
}
4- Transfer axies
Now we are going to start with riskier commands like transfers. It is very important that we understand the security risks and implications of allowing this type of commands. For security, we are going to use 2 filters.
Using each discord message object we are going to check if corresponds with the Manager role we defined before. If not, the command will return error.
if(!utils.isManager(message))return message.channel.send("You don't have the propper rights to run this command.")
Also, we are going to check the wallet where the transfer is destined to go. If we only allow transfers between our own wallets then we can protect from thief.
if(!this.isSafe(from_acc) || !this.isSafe(to_acc))return message.channel.send(`Incorrect alias/wallet, this wallet doesn't look like your own!`);
Finally, we can run a command that transfers multiple axies from one wallet to another

5- Transfer USD
Within a guild you may need to send USD equivalent to some collaborators. In this is case it is convenient to have the SLP automatically converted in real time.
let qty=args[2]
let url = "https://api.coingecko.com/api/v3/simple/price?ids=smooth-love-potion&vs_currencies=usd";
let slp_price= await fetch(url, { method: "Get" }).then(res => res.json()).then((json) => { return (Object.values(json)[0].usd)});
qty=Math.round(qty/slp_price)
await utils.transfer('usd'from,to,qty,message)
We can also use this method for transferring other tokens like Weth, Axs and SLP.
6- Claim SLP
Finally, we can claim the in game SLP generated by players for then distribute it according to your guilds rules and policies.

Conclusion
Discord is a beautiful for managing community, privileges and contributors. It’s also a great tool for automation. My guild uses a more developed discord bot which contains databases, scholars can verify using passwords and can also claim their tokens without need for managers to do anything.
Managing a gaming guild with many scholars can be a challenging operational task given that we need to manage a lot of valuable assets (tokens and axies) and at the same time worry about security of our private keys which makes it impossible to give access to collaborators without delegating control of the assets.
We are going to be interacting with RONIN blockchain through the Web3js library. We are going to create a discord bot that interprets wallets via their aliases and then verifies discord user’s privileges to run different commands like claims, transfers and reading information.
What we will learn:
Set up discord bot
Obtain SLP balance
Get information about a scholar
Transfer axies
Transfer tokens
Claim SLP
Get discord application token
First we need to create a discord application for interacting with our bot. We can read discord documentation. After that we can get out TOKEN what we will be using for running our bot on localhost

After that we need to create a /Data/config.json file inside the Data folder of the repo and inside it copy our token. You cannot share this token with anyone so protect it and that’s why I hide it in the .gitignore so you can’t commit it to git.
{
"token": "DISCORD_TOKEN",
"prefix": "!"
}
Find the contract ABI’s
For managing different assets in the ronin blockchain we are going to need 2 ABI. One for the tokens and one for the Axies. There may be others for land or other assets but not needed in the context of this tutorial.
Ronin is an Ethereum sidechain, it’s EVM compatible and uses the same standard ERC20 for its tokens. We ERC20 ABI to manage AXS, SLP, WETH or RON. For managing AXIES, the contract is not fully compliant with the ERC721 standard. This is because it was deployed before the standard had become finalized.

Still we can get the ABI which we can get from the contract creator and still has all the needed methods. This ABI’s are already in the repo witch filenames axie_abi.json and token_abi.json
Setting up wallet aliases
First we need to create a secrets.json file containing all our private keys, each one with its own descriptive alias. This alias may be a number or a descriptive name we use in our wallets. For example main wallet could be were we make the breeding of axies or were we store high value assets.
DO NOT SHARE THIS PRIVATE KEYS EVER.
{
"breed_old": "PRIVATE KEY",
"buenos": "PRIVATE KEY",
"main":"PRIVATE KEY",
"acc2": "PRIVATE KEY",
"acc_admin": "PRIVATE KEY",
"acc_tri": "PRIVATE KEY",
"account1": "PRIVATE KEY",
"account2": "PRIVATE KEY",
"account3": "PRIVATE KEY",
"account69": "PRIVATE KEY"
}
Once we have our secrets file ready we can star writing and running commands by only mentioning this aliases instead of the public keys. For example for transferring certain axie from one account to another should be very easy!
async getWalletByAlias(alias){
let from_private = secrets[alias]
const web3 = await new Web3(new Web3.providers.HttpProvider(RONIN_PROVIDER_FREE));
if(from_private){
const signer = web3.eth.accounts.privateKeyToAccount(from_private)
let wallet=signer.address//.replace('0x','ronin:')
return wallet
}
return false
}
!transfer axie_123 account1 account2
Set up roles
Through discord, we are going to allow other collaborators of the guild to manage Ronin assets. We only need to protect the private keys by uploading them to a private server. After these are done we can allow certain roles in discord to run certain commands.
For the example we are going to create the Manager role in discord and then get the ID on Server settings → Roles

Then we can call a method that verifies the Role of the incoming message to see if allows the command to execute or not.
isManager:function(message){
if(message.author.bot)return true
let r1=message.guild.roles.cache.find(r => r.name === "Manager")
//we can also filter with channel names using message.channel.name
if(r1 && message.member.roles.cache.has(r1.id))return true
return false
}
2- Obtain SLP balance
Let’s start with the commands. We are going to start simple by checking the token balances of a wallet, for example of main wallet.

We first need to identify which token or assets we need to check the balance of and then identify the contract address
const web3 = await new Web3(new Web3.providers.HttpProvider(RONIN_PROVIDER));
from_acc=await this.getWalletByAlias(from_acc)
let contract_add=''
if(token == 'slp') contract_add = SLP_CONTRACT
else if(token == 'axs') contract_add = AXS_CONTRACT
else if(token == "axies")contract_add = AXIE_CONTRACT
else if(token == "weth")contract_add = WETH_CONTRACT
else if(token == "ron") return await web3.eth.getBalance(from_acc)
else return message.channel.send("Message send")
let contract = new web3.eth.Contract(token_abi,web3.utils.toChecksumAddress(contract_add))
let balance = await contract.methods.balanceOf( web3.utils.toChecksumAddress(from_acc)).call()
4- Get information about a scholar
With the command report we can get information about SLP, MMR, list the Axies and much more.

For this to work we need to check out Axie Infinity API’s which we can found on their discord server.
getSLP:async function(from_acc,message=null,cache=false){
try{
let data={}
let url = "https://game-api.axie.technology/api/v2/"+from_acc.replace('0x','ronin:') ;
data= await fetch(url, { method: "Get" }).then(res => res.json()).then((json) => { return json});
return data
}catch(e){
this.log("ERROR: "+e.message,message)
}
}
Also using GraphQL we can get the information about the particular Axies inside the wallet
getAxiesIds:async function (wallet){
if(!wallet)return
wallet=wallet.replace('ronin:','0x')
let url = `https://graphql-gateway.axieinfinity.com/graphql`;
let query = `
{
"operationName": "GetAxieBriefList",
"variables": {
"owner":"${wallet}"
},
"query": "query GetAxieBriefList($auctionType: AuctionType, $criteria: AxieSearchCriteria, $from: Int, $sort: SortBy, $size: Int, $owner: String) { axies(auctionType: $auctionType, criteria: $criteria, from: $from, sort: $sort, size: $size, owner: $owner) { total results { ...AxieBrief __typename } __typename }}fragment AxieBrief on Axie { id name stage class breedCount image title battleInfo { banned __typename } auction { currentPrice currentPriceUSD __typename } parts { id name class type specialGenes __typename } __typename}"
}`
let response=await fetch(url, { method: 'post',headers: { 'Content-Type': 'application/json'},body: JSON.stringify(JSON.parse(query))}).then(response => response.json()).then(data => { return data});
if(!response || !response.data || !response.data.axies)return null
let dev= {count:response.data.axies.total,axies:response.data.axies.results}
return dev
}
4- Transfer axies
Now we are going to start with riskier commands like transfers. It is very important that we understand the security risks and implications of allowing this type of commands. For security, we are going to use 2 filters.
Using each discord message object we are going to check if corresponds with the Manager role we defined before. If not, the command will return error.
if(!utils.isManager(message))return message.channel.send("You don't have the propper rights to run this command.")
Also, we are going to check the wallet where the transfer is destined to go. If we only allow transfers between our own wallets then we can protect from thief.
if(!this.isSafe(from_acc) || !this.isSafe(to_acc))return message.channel.send(`Incorrect alias/wallet, this wallet doesn't look like your own!`);
Finally, we can run a command that transfers multiple axies from one wallet to another

5- Transfer USD
Within a guild you may need to send USD equivalent to some collaborators. In this is case it is convenient to have the SLP automatically converted in real time.
let qty=args[2]
let url = "https://api.coingecko.com/api/v3/simple/price?ids=smooth-love-potion&vs_currencies=usd";
let slp_price= await fetch(url, { method: "Get" }).then(res => res.json()).then((json) => { return (Object.values(json)[0].usd)});
qty=Math.round(qty/slp_price)
await utils.transfer('usd'from,to,qty,message)
We can also use this method for transferring other tokens like Weth, Axs and SLP.
6- Claim SLP
Finally, we can claim the in game SLP generated by players for then distribute it according to your guilds rules and policies.

Conclusion
Discord is a beautiful for managing community, privileges and contributors. It’s also a great tool for automation. My guild uses a more developed discord bot which contains databases, scholars can verify using passwords and can also claim their tokens without need for managers to do anything.
No activity yet