You have two testing environments: testnet and an instance of the blockchain running locally (a solo node).
Testing your app on testnet is more straightforward since all contracts are already deployed by us and you can use our testnet dApp to add apps, interact with smart contracts, and manage reward distribution.
Testing on solo will be a bit more complicated because you will need to deploy some mocked VeBetterDAO contracts by yourself, but we tried to make that easy as well.
Testnet
Use our testnet environment, running on vechain testnet network, to create apps, interact with smart contracts, and manage reward distribution.
Now you will need to get some B3TR tokens: claim them from the Faucet
Deposit the B3TR tokens to your app balance so you can distribute them: go to your managed app page, and click "Deposit" in the app balance section
To allow your contract to distribute the rewards you need to click the cogs icon to enter the Settings section of your app and add the address of your contract (that will call the distributeReward function) as a "Reward Distributor".
That's it, you are all set and can distribute rewards through your backend or smart contract.
If you need to simulate allocation rounds, go to the Admin section and press the "Start round" button. In testnet rounds last 10 minutes, but apart from this everything else is the same as mainnet.
Testing on the solo node is a bit more complicated than testing on testnet, since you will need to deploy the VeBetterDAO contracts locally and interact with them to create your app, obtain the APP_ID, start an allocation round, vote, start round again, and add the reward distributor.
We recommend following the testnet path, but if you need to do it on the solo network you will need to mock a few VeBetterDAO contracts:
B3TR token mock: you need a fake token to distribute
X2EarnApps mock: you need a contract where to add your app, generate an APP_ID and add a reward distributor
X2EarnRewardsPool mock: you need a contract to distribute the rewards
While the X2EarnRewardsPoolMock contract can be the exact same contract deployed on mainnet and testnet, the other two can be customized in order to have only the essential logic needed for running tests.
You can take a look at the mocked contracts in the X-App-Template repository, under the contracts/mocks folder.
After you added the mock contracts to your repository you should adjust the deploy script in a way that you will deploy and configure the mocked contracts only if you are deploying to the vechain_solo network.
Your script should look something like this:
import { ethers, network } from"hardhat";import { Challenges, Cleanify, RolesManager } from"../../typechain-types";import { networkConfig } from"@repo/config";import { deployProxy } from"../helpers/upgrades";import { faker } from"@faker-js/faker";letREWARD_TOKEN_ADDRESS="0xE5FEfcB230364ef7f9B5B0df6DA81B227726612b"; // mainnet addressexportasyncfunctiondeploy():Promise<{ mySustainableContractAddress:string;}> {console.log(`Deploying on ${network.name} (${networkConfig.network.defaultNodeUrl})...` );console.log(`Deploying my app contract...`);constMySustainableContract=awaitethers.getContractFactory("MySustainableContract");constmySustainableContract=awaitMySustainableContract.deploy();awaitmySustainableContract.waitForDeployment();console.log(`Sustainable Contract deployed to ${awaitmySustainableContract.getAddress()}`);if (network.name ==="vechain_solo") {console.log(`Deploying mock RewardToken...`);constRewardToken=awaitethers.getContractFactory("B3TR_Mock");constrewardToken=awaitRewardToken.deploy();awaitrewardToken.waitForDeployment();REWARD_TOKEN_ADDRESS=awaitrewardToken.getAddress();console.log(`RewardToken deployed to ${REWARD_TOKEN_ADDRESS}`);console.log("Deploying X2EarnApps mock contract...");constX2EarnApps=awaitethers.getContractFactory("X2EarnAppsMock");constx2EarnApps=awaitX2EarnApps.deploy();awaitx2EarnApps.waitForDeployment();console.log(`X2EarnApps deployed to ${awaitx2EarnApps.getAddress()}`);console.log("Deploying X2EarnRewardsPool mock contract...");constX2EarnRewardsPool=awaitethers.getContractFactory("X2EarnRewardsPoolMock" );constx2EarnRewardsPool=awaitX2EarnRewardsPool.deploy(deployer.address,REWARD_TOKEN_ADDRESS,awaitx2EarnApps.getAddress() );awaitx2EarnRewardsPool.waitForDeployment();console.log(`X2EarnRewardsPool deployed to ${awaitx2EarnRewardsPool.getAddress()}` );console.log("Adding app in X2EarnApps...");awaitx2EarnApps.addApp(deployer.address,deployer.address,"MySustainableApp");constappID=awaitx2EarnApps.hashAppName("MySustainableApp");console.log(`Funding contract...`);awaitrewardToken.approve(awaitx2EarnRewardsPool.getAddress(),ethers.parseEther("10000") );awaitx2EarnRewardsPool.deposit(ethers.parseEther("2000"), appID);console.log("Funded");console.log("Add MySustainableContract as distributor...");awaitx2EarnApps.addRewardDistributor( appID,awaitmySustainableContract.getAddress() );console.log("Added");console.log("Set APP_ID and X2EarnRewardsPool address in Challenges contract..." );awaitmySustainableContract.setVBDAppId(appID);awaitmySustainableContract.setX2EarnRewardsPool(awaitx2EarnRewardsPool.getAddress() );console.log("Set"); }return { mySustainableContract:awaitmySustainableContract.getAddress() };}
That's it, you can now deploy your contracts locally/run tests where you simulate the VeBetterDAO contracts, your app added to the ecosystem, and tokens distribution.