Skip to content

Commit

Permalink
Merge pull request #4 from ElrondDevGuild/feature/herotag
Browse files Browse the repository at this point in the history
herotag create and resolve functionality
juliancwirko authored Jun 17, 2022
2 parents 4e45501 + 3da6636 commit 733fa8a
Showing 8 changed files with 227 additions and 12 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
### [0.2.0](https://github.com/juliancwirko/buildo-begins/releases/tag/v0.2.0) (2022-06-16)
- added `buildo-begins herotag` - a command for creating Elrond herotag (dns) and checking the address of the existing one

### [0.1.0](https://github.com/juliancwirko/buildo-begins/releases/tag/v0.1.0) (2022-06-12)
- added `buildo-begins issue-esdt` command for issuing new ESDT tokens
- added `buildo-begins set-special-roles-esdt` command for setting and unsetting special ESDT roles - local mint, and local burn
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -49,6 +49,7 @@ For now, the first version gives you basic stuff. But there will be much more:
7. `buildo-begins issue-esdt` - issue new ESDT token
8. `buildo-begins set-special-roles-esdt` - set/unset special ESDT roles
9. `buildo-begins mint-burn-esdt` - mint/burn the ESDT token supply (requires special roles)
10. `buildo-begins herotag` - create a herotag and assign it to addres and check addresses of existing ones

What is awesome here is that you don't have to worry about proper nonce, decimal places, or differentiation between the NFT token id and collection ticker. The maximum amount of arguments will always be the address, token id, and amount. It will differ for each type, but these are maximum.

1 change: 1 addition & 0 deletions esbuild.config.js
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ esbuild
'ora',
'axios',
'bignumber.js',
'keccak',
],
})
.catch(() => process.exit(1));
88 changes: 78 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@
"node": "^14.13.1 || >=16.0.0"
},
"types": "build/types",
"version": "0.1.0",
"version": "0.2.0",
"description": "Elrond blockchain CLI helper tools",
"main": "build/index.js",
"bin": {
@@ -31,6 +31,7 @@
"typescript"
],
"devDependencies": {
"@types/keccak": "^3.0.1",
"@types/node": "^17.0.39",
"@types/prompt": "^1.1.2",
"@types/prompts": "^2.0.14",
@@ -51,6 +52,7 @@
"axios": "^0.27.2",
"bignumber.js": "^9.0.2",
"cosmiconfig": "^7.0.1",
"keccak": "^3.0.2",
"ora": "5.4.1",
"prompts": "^2.4.2"
}
114 changes: 114 additions & 0 deletions src/herotag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import prompts, { PromptObject } from 'prompts';
import { exit } from 'process';
import {
Transaction,
ContractCallPayloadBuilder,
ContractFunction,
TypedValue,
BytesValue,
SmartContract,
} from '@elrondnetwork/erdjs';

import axios from 'axios';

import {
areYouSureAnswer,
setup,
commonTxOperations,
dnsScAddressForHerotag,
} from './utils';
import { chain, shortChainId, publicApi } from './config';

const promptQuestions: PromptObject[] = [
{
type: 'select',
name: 'type',
message: 'What do you want to do with the herotag?\n',
validate: (value) => (!value ? 'Required!' : true),
choices: [
{ title: 'Create one', value: 'create' },
{ title: 'Check the address for one', value: 'check' },
],
},
{
type: 'text',
name: 'herotag',
message: 'Please provide the herotag name (without .elrond suffix)\n',
validate: (value) => {
if (!value) return 'Required!';
if (value.length > 25 || value.length < 3) {
return 'Length between 3 and 25 characters!';
}
if (!new RegExp(/^[a-z0-9]+$/).test(value)) {
return 'Lowercase alphanumeric characters only!';
}
return true;
},
},
];

export const herotag = async () => {
const { herotag, type } = await prompts(promptQuestions);

if (!herotag) {
console.log('You have to provide the herotag name!');
exit(9);
}

if (type === 'check') {
try {
const response = await axios.get<{ address: string }>(
`${publicApi[chain]}/usernames/${herotag.trim()}`,
{
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
}
);
console.log(
`\nAddress of ${herotag}.elrond is: ${response?.data?.address}\n`
);
} catch {
console.log(
'\nThere is no such herotag registered. Please also check the chain type. By default it checks on the devnet.\n'
);
}
} else {
try {
await areYouSureAnswer();

const dnsScAddress = dnsScAddressForHerotag(`${herotag}.elrond`);
const heroBytes = BytesValue.fromUTF8(`${herotag}.elrond`);

const { signer, userAccount, provider } = await setup();

const dnsSc = new SmartContract({ address: dnsScAddress });
const dnsCanRegisterQuery = dnsSc.createQuery({
func: new ContractFunction('canRegister'),
args: [heroBytes],
});

await provider.queryContract(dnsCanRegisterQuery);

const args: TypedValue[] = [heroBytes];

const data = new ContractCallPayloadBuilder()
.setFunction(new ContractFunction('register'))
.setArgs(args)
.build();

const tx = new Transaction({
data,
value: 0,
gasLimit: 50000 + 1500 * data.length() + 20000000,
receiver: dnsScAddress,
chainID: shortChainId[chain],
});

await commonTxOperations(tx, userAccount, signer, provider);
} catch (e) {
console.log((e as Error)?.message);
}
}
};
5 changes: 5 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@ import { sendEgld } from './egld/send-egld';
import { sendNft } from './nft/send-nft';
import { sendSft } from './sft/send-sft';
import { sendMetaEsdt } from './meta-esdt/send-meta-esdt';
import { herotag } from './herotag';

const COMMANDS = {
derivePem: 'derive-pem',
@@ -23,6 +24,7 @@ const COMMANDS = {
issueEsdt: 'issue-esdt',
mintBurnEsdt: 'mint-burn-esdt',
setSpecialRolesEsdt: 'set-special-roles-esdt',
herotag: 'herotag',
};

const args = argv;
@@ -75,6 +77,9 @@ switch (command) {
case COMMANDS.setSpecialRolesEsdt:
setSpecialRolesEsdt();
break;
case COMMANDS.herotag:
herotag();
break;
default:
break;
}
23 changes: 22 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
@@ -3,8 +3,9 @@ import { exit, cwd } from 'process';
import prompts, { PromptObject } from 'prompts';
import { Transaction, TransactionWatcher } from '@elrondnetwork/erdjs';
import ora from 'ora';
import keccak from 'keccak';

import { Account } from '@elrondnetwork/erdjs';
import { Account, SmartContract, Address } from '@elrondnetwork/erdjs';
import { parseUserKey, UserSigner } from '@elrondnetwork/erdjs-walletcore';
import { ApiNetworkProvider } from '@elrondnetwork/erdjs-network-providers';

@@ -126,3 +127,23 @@ export const commonTxOperations = async (
`Transaction link: ${elrondExplorer[chain]}/transactions/${txHash}\n`
);
};

export const dnsScAddressForHerotag = (herotag: string) => {
const hashedHerotag = keccak('keccak256').update(herotag).digest();

const initialAddress = Buffer.from(Array(32).fill(1));
const initialAddressSlice = initialAddress.slice(0, 30);
const scId = hashedHerotag.slice(31);

const deployer_pubkey = Buffer.concat([
initialAddressSlice,
Buffer.from([0, scId.readUIntBE(0, 1)]),
]);

const scAddress = SmartContract.computeAddress(
new Address(deployer_pubkey),
0
);

return scAddress;
};

0 comments on commit 733fa8a

Please sign in to comment.