Skip to content

Commit

Permalink
env setup script (#4)
Browse files Browse the repository at this point in the history
* add script to generate stubs

* add stub assets

* temporarily deploy to s3 on pull requests

* improve tests

* add tests

* fix meta of fungible tokens

* add python dependency

* add images game a

* add images

* update link to images in metadata files

* update cdn links

* add cover images for swords

* update the docs

* add names for the game a

* add names to the game a

* add names to the game b

* add names to the game a

* add names to the game c

* add names to the game c

* wip

* more fixese

* typo fix

* cleanup

* set assets metadata

* First batch run

* use assets to generate app agents

* fix images

* fix images

* add TODOs

* Game a artifacts

* Game B collection A

* Game B collection B

* Revert "Game B collection B"

This reverts commit 6cbb966.

* Game B Callection B

* Game B Collection C

* Game B Collection D

* Game C Collection A

* Game C Collection B

* Game C Collection C

* Game C Collection D

* Manual modifications for balancing

* Updated Game A

* Game B

* Game C

* openAI API

* cleanup and refactor

* fixes

* add upscaled game icons

* fixes

* Revert id changes

* Reverted title and description changes

* fixes

* fixes

* wip

* wip

* wip

* wip

* update github ci

* add retry logic

* fixes

* run parallel working

* setup free transfers

* setup decimals

* setup decimals

* wip : common functions

* fix promise resolving and refactor

* cleanup

* wip

* unsubscribe from TX updates

* change isInBlock to isFinalized

* seperate event scanning

* seperate event scanning

* switch to use datagate

* typo fix

* typo fix

* fix naming actions&atomics

* fix naming actions&atomics

* fix naming actions&atomics, improve performance

* fix minting of NFTs

* update example .env

* do not use node subscriptions, do not send the same TX multiple times

* various fixes

---------

Co-authored-by: Victor Mezrin <[email protected]>
Co-authored-by: kehindave <[email protected]>
  • Loading branch information
3 people authored Sep 27, 2024
1 parent 20417e8 commit 631ae5e
Show file tree
Hide file tree
Showing 9 changed files with 711 additions and 415 deletions.
4 changes: 3 additions & 1 deletion deploy/env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ DEMO_ACCOUNT_ONE_MNEMONIC="//Dave"
DEMO_ACCOUNT_TWO_MNEMONIC="//Eve"
DEMO_ACCOUNT_THREE_MNEMONIC="//Ferdie"

# Connection to the blockchain
WS_PROVIDER_URL="ws://127.0.0.1:52279"
DATAGATE_URL="http://127.0.0.1:18890"

# Amount to transfer to app agents
TRANSFER_AMOUNT=10
TRANSFER_AMOUNT=1000
246 changes: 142 additions & 104 deletions deploy/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ const dotenv = require("dotenv");
const fs = require('fs');
const path = require('path');
const { create_app_agent } = require('./utils/app_agent');
const { create_app_agent_fungible_token } = require('./utils/fungible');
const { create_app_agent_nft_collection } = require('./utils/nft');
const { create_app_agent_nft_token } = require('./utils/nft');
const { create_fungible_tokens, set_metadata_and_mint_fungible_token, create_token_transfer } = require('./utils/fungible');
const { create_nft_collections, set_metadata_and_mint_nft, create_nft_transfers } = require('./utils/nft');
const { processSignedTransaction, processSignedBatchTransaction } = require('./utils/utils');

const startTime = Date.now();

const aws_s3_assets_path = path.join(__dirname, '..', 'aws_s3_assets');
const game_a_path = path.join(aws_s3_assets_path, 'game-a/');
Expand All @@ -18,16 +20,16 @@ const game_folders = [game_a_path, game_b_path, game_c_path];
dotenv.config();

async function main() {
// Read WS_PROVIDER_URL from .env file
console.log("Read WS_PROVIDER_URL from .env file");
const wsProviderUrl = process.env.WS_PROVIDER_URL;
if (!wsProviderUrl) {
throw new Error("WS_PROVIDER_URL is not set in the .env file");
}

// Create a provider with the URL from .env
console.log("Create a provider with the URL from .env");
const provider = new WsProvider(wsProviderUrl);

// Instantiate the API with the provider
console.log("Instantiate the API with the provider");
const api = await ApiPromise.create({
provider,
types: {
Expand All @@ -44,148 +46,184 @@ async function main() {
}
});

// Construct the keyring
console.log("Construct the keyring");
const keyring = new Keyring({ type: "sr25519" });

// Load accounts from .env file
console.log("Load accounts from .env file");
const faucetAccount = keyring.addFromUri(process.env.FAUCET_ACCOUNT_MNEMONIC);
const appAgentOne = keyring.addFromUri(process.env.APP_AGENT_OWNER_ONE_MNEMONIC);
const appAgentTwo = keyring.addFromUri(process.env.APP_AGENT_OWNER_TWO_MNEMONIC);
const appAgentThree = keyring.addFromUri(process.env.APP_AGENT_OWNER_THREE_MNEMONIC);
const appAgentOwners = [appAgentOne, appAgentTwo, appAgentThree];
const appAgentOneOwner = keyring.addFromUri(process.env.APP_AGENT_OWNER_ONE_MNEMONIC);
const appAgentTwoOwner = keyring.addFromUri(process.env.APP_AGENT_OWNER_TWO_MNEMONIC);
const appAgentThreeOwner = keyring.addFromUri(process.env.APP_AGENT_OWNER_THREE_MNEMONIC);
const appAgentOwners = [appAgentOneOwner, appAgentTwoOwner, appAgentThreeOwner];

const demo_user_one = keyring.addFromUri(process.env.DEMO_ACCOUNT_ONE_MNEMONIC);
const demo_user_two = keyring.addFromUri(process.env.DEMO_ACCOUNT_TWO_MNEMONIC);
const demo_user_three = keyring.addFromUri(process.env.DEMO_ACCOUNT_THREE_MNEMONIC);

const transferAmount = parseInt(process.env.TRANSFER_AMOUNT) * 1e12;
const demotransferAmount = parseInt(process.env.TRANSFER_AMOUNT) * 1e10;

console.log("Start to initialise the owners of the app agents");
// const transfers = [
// api.tx.balances.transferKeepAlive(appAgentOneOwner.address, transferAmount.toString()),
// api.tx.balances.transferKeepAlive(appAgentTwoOwner.address, transferAmount.toString()),
// api.tx.balances.transferKeepAlive(appAgentThreeOwner.address, transferAmount.toString()),
// api.tx.balances.transferKeepAlive(demo_user_one.address, demotransferAmount.toString()),
// api.tx.balances.transferKeepAlive(demo_user_two.address, demotransferAmount.toString()),
// api.tx.balances.transferKeepAlive(demo_user_three.address, demotransferAmount.toString()),
// ];

// console.log("Send the batch of transfers");
// await processSignedBatchTransaction(api, faucetAccount, api.tx.utility.batchAll(transfers));
// await create_balance_transfers(api, demo_user_one, demo_user_two);
// await create_balance_transfers(api, demo_user_three, demo_user_one);

console.log("Traverse the game folders and collect entity data");
const gameData = collectGameData(game_folders);

// array of fungible ids
let fungibles = [];

// array of { collectionId: collectionId, tokenId: tokenId}
let collections = [];

console.log("Starting to process game data");
for (const [gameIndex, game] of gameData.entries()) {
console.log(`Processing game ${gameIndex + 1}`);
const appAgentOwner = appAgentOwners[gameIndex];

// Create app agent and set metadata
console.log(`Creating app agent for game ${gameIndex + 1}`);
const appAgentId = await create_app_agent(api, appAgentOwner, game.appAgent.metadataUrl);
console.log(`App agent created for game ${gameIndex + 1}: ${appAgentId}`);

// Create and configure fungible tokens
if (game.fungibles.length > 0) {
console.log(`Creating fungible tokens for game ${gameIndex + 1}`);
const fungibleIds = await create_fungible_tokens(api, appAgentOwner, appAgentId, game.fungibles.length);
fungibles = [...fungibles, ...fungibleIds];
console.log(`Setting metadata and minting fungible tokens for game ${gameIndex + 1}`);
await set_metadata_and_mint_fungible_token(api, appAgentOwner, appAgentId, fungibleIds, game.fungibles.map(f => f.metadataUrl), demo_user_one, game.fungibles.map(f => f.decimals));
console.log(`Fungible tokens created and configured for game ${gameIndex + 1}`);
}

// Create a batch of transfers
const transfers = [
api.tx.balances.transferKeepAlive(appAgentOne.address, transferAmount.toString()),
api.tx.balances.transferKeepAlive(appAgentTwo.address, transferAmount.toString()),
api.tx.balances.transferKeepAlive(appAgentThree.address, transferAmount.toString())
];

// Send the batch of transfers
await new Promise((resolve, reject) => {
api.tx.utility
.batchAll(transfers)
.signAndSend(faucetAccount, ({ status, events }) => {
if (status.isInBlock || status.isFinalized) {
events.forEach(({ event }) => {
if (api.events.balances.Transfer.is(event)) {
const [from, to, amount] = event.data;
console.log(`Transferred ${amount.toNumber() / 1e12} tokens from ${from.toString()} to ${to.toString()}`);
}
});
console.log("Initial transfers completed successfully");
resolve();
}
})
.catch(reject);
});

// traverse the game folders and create app-agents and assets for each game
for (const [index, folder] of game_folders.entries()) {
console.log("folder:", folder);
let appagentId = null;
let appAgentOwner = appAgentOwners[index];

// Search for folders starting with app-agent- and print all files
const subFolders = fs.readdirSync(folder);

for (const subFolder of subFolders) {
console.log("subFolder:", subFolder);
if (subFolder.startsWith('app-agent-')) {
const folderPath = path.join(folder, subFolder);
console.log("folderPath:", folderPath);
// Create and configure NFT collections and tokens
console.log(`Creating NFT collections for game ${gameIndex + 1}`);
const collectionIds = await create_nft_collections(api, appAgentOwner, appAgentId, game.nftCollections.length);
console.log(`NFT collections created for game ${gameIndex + 1}:`, collectionIds);
for (let i = 0; i < game.nftCollections.length; i++) {
console.log(`Setting metadata and minting NFTs for collection ${collectionIds[i]} of game ${gameIndex + 1}`);
let nftInfo = await set_metadata_and_mint_nft(api, appAgentOwner, appAgentId, collectionIds[i], game.nftCollections[i], demo_user_one.address);
collections = [...collections, ...nftInfo];
}
console.log(`NFT collections created and configured for game ${gameIndex + 1}`);
}

let metadataUrl = readFilesInDirectory(folderPath);
console.log("metadataUrl:", metadataUrl);
console.log("All games processed. Fungibles:", fungibles);
console.log("Collections:", collections);

if (metadataUrl) {
appagentId = await create_app_agent(api, appAgentOwner, metadataUrl);
await new Promise(resolve => setTimeout(resolve, 10_000)); // wait for the previous tx to propogate
}
}
console.log("Create demo transfers for fungibles");
for (const fungible of fungibles) {
await create_token_transfer(api, fungible, demo_user_one, [demo_user_two, demo_user_three], 10);
await create_token_transfer(api, fungible, demo_user_two, [demo_user_one, demo_user_three], 5);
}

else if (subFolder.startsWith('fungible-')) {
console.log("fungible-token folder detected");
const folderPath = path.join(folder, subFolder);
console.log("folderPath:", folderPath);
console.log("Create demo transfers for NFTs");
for (const collection of collections) {
const recipient = Math.random() < 0.5 ? demo_user_three : demo_user_two;
await create_nft_transfers(api, collection.collectionId, collection.tokenId, demo_user_one, recipient);
}
}

let metadataUrl = readFilesInDirectory(folderPath);
console.log("metadataUrl:", metadataUrl);
create_app_agent_fungible_token(api, appAgentOwner, appagentId, demo_user_one, demo_user_two, metadataUrl);
function collectGameData(gameFolders) {
return gameFolders.map(gameFolder => {
const gameData = {
appAgent: null,
// array of { metadataUrl: metadataUrl, decimals: decimals }
fungibles: [],
// array of { metadataUrl: metadataUrl, tokens: [{ metadataUrl: metadataUrl}]}
nftCollections: []
};

await new Promise(resolve => setTimeout(resolve, 10_000)); // wait for the previous tx to propogate
}
const subFolders = fs.readdirSync(gameFolder);

if (subFolder.startsWith('nft-collection')) {
console.log("nft-collection folder detected");
const folderPath = path.join(folder, subFolder);
console.log("folderPath:", folderPath);
for (const subFolder of subFolders) {
const folderPath = path.join(gameFolder, subFolder);

if (subFolder.startsWith('app-agent-')) {
gameData.appAgent = { metadataUrl: getObjectMetadataURL(folderPath).url };
} else if (subFolder.startsWith('fungible-')) {
gameData.fungibles.push({ metadataUrl: getObjectMetadataURL(folderPath).url, decimals: getObjectMetadataURL(folderPath).decimals });
} else if (subFolder.startsWith('nft-collection')) {
const collection = { metadataUrl: null, tokens: [] };
const subsubFolders = fs.readdirSync(folderPath);

let collection_id = null;

for (const subsubFolder of subsubFolders) {
const subFolderPath = path.join(folderPath, subsubFolder);
if (subsubFolder.startsWith('nft-collection')) {
const nftCollectionPath = path.join(folderPath, subsubFolder);
console.log("nftCollectionPath:", nftCollectionPath);
let metadataUrl = readFilesInDirectory(nftCollectionPath);
console.log("metadataUrl:", metadataUrl);

collection_id = await create_app_agent_nft_collection(api, appAgentOwner, appagentId, metadataUrl);
}

else if (subsubFolder.startsWith('nft-token')) {
const nftItemPath = path.join(folderPath, subsubFolder);
console.log("nftItemPath:", nftItemPath);
let metadataUrl = readFilesInDirectory(nftItemPath);
console.log("metadataUrl:", metadataUrl);

await create_app_agent_nft_token(api, appAgentOwner, appagentId, collection_id, metadataUrl, demo_user_one, demo_user_three);
collection.metadataUrl = getObjectMetadataURL(subFolderPath).url;
} else if (subsubFolder.startsWith('nft-token')) {
collection.tokens.push({ metadataUrl: getObjectMetadataURL(subFolderPath).url });
}
}


}

else {
console.log("unknown folder detected, ignoring...");
gameData.nftCollections.push(collection);
}
}
}

return gameData;
});
}

// Function to read all files in a directory
function readFilesInDirectory(directory) {
/**
* Function searches for the json file with object metadata.
* And calculates the metadata URL based on the file path.
*
* @param {string} directory - The directory where the metadata file is stored.
* @return {string|null} The metadata URL if found, otherwise null.
*/
function getObjectMetadataURL(directory) {
const files = fs.readdirSync(directory);
const jsonFiles = files.filter(file => file.endsWith('.json'));

for (const file of jsonFiles) {
const filePath = path.join(directory, file);
const stats = fs.statSync(filePath);
if (stats.isFile()) {
console.log(`File: ${filePath}`);
const fileContent = fs.readFileSync(filePath, 'utf8');
const jsonData = JSON.parse(fileContent);
// get the decimals from the fungible metadata if it exists
let decimals = jsonData.traits.fungible ? jsonData.traits.fungible.decimals : null;

// Generate the URL based on the folder structure
const relativePath = path.relative(aws_s3_assets_path, filePath);
const url = `https://trait-wallet-demo-account.trait.tech/${relativePath.replace(/\\/g, '/')}`;

console.log(`Generated URL: ${url}`);

// Return the URL instead of reading the file content
return url;
// console.log(`Generated URL: ${url}`);
return { url, decimals };
}
}

return null;
}

async function create_balance_transfers(api, token_recipient, token_recipient_two) {
console.log("Generate free transfers between the two users");

for (let i = 0; i < 2; i++) {
let tx = api.tx.playerTransfers.submitTransferBalances(
token_recipient_two.address,
1000000
);
await processSignedTransaction(token_recipient, tx);
}
console.log(`Free transfer created and confirmed`);
}

main()
.catch(console.error)
.finally(() => process.exit());
.finally(() => {
const endTime = Date.now();
const executionTime = (endTime - startTime) / 1000; // Convert to seconds
console.log(`Total execution time: ${executionTime.toFixed(2)} seconds`);
process.exit();
});
Loading

0 comments on commit 631ae5e

Please sign in to comment.