Prevent reputation from decreasing below zero
This commit is contained in:
parent
e777a0ee85
commit
83f9007401
|
@ -0,0 +1,50 @@
|
|||
Reputation Tokens
|
||||
|
||||
Minting
|
||||
|
||||
Suppose it's possible to mint a reputation token.
|
||||
Say we have a contract that keeps track of all the reputation tokens.
|
||||
Suppose the reputation contract implements ERC720 (NFT).
|
||||
Assume a validation pool always corresponds to a post.
|
||||
A single token could be minted for each validation pool.
|
||||
That token could be subdivided so that each winning voter gets some.
|
||||
Perhaps voters get tokens that are specifically identifiable as governance reputation tokens.
|
||||
Then the main token can be awarded to the post author.
|
||||
Each token should carry a specific value.
|
||||
The forum will update the value of the token for the post author as well as posts affected by its chain of references.
|
||||
|
||||
Then, when participants wish to stake reputation (for voting or for availability),
|
||||
they must specify the amount and the token address which carries that reputation.
|
||||
The token should probably then lock that reputation, preventing it from being staked concurrently for another purpose.
|
||||
|
||||
Perhaps our interface can allow staking reputation from multiple tokens at the same time.
|
||||
And/or we can provide a mechanism for consolidating tokens.
|
||||
|
||||
Or maybe, if reputation is staked via a given token, then the reputation awards should go to that same token.
|
||||
In that case, when should new tokens be minted?
|
||||
|
||||
Maybe a token should be minted for each validation pool, but not subdivided.
|
||||
Voter rewards can just add value to the existing tokens from which reputation was staked.
|
||||
|
||||
Maybe a new token should only be minted if the author did not provide a token from which to stake reputation on their own post.
|
||||
This supports the case of a new author earning their first reputation.
|
||||
In that case the author may need to pay a fee to buy in to the DAO.
|
||||
Or perhaps they can be sponsored by one or more existing reputation token holders.
|
||||
Existing reputation holders could grant some reputation to a new member.
|
||||
Perhaps there could be a contract that allows sponsoring a new member, such that whatever fee is given,
|
||||
that fee will automatically be repaid from the new member's earnings, before the new member starts receiving their share of earnings.
|
||||
This could be a multi-party action, or could just be a generic operation that can be performed multiple times.
|
||||
|
||||
However, this effectively allows buying reputation, which goes against the core concept of reputation as evidence of performance.
|
||||
|
||||
It could make more sense for new members to submit some sort of petition, i.e. to make a post.
|
||||
|
||||
Maybe rather than submitting fees, existing members can grant some of their own reputation to a new member, and receive some sort of compensation if the new member does well.
|
||||
|
||||
So far the only workable model seems to be the idea that a new member must submit a post along with a fee, in order to be considered, and if the post is approved, they gain their first reputation.
|
||||
The amount of this fee can be up to the applicant, and/or can be regulated by soft protocols within the DAO.
|
||||
|
||||
If this is the only scenario in which new rep tokens are minted, and from then on their value is updated as a result of each validation pool,
|
||||
then we probably want each token to store information about the history of its value.
|
||||
At a minimum this can be a list where each item includes the identifier of the corresponding validation pool, and the resulting increment/decrement of token value.
|
||||
Each validation pool can then keep a record of the reputation staked by each voter, and the identifier of the corresponding post.
|
|
@ -83,44 +83,47 @@ export class Forum extends Actor {
|
|||
|
||||
const post = this.getPost(postId);
|
||||
post.setStatus('Validated');
|
||||
const rewards = await this.propagateValue(pool, post, initialValue);
|
||||
|
||||
// Compute rewards
|
||||
const rewards = new Map();
|
||||
await this.propagateValue(rewards, pool, post, initialValue);
|
||||
// Apply computed rewards
|
||||
for (const [id, value] of rewards) {
|
||||
bench.reputations.addTokens(id, value);
|
||||
}
|
||||
}
|
||||
|
||||
async propagateValue(fromActor, post, increment, depth = 0) {
|
||||
async propagateValue(rewards, fromActor, post, increment, depth = 0) {
|
||||
if (params.referenceChainLimit >= 0 && depth > params.referenceChainLimit) {
|
||||
return [];
|
||||
}
|
||||
|
||||
this.actions.propagateValue.log(fromActor, post, `(${increment})`);
|
||||
|
||||
// Apply leaching value
|
||||
const adjustedIncrement = increment * (1 - params.leachingValue * post.totalCitationWeight);
|
||||
|
||||
const rewards = new Map();
|
||||
const addReward = (id, value) => rewards.set(id, (rewards.get(id) ?? 0) + value);
|
||||
const addRewards = (r) => {
|
||||
for (const [id, value] of r) {
|
||||
addReward(id, value);
|
||||
}
|
||||
};
|
||||
|
||||
// Increment the value of the post
|
||||
await this.setPostValue(post, post.value + adjustedIncrement);
|
||||
|
||||
// Award reputation to post author
|
||||
console.log(`reward for post author ${post.authorPublicKey}`, adjustedIncrement);
|
||||
addReward(post.authorPublicKey, adjustedIncrement);
|
||||
|
||||
// Recursively distribute reputation to citations, according to weights
|
||||
let downstreamRefund = 0;
|
||||
for (const { postId: citedPostId, weight } of post.citations) {
|
||||
const citedPost = this.getPost(citedPostId);
|
||||
addRewards(await this.propagateValue(post, citedPost, weight * increment, depth + 1));
|
||||
downstreamRefund += await this.propagateValue(rewards, post, citedPost, weight * increment, depth + 1);
|
||||
}
|
||||
|
||||
return rewards;
|
||||
// Apply leaching value
|
||||
const adjustedIncrement = increment * (1 - params.leachingValue * post.totalCitationWeight) + downstreamRefund;
|
||||
|
||||
// Prevent value from decreasing below zero
|
||||
const rawNewValue = post.value + adjustedIncrement;
|
||||
const newValue = Math.max(0, rawNewValue);
|
||||
const upstreamRefund = rawNewValue < 0 ? rawNewValue : 0;
|
||||
const appliedIncrement = newValue - post.value;
|
||||
|
||||
// Increment the value of the post
|
||||
await this.setPostValue(post, newValue);
|
||||
|
||||
// Award reputation to post author
|
||||
console.log(`reward for post author ${post.authorPublicKey}`, appliedIncrement);
|
||||
|
||||
rewards.set(post.authorPublicKey, appliedIncrement);
|
||||
|
||||
return upstreamRefund;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -224,7 +224,7 @@ export class ValidationPool extends Actor {
|
|||
const tokensForWinners = getTotalStaked(!votePasses);
|
||||
const winningVotes = this.listVotes(({ position, isSystemVote }) => position === votePasses && !isSystemVote);
|
||||
|
||||
// Reward the winning voters, in proportion to their stakes
|
||||
// Compute rewards for the winning voters, in proportion to their stakes
|
||||
const rewards = new Map();
|
||||
for (const [signingPublicKey, { stake }] of winningVotes) {
|
||||
const { reputationPublicKey } = this.voters.get(signingPublicKey);
|
||||
|
@ -233,6 +233,7 @@ export class ValidationPool extends Actor {
|
|||
}
|
||||
|
||||
const authorReputationPublicKey = this.voters.get(this.authorSigningPublicKey).reputationPublicKey;
|
||||
|
||||
// Distribute awards to voters other than the author
|
||||
for (const [id, value] of rewards) {
|
||||
if (id !== authorReputationPublicKey) {
|
||||
|
@ -241,6 +242,8 @@ export class ValidationPool extends Actor {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: revoke staked reputation from losing voters
|
||||
|
||||
if (votePasses) {
|
||||
// Distribute awards to author via the forum
|
||||
const tokensForAuthor = this.tokensMinted * params.stakeForAuthor + rewards.get(authorReputationPublicKey);
|
||||
|
|
|
@ -5,15 +5,22 @@
|
|||
</head>
|
||||
<body>
|
||||
<h2>Tests</h2>
|
||||
<h3>Primary</h3>
|
||||
<ul>
|
||||
<li><a href="/tests/validation-pool.html">Validation Pool</a></li>
|
||||
<li><a href="/tests/availability.html">Availability + Business</a></li>
|
||||
<li><a href="/tests/forum.html">Forum</a></li>
|
||||
</ul>
|
||||
<h3>Secondary</h3>
|
||||
<ul>
|
||||
<li><a href="/tests/forum-network.html">Forum Network</a></li>
|
||||
</ul>
|
||||
<h3>Tertiary</h3>
|
||||
<ul>
|
||||
<li><a href="/tests/basic.html">Basic</a></li>
|
||||
<li><a href="/tests/forum-network.html">Forum Network</a></li>
|
||||
<li><a href="/tests/graph.html">Graph</a></li>
|
||||
<li><a href="/tests/validation-pool.html">Validation Pool</a></li>
|
||||
<li><a href="/tests/mermaid.html">Mermaid</a></li>
|
||||
<li><a href="/tests/graph.html">Graph</a></li>
|
||||
<li><a href="/tests/debounce.html">Debounce</a></li>
|
||||
<li><a href="/tests/availability.html">Availability</a></li>
|
||||
<li><a href="/tests/forum.html">Forum</a></li>
|
||||
<li><a href="/tests/flowchart.html">Flowchart</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
|
|
|
@ -21,7 +21,7 @@ const params = {
|
|||
/* Forum parameters */
|
||||
initialPostValue: () => 1, // q1
|
||||
revaluationLimit: 1, // q2
|
||||
maxPropagationDepth: 3, // q3
|
||||
referenceChainLimit: 3, // q3
|
||||
leachingValue: 1, // q4
|
||||
};
|
||||
|
||||
|
|
|
@ -122,9 +122,9 @@
|
|||
forum,
|
||||
new PostContent({ hello: "y'all" })
|
||||
.setTitle("Post 3")
|
||||
.addCitation(postId2, 0.5),
|
||||
.addCitation(postId2, -0.5),
|
||||
{
|
||||
fee: 10,
|
||||
fee: 100,
|
||||
duration: 1000,
|
||||
tokenLossRatio: 1,
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue