Requesting comments, additions, and feedback on proposal about the future of the outstanding $POW:
PROBLEM:
The current mechanism of the team increasing $POW rewards as we edge closer to the finalization of the $POW reward cutoff date favors newcomers entering the market as opposed to long-term stakeholders who have been staked since the beginning.
PROPOSED SOLUTION:
To combat the above, I propose that we do not continue to increase $POW emissions at dates pre-determined by the team. This would mean we would not fully deplete the committed $POW rewards by the cutoff date.
I’m proposing (a) that the current reward rate should be maintained until the end of the $POW distribution window, and (b) that the total time staked of each MetaHero should been factored into the final $POW distribution amounts.
POTENTIAL UPSIDE:
If we were to employ this method, it would not only appropriate $POW to long term believers, but it would also discourage people from de-staking early for risk of resetting their clocks and losing out on future $POW rewards.
Game theory wise, this may also have a net effect of having individuals burn more MPs to ensure they get their pro-rata share of $POW rewards.
PSEUDO-CODE:
Snapshot at cutoff for $POW distribution.
Snapshot the remainder of $POW remaining for distribution, let’s call it remainingPow
Let’s presume timeStaked is the seconds since epoch timestamp of each MH’s time staked. Summate all timeStaked as a cumulative total, timeStakedTotal , as well as per owner wallet in a mapped array, timeStakedTotalByOwner[wallet]
Each person’s contribution is the amount of time staked as a percentage of total time, so iterate over the array timeStakedTotalByOwner and calculate distributionPercentageToOwner = timeStakedTotalByOwner / timeStakedTotal , to get a percentage of each individual’s contributed time staked.
To calculate distribution amount to the wallet, multiply distributionPercentageToOwner * remainingPow
Correct, the goal is to formulate a weighted distribution to favor those who have been staking their MetaHeroes the longest.
One caveat/wrench in the idea is that it would only work if a user does not de-stake, which would presumably reset their timer. This would discourage sales but may create a mass liquidation event at time of $POW disbursement.
For those of you interested in the actual implementation level details of this, I started to mock up the necessary code for actually calculating this on chain. It’s not complete, but it’s a good starting point.
const fs = require('fs');
const Web3 = require('web3');
const BigNumber = require('bignumber.js');
const contracts = [
{
name: 'core',
address: '0xFb10b1717C92e9cc2d634080c3c337808408D9E1',
abi: './storage/metahero-core-abi.json',
max_id: 84
},
{
name: 'hero',
address: '0x6dc6001535e15b9def7b0f6a20a2111dfa9454e2',
abi: './storage/metahero-abi.json',
max_id: 6614
}
];
(async() => {
let headerFound = false;
let totalBalance = new BigNumber(0);
let results = [];
let ownerMap = {};
// add headers
results.push(['id', 'contract_address', 'owner']);
// initialize with infura
const provider = new Web3.providers.HttpProvider('ENTER_YOUR_INFURA_PROVIDER_URL_HERE');
const web3 = new Web3(provider);
for (const data of contracts) {
ownerMap[data.address] = {};
let contractAbi = fs.readFileSync(data.abi, 'utf8');
contractAbi = JSON.parse(contractAbi);
const contractAddress = data.address;
const contract = new web3.eth.Contract(contractAbi, contractAddress);
// TODO: do we need to disregard certain wallets?
// updao treasury: 0x19c30ad5ea4f7f9f36a8662b5fa2cbc09e55fded
// NOTE: staking wallet is 0x6ce31a42058f5496005b39272c21c576941dbfe9
// started with 195,665,261.89 $POW on 2021-12-05 20:24:30
// to calculate rewards... call `calculateRewards()` and/or `calculateRewardsByAccount()` on
// https://etherscan.io/address/0x6ce31a42058f5496005b39272c21c576941dbfe9#readContract
// for each of the 6614 metahero identities (total derived from https://etherscan.io/address/0x6dc6001535e15b9def7b0f6a20a2111dfa9454e2)
let i = 1;
const max_id = data.max_id + 1;
for (i; i < max_id; i++) {
try {
const tokenId = new BigNumber(i);
console.log(`${data.name} - Checking id ${i}`);
const result = await contract.methods.ownerOf(tokenId).call();
// store balance
results.push([i, data.address, result.toString()]);
if (typeof ownerMap[data.address][result] === 'undefined') {
ownerMap[data.address][result] = [];
}
ownerMap[data.address][result].push(i);
} catch (e) {
if (e.message === 'Returned error: execution reverted: ERC721: owner query for nonexistent token') {
// console.error('Owner query for nonexistent token');
results.push([i, data.address, '']);
} else {
// retry
console.error(`${data.name} - ERROR: ${e.message}`, e);
i = i - 1;
}
}
}
}
// store results
for (const key in results) {
results[key] = results[key].join(',');
}
console.log('Saving ./storage/metahero-owners.csv');
fs.writeFileSync('./storage/metahero-owners.csv', results.join('\n'));
const ownerMapFinal = [];
for (const contract_address in ownerMap) {
for (const owner in ownerMap[contract_address]) {
const ids = ownerMap[contract_address][owner].join(',');
ownerMapFinal.push('"' + owner + '","' + contract_address + '","' + ids + '"');
}
}
console.log('Saving ./storage/metahero-owners-map.csv');
fs.writeFileSync('./storage/metahero-owners-map.csv', ownerMapFinal.join('\n'));
})();
function trim (s, c) {
if (c === "]") c = "\\]";
if (c === "^") c = "\\^";
if (c === "\\") c = "\\\\";
return s.replace(new RegExp(
"^[" + c + "]+|[" + c + "]+$", "g"
), "");
}
At this point I believe it would simply be PV that decides. I would support this proposal if it was do-able, I just don’t see how the PVFD has authority over $POW distribution. We could suggest this to GFunk and see what he thinks, but I don’t think we’d have the control to actually put this in place ourselves.
I don’t think we should factor time into pow distribution because this would not incentivize new people to stake near the end. Additionally, as @LukasNFT noted, this should be an UPDAO decision (although this voting mechanic is not in place).