Skip to content

Commit 9d5d9b9

Browse files
author
Christopher Powroznik
committed
buy and list node licenses
1 parent f7f4f6b commit 9d5d9b9

File tree

11 files changed

+171
-27
lines changed

11 files changed

+171
-27
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import * as Vorpal from "vorpal";
2+
import { config } from "@xai-vanguard-node/core";
3+
4+
/**
5+
* Function to get the node license contract address from the config and log it in the console.
6+
* @param {Vorpal} cli - The Vorpal instance to attach the command to.
7+
*/
8+
export function getNodeLicenseContractAddress(cli: Vorpal) {
9+
cli
10+
.command('get-node-license-contract-address', 'Fetches the node license contract address.')
11+
.action(async function (this: Vorpal.CommandInstance) {
12+
const nodeLicenseContractAddress = config.nodeLicenseAddress;
13+
this.log(`Node License Contract Address: ${nodeLicenseContractAddress}`);
14+
});
15+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import * as Vorpal from "vorpal";
2+
import { listNodeLicenses as listNodeLicensesCore } from "@xai-vanguard-node/core";
3+
4+
/**
5+
* Function to list all NodeLicense token IDs owned by a particular address.
6+
* @param cli - Vorpal instance
7+
*/
8+
export function listNodeLicenses(cli: Vorpal) {
9+
cli
10+
.command('list-node-licenses', 'Lists all NodeLicense token IDs owned by a particular address.')
11+
.action(async function (this: Vorpal.CommandInstance) {
12+
const {address} = await this.prompt({
13+
type: 'input',
14+
name: 'address',
15+
message: 'Please enter the address to list NodeLicense token IDs for:'
16+
});
17+
this.log(`Fetching all NodeLicense token IDs for address ${address}...`);
18+
await listNodeLicensesCore(address, (tokenId: bigint) => {
19+
this.log(`Token ID: ${tokenId}`);
20+
});
21+
this.log(`NodeLicense token IDs retrieved.`);
22+
});
23+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import * as Vorpal from "vorpal";
2+
import { ethers } from "ethers";
3+
import { getSignerFromPrivateKey, mintNodeLicenses as coreMintNodeLicenses } from "@xai-vanguard-node/core";
4+
5+
export function mintNodeLicenses(cli: Vorpal) {
6+
cli
7+
.command('mint-node-licenses', 'Mints NodeLicense tokens if the signer has enough balance and the amount is less than the maximum mint amount.')
8+
.action(async function (this: Vorpal.CommandInstance) {
9+
const amountPrompt: Vorpal.PromptObject = {
10+
type: 'input',
11+
name: 'amount',
12+
message: 'Enter the amount of tokens to mint:',
13+
};
14+
const { amount } = await this.prompt(amountPrompt);
15+
16+
const privateKeyPrompt: Vorpal.PromptObject = {
17+
type: 'password',
18+
name: 'privateKey',
19+
message: 'Enter the private key of the wallet:',
20+
mask: '*'
21+
};
22+
const { privateKey } = await this.prompt(privateKeyPrompt);
23+
24+
this.log(`Minting ${amount} NodeLicense tokens...`);
25+
26+
// get a signer of the private key
27+
const {signer} = getSignerFromPrivateKey(privateKey);
28+
29+
try {
30+
const { mintedNftIds, txReceipt, pricePaid } = await coreMintNodeLicenses(
31+
Number(amount),
32+
signer,
33+
);
34+
35+
this.log(`Tokens successfully minted. Here are the details:`);
36+
mintedNftIds.forEach((id, index) => {
37+
this.log(`Minted ID: ${id}`);
38+
});
39+
40+
41+
42+
// Convert pricePaid from wei to eth using ethers utils
43+
const pricePaidInEth = ethers.formatEther(pricePaid);
44+
this.log(`Price Paid for Minting (in ETH): ${pricePaidInEth}`);
45+
46+
47+
} catch (error) {
48+
this.log(`Error minting tokens: ${(error as Error).message}`);
49+
}
50+
});
51+
}
52+

apps/cli/src/commands/toggle-assertion-checking.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import * as Vorpal from "vorpal";
2-
import { getSignerFromPrivateKey, toggleAssertionChecking } from "@xai-vanguard-node/core";
2+
import { getSignerFromPrivateKey, toggleAssertionChecking as coreToggleAssertionChecking } from "@xai-vanguard-node/core";
33

44
/**
55
* Function to toggle the assertion checking in the Referee contract.
66
* @param {Vorpal} cli - The Vorpal instance to attach the command to.
77
*/
8-
export function toggleAssertionCheckingCommand(cli: Vorpal) {
8+
export function toggleAssertionChecking(cli: Vorpal) {
99
cli
1010
.command('toggle-assertion-checking', 'Toggles the assertion checking.')
1111
.action(async function (this: Vorpal.CommandInstance) {
@@ -20,7 +20,7 @@ export function toggleAssertionCheckingCommand(cli: Vorpal) {
2020
const { signer } = getSignerFromPrivateKey(privateKey);
2121

2222
// Call the toggleAssertionChecking function
23-
await toggleAssertionChecking(signer);
23+
await coreToggleAssertionChecking(signer);
2424

2525
this.log(`Assertion checking toggled.`);
2626
});

apps/cli/src/index.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@ import { manuallyChallengeAssertion } from './commands/manually-challenge-assert
1414
import { removeAdmin } from './commands/access-control/remove-admin';
1515
import { removeChallenger } from './commands/access-control/remove-challenger';
1616
import { setChallengerPublicKey } from './commands/set-challenger-public-key';
17-
import { toggleAssertionCheckingCommand } from './commands/toggle-assertion-checking';
17+
import { toggleAssertionChecking } from './commands/toggle-assertion-checking';
1818
import { addOperator } from './commands/operator-control/add-operator';
1919
import { removeOperator } from './commands/operator-control/remove-operator';
2020
import { listOperators } from './commands/operator-control/list-operators';
21+
import { mintNodeLicenses } from "./commands/mint-node-licenses";
22+
import { getNodeLicenseContractAddress } from './commands/get-node-license-address';
23+
import { listNodeLicenses } from './commands/list-node-licenses';
2124

2225
const cli = new Vorpal();
2326

@@ -40,7 +43,10 @@ removeAdmin(cli);
4043
removeChallenger(cli);
4144
removeOperator(cli);
4245
setChallengerPublicKey(cli);
43-
toggleAssertionCheckingCommand(cli);
46+
toggleAssertionChecking(cli);
47+
mintNodeLicenses(cli);
48+
getNodeLicenseContractAddress(cli);
49+
listNodeLicenses(cli);
4450

4551
cli
4652
.delimiter('vanguard-node$')

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"author": "",
1515
"license": "UNLICENSED",
1616
"dependencies": {
17-
"@openzeppelin/contracts": "^4.9.3"
17+
"ethers": "^6.7.1"
1818
},
1919
"devDependencies": {
2020
"@typescript-eslint/eslint-plugin": "^6.6.0",

packages/core/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
"author": "",
1414
"license": "UNLICENSED",
1515
"dependencies": {
16-
"@noble/curves": "^1.2.0",
17-
"ethers": "^6.7.1"
16+
"@noble/curves": "^1.2.0"
1817
},
1918
"devDependencies": {
2019
"@types/node": "^20.6.0"
2120
}
2221
}
22+
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
export * from "./mintNodeLicenses";
1+
export * from "./mintNodeLicenses";
2+
export * from "./listNodeLicenses";
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { ethers } from 'ethers';
2+
import { NodeLicenseAbi } from '../abis';
3+
import { config } from '../config';
4+
import { getProvider } from '../utils/getProvider';
5+
6+
/**
7+
* Fetches all NodeLicense token IDs owned by a given address.
8+
* @param ownerAddress - The address of the owner.
9+
* @param callback - Optional callback function to handle token IDs as they are retrieved.
10+
* @returns An array of token IDs.
11+
*/
12+
export async function listNodeLicenses(
13+
ownerAddress: string,
14+
callback?: (tokenId: bigint) => void
15+
): Promise<bigint[]> {
16+
17+
// Get the provider
18+
const provider = getProvider();
19+
20+
// Create an instance of the NodeLicense contract
21+
const nodeLicenseContract = new ethers.Contract(config.nodeLicenseAddress, NodeLicenseAbi, provider);
22+
23+
// Get the balance of the owner's address
24+
const balance = await nodeLicenseContract.balanceOf(ownerAddress);
25+
26+
// Initialize an array to store the token IDs
27+
const tokenIds: bigint[] = [];
28+
29+
// Loop through the balance and fetch each token ID
30+
for (let i = 0; i < balance; i++) {
31+
const tokenId = await nodeLicenseContract.tokenOfOwnerByIndex(ownerAddress, i);
32+
tokenIds.push(tokenId);
33+
if (callback) {
34+
callback(tokenId);
35+
}
36+
}
37+
38+
return tokenIds;
39+
}

packages/core/src/node-license/mintNodeLicenses.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ import { config } from '../config';
66
* Mints NodeLicense tokens if the signer has enough balance and the amount is less than the maximum mint amount.
77
* @param amount - The amount of tokens to mint.
88
* @param signer - The signer to interact with the contract.
9-
* @returns An array of minted NFT IDs and the transaction receipt.
9+
* @returns An object containing an array of minted NFT IDs, the transaction receipt, and the price paid.
1010
*/
1111
export async function mintNodeLicenses(
1212
amount: number,
1313
signer: ethers.Signer
14-
): Promise<{ mintedNftIds: number[], txReceipt: ethers.TransactionReceipt }> {
14+
): Promise<{ mintedNftIds: bigint[], txReceipt: ethers.TransactionReceipt, pricePaid: bigint }> {
1515

1616
// Create an instance of the NodeLicense contract
1717
const nodeLicenseContract = new ethers.Contract(config.nodeLicenseAddress, NodeLicenseAbi, signer);
@@ -47,19 +47,30 @@ export async function mintNodeLicenses(
4747
}
4848

4949
// Mint the tokens, passing the price as the msg.value
50-
const mintTx = await nodeLicenseContract.mint({ value: price }, amount);
51-
50+
const mintTx = await nodeLicenseContract.mint(amount, { value: price },);
5251
// Wait for the transaction to be mined and get the receipt
5352
const txReceipt = await mintTx.wait();
5453

55-
// Get the minted NFT IDs from the "Transfer" events in the transaction receipt
56-
const mintedNftIds = txReceipt.events
57-
?.map((event: ethers.Log) => nodeLicenseContract.interface.parseLog({
58-
...event,
54+
// Get the "Transfer" events from the transaction receipt logs
55+
const transferEvents = txReceipt.logs.filter((log: ethers.Log) => log.topics[0] === ethers.id("Transfer(address,address,uint256)"));
56+
57+
// Extract the mintedNftIds from the transfer events
58+
const mintedNftIds = transferEvents.map((event: ethers.EventLog) => {
59+
// Parse the event log using the contract interface
60+
const parsedLog = nodeLicenseContract.interface.parseLog({
5961
topics: [...event.topics],
60-
}))
61-
.filter((event: ethers.LogDescription) => event.name === 'Transfer')
62-
.map((event: ethers.LogDescription) => event.args?.tokenId.toNumber()) ?? [];
62+
data: event.data
63+
});
64+
65+
// Check if parsedLog is not null before accessing args
66+
if (parsedLog) {
67+
// Return the tokenId from the parsed log
68+
return parsedLog.args.tokenId;
69+
}
70+
71+
// Return a default value or throw an error if parsedLog is null
72+
throw new Error('Failed to parse log. Please double check your transaction when through on chain.');
73+
});
6374

64-
return { mintedNftIds, txReceipt };
75+
return { mintedNftIds, txReceipt, pricePaid: price };
6576
}

0 commit comments

Comments
 (0)