89 lines
2.2 KiB
JavaScript
89 lines
2.2 KiB
JavaScript
class Lock {
|
|
constructor(tokens, duration) {
|
|
this.dateCreated = new Date();
|
|
this.tokens = tokens;
|
|
this.duration = duration;
|
|
}
|
|
}
|
|
|
|
class Reputation {
|
|
constructor() {
|
|
this.tokens = 0;
|
|
this.locks = new Set();
|
|
}
|
|
|
|
addTokens(tokens) {
|
|
if (this.tokens + tokens < 0) {
|
|
throw new Error('Token balance can not become negative');
|
|
}
|
|
this.tokens += tokens;
|
|
}
|
|
|
|
lockTokens(tokens, duration) {
|
|
if (tokens > this.getAvailableTokens()) {
|
|
throw new Error('Can not lock more tokens than are available');
|
|
}
|
|
const lock = new Lock(tokens, duration);
|
|
this.locks.add(lock);
|
|
// TODO: Prune locks once expired
|
|
}
|
|
|
|
getTokens() {
|
|
return this.tokens;
|
|
}
|
|
|
|
getAvailableTokens() {
|
|
const now = new Date();
|
|
const tokensLocked = Array.from(this.locks.values())
|
|
.filter(({ dateCreated, duration }) => now - dateCreated < duration)
|
|
.reduce((acc, cur) => acc += cur.tokens, 0);
|
|
if (tokensLocked > this.tokens) {
|
|
throw new Error('Assertion failure. tokensLocked > tokens');
|
|
}
|
|
return this.tokens - tokensLocked;
|
|
}
|
|
}
|
|
|
|
export class Reputations extends Map {
|
|
getTokens(reputationPublicKey) {
|
|
const reputation = this.get(reputationPublicKey);
|
|
if (!reputation) {
|
|
return 0;
|
|
}
|
|
return reputation.getTokens();
|
|
}
|
|
|
|
getAvailableTokens(reputationPublicKey) {
|
|
const reputation = this.get(reputationPublicKey);
|
|
if (!reputation) {
|
|
return 0;
|
|
}
|
|
return reputation.getAvailableTokens();
|
|
}
|
|
|
|
addTokens(reputationPublicKey, tokens) {
|
|
const reputation = this.get(reputationPublicKey) ?? new Reputation();
|
|
reputation.addTokens(tokens);
|
|
this.set(reputationPublicKey, reputation);
|
|
}
|
|
|
|
lockTokens(reputationPublicKey, tokens, duration) {
|
|
if (!tokens || !duration) {
|
|
return;
|
|
}
|
|
const reputation = this.get(reputationPublicKey);
|
|
if (!reputation) {
|
|
throw new Error(`${reputationPublicKey} has no tokens to lock`);
|
|
}
|
|
reputation.lockTokens(tokens, duration);
|
|
}
|
|
|
|
getTotal() {
|
|
return Array.from(this.values()).reduce((acc, cur) => acc += cur.getTokens(), 0);
|
|
}
|
|
|
|
getTotalAvailable() {
|
|
return Array.from(this.values()).reduce((acc, cur) => acc += cur.getAvailableTokens(), 0);
|
|
}
|
|
}
|