UNPKG

@vechain/vebetterdao-contracts

Version:

Open-source repository that houses the smart contracts powering the decentralized VeBetterDAO on the VeChain Thor blockchain.

224 lines (223 loc) 11.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.setupMainnetEnvironment = exports.setupLocalEnvironment = exports.endorseAndVerifySeededApps = exports.updateGMMultipliers = exports.setupEnvironment = exports.APPS = void 0; const helpers_1 = require("../helpers"); const airdrop_1 = require("../helpers/airdrop"); const emissions_1 = require("../helpers/emissions"); const seedAccounts_1 = require("../helpers/seedAccounts"); const swap_1 = require("../helpers/swap"); const hardhat_1 = require("hardhat"); const sdk_core_1 = require("@vechain/sdk-core"); const xApp_1 = require("../helpers/xApp"); const accounts = (0, seedAccounts_1.getTestKeys)(17); const xDappCreatorAccounts = accounts.slice(0, 8); exports.APPS = [ { admin: accounts[6].address.toString(), teamWalletAddress: accounts[6].address.toString(), name: "Mugshot", metadataURI: "bafkreiba646cx2y2pv7vrj4sd4fw7m4kdebdthkum2p6jczs5umid5cjgy", categories: ["nutrition", "plastic-waste-recycling"], }, { admin: accounts[6].address.toString(), teamWalletAddress: accounts[6].address.toString(), name: "Cleanify", metadataURI: "bafkreigefkdis3kxspa5ovz4wybcbebecrqw256m7yimwj2jmrmsx57fui", categories: ["plastic-waste-recycling"], }, { admin: accounts[6].address.toString(), teamWalletAddress: accounts[6].address.toString(), name: "GreenCart", metadataURI: "bafkreigu2rw4psbpazeudqhcpjdxsrhrtz3unckcnlidsjsiqjsgje3kli", categories: ["sustainable-shopping"], }, { admin: accounts[6].address.toString(), teamWalletAddress: accounts[6].address.toString(), name: "Green Ambassador Challenge", metadataURI: "bafkreibjxezzffohborgmtqsp6w7koxxdc55bd4dsiud4dlfp2vno5f4le", categories: ["education-learning", "green-mobility-travel"], }, { admin: accounts[6].address.toString(), teamWalletAddress: accounts[6].address.toString(), name: "Oily", metadataURI: "bafkreiakrtehu5xmzrxiwnwo2l6yfgt7ejhjhwxtgkn57vnflpfklx7ioe", categories: ["renewable-energy-efficiency"], }, { admin: accounts[6].address.toString(), teamWalletAddress: accounts[6].address.toString(), name: "EVearn", metadataURI: "bafkreiajy2ldq3o3rhw2gmzmvqbqego76oh2gtmkcz3fxsmfcre6jzuzfu", categories: ["green-finance-defi", "renewable-energy-efficiency"], }, { admin: accounts[6].address.toString(), teamWalletAddress: accounts[6].address.toString(), name: "Vyvo", metadataURI: "bafkreib6uklcdfpudaqlu4budf7f2ngays2rrhqcxshqnjvme5umtykiui", categories: ["fitness-wellness"], }, { admin: accounts[6].address.toString(), teamWalletAddress: accounts[6].address.toString(), name: "Non Fungible Book Club (NFBC)", metadataURI: "bafkreieyqnioauddqzpscgo3gm5nlxu6r3sm2zriz4ft23rw2efc6e252q", categories: ["education-learning"], }, ]; const setupEnvironment = async (config, emissions, treasury, x2EarnApps, _governor, _xAllocationVoting, b3tr, vot3, stargateMock) => { switch (config) { case "local": case "testnet": case "testnet-staging": await (0, exports.setupLocalEnvironment)(config, emissions, treasury, x2EarnApps, b3tr, vot3, stargateMock); break; case "mainnet": await (0, exports.setupMainnetEnvironment)(emissions, x2EarnApps); break; default: throw new Error(`Unsupported app environment: ${config}`); } }; exports.setupEnvironment = setupEnvironment; const updateGMMultipliers = async (levels, multipliers, voterRewards) => { for (let i = 0; i < levels.length; i++) { const level = levels[i]; const multiplier = multipliers[i]; // Update the multiplier for the level await voterRewards.setLevelToMultiplierNow(level, multiplier); } }; exports.updateGMMultipliers = updateGMMultipliers; const endorseAndVerifySeededApps = async (x2EarnApps, stargateMock, endorserSigners) => { const mintAccounts = []; const mintLevels = []; for (const acct of endorserSigners) { mintAccounts.push(acct, acct, acct); mintLevels.push(7, 7, 7); } await (0, helpers_1.mintStargateNFTs)(stargateMock, mintAccounts, mintLevels); const unendorsedApps = await x2EarnApps.unendorsedAppIds(); await (0, xApp_1.endorseXApps)(endorserSigners, x2EarnApps, unendorsedApps, stargateMock); await verifyEndorsedApps(x2EarnApps); }; exports.endorseAndVerifySeededApps = endorseAndVerifySeededApps; const verifyEndorsedApps = async (x2EarnApps) => { const remaining = await x2EarnApps.unendorsedAppIds(); console.log(`Remaining apps: ${remaining.length} ${remaining.join(", ")}`); if (remaining.length > 0) { const threshold = Number(await x2EarnApps.endorsementScoreThreshold()); console.log(`Threshold: ${threshold}`); for (const appId of remaining) { const score = Number(await x2EarnApps.getScore(appId)); console.error(`App ${appId} has ${score}/${threshold} endorsement points`); } throw new Error(`${remaining.length} app(s) did not reach endorsement threshold`); } console.log(`All apps verified as endorsed (>= ${await x2EarnApps.endorsementScoreThreshold()} pts)`); }; const setupLocalEnvironment = async (env, emissions, treasury, x2EarnApps, b3tr, vot3, stargateMock) => { const start = performance.now(); // Define specific accounts const admin = accounts[0]; // Make sure the first 10 accounts have a VTHO balance await (0, airdrop_1.airdropVTHO)(accounts.slice(1, 10).map(acct => acct.address), 5000n, admin); // Bootstrap emissions const emissionsContract = await emissions.getAddress(); await (0, emissions_1.bootstrapEmissions)(emissionsContract, admin); // Add x-apps to the XAllocationPool const x2EarnAppsAddress = await x2EarnApps.getAddress(); await (0, xApp_1.registerXDapps)(x2EarnAppsAddress, xDappCreatorAccounts, exports.APPS); // Assign categories to apps (deployer has DEFAULT_ADMIN_ROLE) const deployer = (await hardhat_1.ethers.getSigners())[0]; await (0, xApp_1.assignAppCategories)(x2EarnApps, deployer, exports.APPS); // Seed the first 10 accounts with B3TR + VOT3 const treasuryAddress = await treasury.getAddress(); const allAccounts = (0, seedAccounts_1.getSeedAccounts)(seedAccounts_1.SeedStrategy.FIXED, 10 + exports.APPS.length, 0); const first10 = allAccounts.slice(0, 10); const appCreatorSeedAccounts = allAccounts.slice(10); await (0, airdrop_1.airdropVTHO)(first10.map(acct => acct.key.address), 500n, admin); // Step 1: small airdrop (10k B3TR) → convert all to VOT3 const vot3Accounts = first10.map(a => ({ ...a, amount: hardhat_1.ethers.parseEther("10000") })); await (0, airdrop_1.airdropB3trFromTreasury)(treasuryAddress, admin, [...vot3Accounts, ...appCreatorSeedAccounts]); await (0, swap_1.convertB3trForVot3)(b3tr, vot3, vot3Accounts); // Step 2: airdrop 50k B3TR — stays as B3TR for challenges etc. const b3trAccounts = first10.map(a => ({ ...a, amount: hardhat_1.ethers.parseEther("50000") })); await (0, airdrop_1.airdropB3trFromTreasury)(treasuryAddress, admin, b3trAccounts); // If the first 8 accounts does not have the correct nodes, run the following line await (0, emissions_1.startEmissions)(emissionsContract, admin); // Endorsement strategy: on solo (local) we can mint mock Stargate NFTs because accounts // are pre-funded with VET. On real networks (testnet/testnet-staging) accounts lack VET, // so we set endorsement threshold to 0 and call checkEndorsement to auto-endorse. if (env === "local") { const allSigners = await hardhat_1.ethers.getSigners(); const endorserSigners = allSigners.slice(0, 10); await (0, airdrop_1.airdropVTHO)(endorserSigners.map(acct => sdk_core_1.Address.of(acct.address)), 5000n, admin); // Every endorser gets 3 MjolnirX nodes (need 3 per app since max 49 pts/node/app) // Total: 30 nodes x 100 pts = 3000 pts >> 8 apps x 100 threshold await (0, exports.endorseAndVerifySeededApps)(x2EarnApps, stargateMock, endorserSigners); } else { // testnet and testnet-staging: set threshold to 0 so apps auto-endorse via checkEndorsement await x2EarnApps .connect(deployer) .updateEndorsementScoreThreshold(0) .then(async (tx) => await tx.wait()); console.log("Endorsement score threshold set to 0"); const unendorsedApps = await x2EarnApps.unendorsedAppIds(); for (const appId of unendorsedApps) { const tx = await x2EarnApps.checkEndorsement(appId); await tx.wait(); } console.log(`checkEndorsement called for ${unendorsedApps.length} apps`); await verifyEndorsedApps(x2EarnApps); } const end = new Date(performance.now() - start); console.log(`Setup complete in ${end.getMinutes()}m ${end.getSeconds()}s`); }; exports.setupLocalEnvironment = setupLocalEnvironment; const setupMainnetEnvironment = async (emissions, x2EarnApps) => { console.log("================ Setup Mainnet environment"); const start = performance.now(); const mainnet_admin_addresses = new Map([ ["Mugshot", "0xbfe2122a82c0aea091514f57c7713c3118101eda"], ["Cleanify", "0x6b020e5c8e8574388a275cc498b27e3eb91ec3f2"], ["GreenCart", "0x4e506ee842ba8ccce88e424522506f5b860e5c9b"], ["Green Ambassador Challenge", "0x15e74aeb00d367a5a20c61b469df30a25f0e602f"], ["Oily", "0xd52e3356231c9fa86bb9fab731f8c0c3f1018753"], ["EVearn", "0xb2919e12d035a484f8414643b606b2a180224f54"], ["Vyvo", "0x61ffc950b04090f5ce857ebf056852a6d27b0c3c"], ["Non Fungible Book Club (NFBC)", "0xbe50d2fae95b23082f351e290548365e84ec1780"], ]); const admin = accounts[0]; // Bootstrap emissions const emissionsContract = await emissions.getAddress(); await (0, emissions_1.bootstrapEmissions)(emissionsContract, admin); // Add x-apps to the XAllocationPool console.log("Adding x-apps..."); // Add x-apps to the XAllocationPool const x2EarnAppsAddress = await x2EarnApps.getAddress(); // Overwrite the admin and teamWalletAddress with the mainnet addresses exports.APPS.forEach(app => { const newAddress = mainnet_admin_addresses.get(app.name); if (newAddress) { app.admin = newAddress; app.teamWalletAddress = newAddress; } else { throw new Error(`Mainnet admin address not found for ${app.name}`); } console.log(app.name); console.log("Admin: ", app.admin); console.log("Team Wallet Address: ", app.teamWalletAddress); }); await (0, xApp_1.registerXDapps)(x2EarnAppsAddress, xDappCreatorAccounts, exports.APPS); console.log("x-apps added"); const end = performance.now(); console.log(`Setup complete in ${end - start}ms`); }; exports.setupMainnetEnvironment = setupMainnetEnvironment;