@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
JavaScript
;
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;