Merge branch 'dev' into 'main'
Add support for manually stepping through tests See merge request dao-governance-framework/science-publishing-dao!2
This commit is contained in:
commit
c4a528283c
|
@ -37,6 +37,7 @@ module.exports = {
|
||||||
'no-multi-assign': ['off'],
|
'no-multi-assign': ['off'],
|
||||||
'no-constant-condition': ['off'],
|
'no-constant-condition': ['off'],
|
||||||
'no-await-in-loop': ['off'],
|
'no-await-in-loop': ['off'],
|
||||||
|
'no-underscore-dangle': ['off'],
|
||||||
},
|
},
|
||||||
globals: {
|
globals: {
|
||||||
_: 'readonly',
|
_: 'readonly',
|
||||||
|
@ -44,5 +45,6 @@ module.exports = {
|
||||||
sinon: 'readonly',
|
sinon: 'readonly',
|
||||||
sinonChai: 'readonly',
|
sinonChai: 'readonly',
|
||||||
should: 'readonly',
|
should: 'readonly',
|
||||||
|
mocha: 'readonly',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
# Revenue-generating work
|
||||||
|
|
||||||
|
## Expert stakes REP to register availability
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph
|
||||||
|
|
||||||
|
subgraph EOA
|
||||||
|
expert(Expert)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Contracts
|
||||||
|
availability(Availability)
|
||||||
|
end
|
||||||
|
|
||||||
|
expert -- 1. Stake ℝ --> availability
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Public submits work request with fee
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph
|
||||||
|
|
||||||
|
subgraph EOA
|
||||||
|
expert(Expert)
|
||||||
|
public(Public)
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Contracts
|
||||||
|
business(Business)
|
||||||
|
availability(Availability)
|
||||||
|
end
|
||||||
|
|
||||||
|
public -- 1. Request<br />with fee $ --> business
|
||||||
|
business -- 2. Assign<br />work --> availability
|
||||||
|
availability -- 3. Transfer<br />staked ℝ --> business
|
||||||
|
availability -- 4. TODO Notify --> expert
|
||||||
|
```
|
||||||
|
|
||||||
|
## Expert submits work evidence
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph
|
||||||
|
|
||||||
|
subgraph EOA
|
||||||
|
expert(Expert)
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Contracts
|
||||||
|
business(Business)
|
||||||
|
forum(Forum)
|
||||||
|
pool(Pool)
|
||||||
|
end
|
||||||
|
|
||||||
|
expert -- 1. Work<br />evidence --> business
|
||||||
|
business -- 2. Post --> forum
|
||||||
|
business -- 3. Stake ℝ --> pool
|
||||||
|
```
|
||||||
|
|
||||||
|
## Peers validate the work evidence
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph
|
||||||
|
|
||||||
|
subgraph EOA
|
||||||
|
peers(Peers)
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Contracts
|
||||||
|
forum(Forum)
|
||||||
|
pool(Pool)
|
||||||
|
end
|
||||||
|
|
||||||
|
peers -- 8. Stake ℝ --> pool
|
||||||
|
pool -- 9. Validate post,<br />Transfer ℝ --> forum
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rewards are distributed
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph
|
||||||
|
|
||||||
|
subgraph EOA
|
||||||
|
expert(Expert)
|
||||||
|
peers(Peers)
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Contracts
|
||||||
|
pool(Pool)
|
||||||
|
business(Business)
|
||||||
|
forum(Forum)
|
||||||
|
end
|
||||||
|
|
||||||
|
pool -- Reward ℝ --> peers
|
||||||
|
forum -- Award ℝ --> expert
|
||||||
|
forum -- Award ℝ<br />via citation<br />WDAG --> peers
|
||||||
|
business -- Award % fee $<br />weighted by ℝ--> expert
|
||||||
|
business -- Award % fee $<br />weighted by ℝ--> peers
|
||||||
|
```
|
|
@ -1,43 +0,0 @@
|
||||||
# Primary
|
|
||||||
|
|
||||||
## Forum
|
|
||||||
|
|
||||||
## ValidationPool
|
|
||||||
|
|
||||||
## ReputationToken
|
|
||||||
|
|
||||||
## WDAG
|
|
||||||
|
|
||||||
# Secondary
|
|
||||||
|
|
||||||
## Availability
|
|
||||||
|
|
||||||
## Business
|
|
||||||
|
|
||||||
## ERC721
|
|
||||||
|
|
||||||
## Expert
|
|
||||||
|
|
||||||
## Bench
|
|
||||||
|
|
||||||
# Tertiary
|
|
||||||
|
|
||||||
## Actor
|
|
||||||
|
|
||||||
## Action
|
|
||||||
|
|
||||||
## Scene
|
|
||||||
|
|
||||||
# To Explore
|
|
||||||
|
|
||||||
## Exchange
|
|
||||||
|
|
||||||
## Storage
|
|
||||||
|
|
||||||
## Network
|
|
||||||
|
|
||||||
## Wallet
|
|
||||||
|
|
||||||
## Agent/UI
|
|
||||||
|
|
||||||
## BlockConsensus
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
## Client/UI
|
||||||
|
|
||||||
|
Voting consists of staking operations performed by software operated by owners of EOA.
|
||||||
|
|
||||||
|
This software may be referred to as "The UI". It may also be considered "a client".
|
||||||
|
|
||||||
|
It will need to be a network-connected application. It will need a certain minimum of RAM,
|
||||||
|
and for some features disk storage,
|
||||||
|
and for some features uptime .
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Client Operations
|
||||||
|
|
||||||
|
Client must communicate with one or more servers.
|
||||||
|
|
||||||
|
Client must build a local view
|
|
@ -33,3 +33,114 @@ WHAT is our protocol for evaluating the perspectives offered by peers?
|
||||||
- If there is the HOPE of exact agreement, mistakes and attacks can be costly
|
- If there is the HOPE of exact agreement, mistakes and attacks can be costly
|
||||||
|
|
||||||
- If there is an EXPECTATION of exact agreement, there must be externalities supporting that agreement, i.e. a common protocol and governance of that protocol.
|
- If there is an EXPECTATION of exact agreement, there must be externalities supporting that agreement, i.e. a common protocol and governance of that protocol.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Internal operations
|
||||||
|
|
||||||
|
## Expert starts new DAO
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph
|
||||||
|
|
||||||
|
subgraph EOA
|
||||||
|
expert(Expert)
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Contracts
|
||||||
|
forum(Forum)
|
||||||
|
pool(Pool)
|
||||||
|
end
|
||||||
|
|
||||||
|
expert -- Post --> forum
|
||||||
|
expert -- Fee $ --> pool
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Expert joins existing DAO
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph
|
||||||
|
|
||||||
|
subgraph EOA
|
||||||
|
expert(Expert)
|
||||||
|
peers(Peers)
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Contracts
|
||||||
|
forum(Forum)
|
||||||
|
pool(Pool)
|
||||||
|
end
|
||||||
|
|
||||||
|
expert -- 1. Post --> forum
|
||||||
|
expert -- 2. Fee $ --> pool
|
||||||
|
peers -- 3. Stake ℝ<br />to approve --> pool
|
||||||
|
```
|
||||||
|
|
||||||
|
## Expert submits governance post
|
||||||
|
|
||||||
|
A governance post can be considered one that is respected in some way by the operations of the [Client/UI](./client-or-ui.md).
|
||||||
|
|
||||||
|
This is a broad class of posts.
|
||||||
|
|
||||||
|
Each type of governance post can be individually (or by category?) handled by the business contract for a given DAO.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph
|
||||||
|
|
||||||
|
subgraph EOA
|
||||||
|
expert(Expert)
|
||||||
|
peers(Peers)
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Contracts
|
||||||
|
forum(Forum)
|
||||||
|
pool(Pool)
|
||||||
|
business(Business)
|
||||||
|
end
|
||||||
|
|
||||||
|
expert -- 1. Stake ℝ on<br />governance post --> business
|
||||||
|
business -- 2. Post --> forum
|
||||||
|
business -- 2. Fee $ from<br />internal fund? --> pool
|
||||||
|
peers -- 3. Stake ℝ<br />to approve --> pool
|
||||||
|
pool -- 4. Validate --> forum
|
||||||
|
```
|
||||||
|
|
||||||
|
Forum usage is open-ended.
|
||||||
|
DAO protocol consists of core contracts + client behaviors.
|
||||||
|
Core contracts provide resilience to attacks, since reputation minting is financially backed by future income
|
||||||
|
|
||||||
|
Question: What does the DAO do with funds it receives?
|
||||||
|
Awswer: Distributes the funds to members immediately upon resolution of the reputation effects of a funded validation pool.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Before we delve into example use cases, we need to talk about the [Client/UI](./client-or-ui.md), and make sure we have
|
||||||
|
a sound understanding of how client/ui behaviors interact with the core of the system.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
The forum, pool, business, and availability contracts all work together to express a single DAO.
|
||||||
|
|
||||||
|
Each post in the forum can be its own new DAO
|
||||||
|
|
||||||
|
What it would take for that to happen:
|
||||||
|
|
||||||
|
The seed of the new DAO becomes the tokens minted by that post DAO when it receives fees.
|
||||||
|
|
||||||
|
When will it receive fees? When submitted to its business contract interface.
|
||||||
|
|
||||||
|
What happens then? Work is assigned via availability stakes.
|
||||||
|
|
||||||
|
Meaning that someone has staked reputation.
|
||||||
|
|
||||||
|
Meaning that they had previously been awarded reputation.
|
||||||
|
|
||||||
|
The business contract, or the DAO, or the seed post, must be able to accept an initial fee
|
||||||
|
to mint the reputation of the first expert.
|
||||||
|
|
||||||
|
Then, that expert can stake their reputation on availability to perform the work expressed by the post and its associated business contract.
|
||||||
|
|
||||||
|
These operations can be consolidated.
|
||||||
|
|
||||||
|
When submitting a post to the forum, you may include an optional fee
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Each DAO needs to allocate some of its incoming fees to incentivize development.
|
|
@ -0,0 +1,30 @@
|
||||||
|
Matrix uses rooms to establish contexts.
|
||||||
|
|
||||||
|
We can have a forum context,
|
||||||
|
wherein a few things happen.
|
||||||
|
|
||||||
|
One is that the forum will have a root post; equivalently, any post can be the root of a forum.
|
||||||
|
|
||||||
|
The context of that post can be preserved.
|
||||||
|
|
||||||
|
The forum is thus a collection of posts. Each post MAY have its own internal structure.
|
||||||
|
A post MAY "replace" a prior post. This consists of on-chain and off-chain elements.
|
||||||
|
On-chain, a new post replaces a prior post.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Reading Matrix spec, https://spec.matrix.org/latest/
|
||||||
|
|
||||||
|
> Events are signed by the originating server (the signature includes the parent relations, type, depth and payload hash) and are pushed over federation to the participating servers in a room, currently using full mesh topology. Servers may also request backfill of events over federation from the other servers participating in a room.
|
||||||
|
|
||||||
|
> In order to ensure that the mapping from 3PID to user ID is genuine, a globally federated cluster of trusted “identity servers” (IS) are used to verify the 3PID and persist and replicate the mappings.
|
||||||
|
>
|
||||||
|
> Usage of an IS is not required in order for a client application to be part of the Matrix ecosystem. However, without one clients will not be able to look up user IDs using 3PIDs.
|
||||||
|
|
||||||
|
> Users may publish arbitrary key/value data associated with their account
|
||||||
|
>
|
||||||
|
> - such as a human-readable display name, a profile photo URL, contact information (email address, phone numbers, website URLs etc).
|
||||||
|
|
||||||
|
> Users may also store arbitrary private key/value data in their account - such as client preferences, or server configuration settings which lack any other dedicated API. The API is symmetrical to managing Profile data.
|
||||||
|
|
||||||
|
> The client-server API allows clients to send messages, control rooms and synchronise conversation history. It is designed to support both lightweight clients which store no state and lazy-load data from the server as required - as well as heavyweight clients which maintain a full local persistent copy of server state.
|
|
@ -0,0 +1,4 @@
|
||||||
|
digraph {
|
||||||
|
layout=neato
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
```mermaid
|
||||||
|
graph
|
||||||
|
classDef blue fill:#08f, color:#d8d8d8, stroke-width: 0
|
||||||
|
classDef yellow fill:#dd0, color:#a0c, stroke-width: 0
|
||||||
|
classDef green fill:#8c8, color:#333, stroke-width: 0
|
||||||
|
classDef purple stroke:#c38, stroke-width:2px, fill:#bbf, color:#c38
|
||||||
|
classDef orange fill:#d60, color:#dff, stroke-width: 0
|
||||||
|
classDef fuscia fill:#f6c, color:#00c
|
||||||
|
|
||||||
|
nodeSpec(Node spec<br />Matrix homeservers):::blue
|
||||||
|
storageSpec(Storage spec<br />Matrix homeservers):::orange
|
||||||
|
archiveSpec(Archive spec<br />Weavechain):::green
|
||||||
|
blockchainSpec(Blockchain spec):::purple
|
||||||
|
peerProtocolSpec(Peer protocol spec<br />Matrix messaging):::yellow
|
||||||
|
uiSpec(UI spec<br />Matrix client):::fuscia
|
||||||
|
|
||||||
|
|
||||||
|
nodeSpec --- uiSpec
|
||||||
|
linkStyle 0 stroke:#08f
|
||||||
|
nodeSpec --- storageSpec
|
||||||
|
linkStyle 1 stroke:#08f
|
||||||
|
nodeSpec --- peerProtocolSpec
|
||||||
|
linkStyle 2 stroke:#08f
|
||||||
|
nodeSpec --- archiveSpec
|
||||||
|
linkStyle 3 stroke:#08f
|
||||||
|
nodeSpec --- blockchainSpec
|
||||||
|
linkStyle 4 stroke:#08f
|
||||||
|
|
||||||
|
peerProtocolSpec --- storageSpec
|
||||||
|
linkStyle 5 stroke:#d60
|
||||||
|
|
||||||
|
storageSpec --- blockchainSpec
|
||||||
|
linkStyle 6 stroke:#c38
|
||||||
|
storageSpec --- archiveSpec
|
||||||
|
linkStyle 7 stroke:#8c8
|
||||||
|
|
||||||
|
archiveSpec --- blockchainSpec
|
||||||
|
linkStyle 8 stroke:#c38
|
||||||
|
|
||||||
|
uiSpec --- blockchainSpec
|
||||||
|
linkStyle 9 stroke:#c38
|
||||||
|
uiSpec --- archiveSpec
|
||||||
|
linkStyle 10 stroke:#8c8
|
||||||
|
uiSpec --- storageSpec
|
||||||
|
linkStyle 11 stroke:#d60
|
||||||
|
```
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph
|
||||||
|
|
||||||
|
forum --- pool
|
||||||
|
availability --- business
|
||||||
|
business --- forum
|
||||||
|
business --- pool
|
||||||
|
|
||||||
|
```
|
|
@ -1,7 +1,7 @@
|
||||||
import { Action } from '../display/action.js';
|
import { Action } from '../display/action.js';
|
||||||
import { PostMessage } from '../forum-network/message.js';
|
import { PostMessage } from '../forum-network/message.js';
|
||||||
import { CryptoUtil } from '../util/crypto.js';
|
import { CryptoUtil } from '../util/crypto.js';
|
||||||
import { ReputationHolder } from './reputation-holder.js';
|
import { ReputationHolder } from '../reputation/reputation-holder.js';
|
||||||
|
|
||||||
export class Expert extends ReputationHolder {
|
export class Expert extends ReputationHolder {
|
||||||
constructor(dao, name, scene) {
|
constructor(dao, name, scene) {
|
||||||
|
@ -47,7 +47,7 @@ export class Expert extends ReputationHolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
async initiateValidationPool(poolOptions) {
|
async initiateValidationPool(poolOptions) {
|
||||||
// For now, directly call bench.initiateValidationPool();
|
// For now, make direct call rather than network
|
||||||
poolOptions.reputationPublicKey = this.reputationPublicKey;
|
poolOptions.reputationPublicKey = this.reputationPublicKey;
|
||||||
const pool = await this.dao.initiateValidationPool(poolOptions);
|
const pool = await this.dao.initiateValidationPool(poolOptions);
|
||||||
this.tokens.push(pool.tokenId);
|
this.tokens.push(pool.tokenId);
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
import { Actor } from '../display/actor.js';
|
|
||||||
import { displayNumber } from '../../util.js';
|
|
||||||
import params from '../../params.js';
|
|
||||||
|
|
||||||
export class Post extends Actor {
|
|
||||||
constructor(forum, authorPublicKey, postContent) {
|
|
||||||
const index = forum.posts.countVertices();
|
|
||||||
const name = `Post${index + 1}`;
|
|
||||||
super(name, forum.scene);
|
|
||||||
this.id = postContent.id ?? name;
|
|
||||||
this.authorPublicKey = authorPublicKey;
|
|
||||||
this.value = 0;
|
|
||||||
this.initialValue = 0;
|
|
||||||
this.citations = postContent.citations;
|
|
||||||
this.title = postContent.title;
|
|
||||||
const leachingTotal = this.citations
|
|
||||||
.filter(({ weight }) => weight < 0)
|
|
||||||
.reduce((total, { weight }) => total += -weight, 0);
|
|
||||||
const donationTotal = this.citations
|
|
||||||
.filter(({ weight }) => weight > 0)
|
|
||||||
.reduce((total, { weight }) => total += weight, 0);
|
|
||||||
if (leachingTotal > params.revaluationLimit) {
|
|
||||||
throw new Error('Post leaching total exceeds revaluation limit '
|
|
||||||
+ `(${leachingTotal} > ${params.revaluationLimit})`);
|
|
||||||
}
|
|
||||||
if (donationTotal > params.revaluationLimit) {
|
|
||||||
throw new Error('Post donation total exceeds revaluation limit '
|
|
||||||
+ `(${donationTotal} > ${params.revaluationLimit})`);
|
|
||||||
}
|
|
||||||
if (this.citations.some(({ weight }) => Math.abs(weight) > params.revaluationLimit)) {
|
|
||||||
throw new Error(`Each citation magnitude must not exceed revaluation limit ${params.revaluationLimit}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getLabel() {
|
|
||||||
return `${this.name}
|
|
||||||
<table><tr>
|
|
||||||
<td>initial</td>
|
|
||||||
<td>${displayNumber(this.initialValue)}</td>
|
|
||||||
</tr><tr>
|
|
||||||
<td>value</td>
|
|
||||||
<td>${displayNumber(this.value)}</td>
|
|
||||||
</tr></table>`
|
|
||||||
.replaceAll(/\n\s*/g, '');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
import params from '../../params.js';
|
import params from '../../params.js';
|
||||||
import { Forum } from './forum.js';
|
import { Forum } from './forum.js';
|
||||||
import { ReputationTokenContract } from '../contracts/reputation-token.js';
|
import { ReputationTokenContract } from '../reputation/reputation-token.js';
|
||||||
import { ValidationPool } from './validation-pool.js';
|
import { ValidationPool } from './validation-pool.js';
|
||||||
import { Availability } from './availability.js';
|
import { Availability } from './availability.js';
|
||||||
import { Business } from './business.js';
|
import { Business } from './business.js';
|
||||||
|
@ -72,9 +72,4 @@ export class DAO extends Actor {
|
||||||
|
|
||||||
return pool;
|
return pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
async submitPost(reputationPublicKey, postContent) {
|
|
||||||
const post = await this.forum.addPost(reputationPublicKey, postContent);
|
|
||||||
return post.id;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,13 +1,56 @@
|
||||||
import { WDAG } from '../supporting/wdag.js';
|
import { WDAG } from '../supporting/wdag.js';
|
||||||
import { Action } from '../display/action.js';
|
import { Action } from '../display/action.js';
|
||||||
|
import { Actor } from '../display/actor.js';
|
||||||
import params from '../../params.js';
|
import params from '../../params.js';
|
||||||
import { ReputationHolder } from './reputation-holder.js';
|
import { ReputationHolder } from '../reputation/reputation-holder.js';
|
||||||
import { displayNumber, EPSILON } from '../../util.js';
|
import { displayNumber, EPSILON } from '../../util.js';
|
||||||
import { Post } from './post.js';
|
|
||||||
|
|
||||||
const CITATION = 'citation';
|
const CITATION = 'citation';
|
||||||
const BALANCE = 'balance';
|
const BALANCE = 'balance';
|
||||||
|
|
||||||
|
class Post extends Actor {
|
||||||
|
constructor(forum, authorPublicKey, postContent) {
|
||||||
|
const index = forum.posts.countVertices();
|
||||||
|
const name = `Post${index + 1}`;
|
||||||
|
super(name, forum.scene);
|
||||||
|
this.id = postContent.id ?? name;
|
||||||
|
this.authorPublicKey = authorPublicKey;
|
||||||
|
this.value = 0;
|
||||||
|
this.initialValue = 0;
|
||||||
|
this.citations = postContent.citations;
|
||||||
|
this.title = postContent.title;
|
||||||
|
const leachingTotal = this.citations
|
||||||
|
.filter(({ weight }) => weight < 0)
|
||||||
|
.reduce((total, { weight }) => total += -weight, 0);
|
||||||
|
const donationTotal = this.citations
|
||||||
|
.filter(({ weight }) => weight > 0)
|
||||||
|
.reduce((total, { weight }) => total += weight, 0);
|
||||||
|
if (leachingTotal > params.revaluationLimit) {
|
||||||
|
throw new Error('Post leaching total exceeds revaluation limit '
|
||||||
|
+ `(${leachingTotal} > ${params.revaluationLimit})`);
|
||||||
|
}
|
||||||
|
if (donationTotal > params.revaluationLimit) {
|
||||||
|
throw new Error('Post donation total exceeds revaluation limit '
|
||||||
|
+ `(${donationTotal} > ${params.revaluationLimit})`);
|
||||||
|
}
|
||||||
|
if (this.citations.some(({ weight }) => Math.abs(weight) > params.revaluationLimit)) {
|
||||||
|
throw new Error(`Each citation magnitude must not exceed revaluation limit ${params.revaluationLimit}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getLabel() {
|
||||||
|
return `${this.name}
|
||||||
|
<table><tr>
|
||||||
|
<td>initial</td>
|
||||||
|
<td>${displayNumber(this.initialValue)}</td>
|
||||||
|
</tr><tr>
|
||||||
|
<td>value</td>
|
||||||
|
<td>${displayNumber(this.value)}</td>
|
||||||
|
</tr></table>`
|
||||||
|
.replaceAll(/\n\s*/g, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Purpose:
|
* Purpose:
|
||||||
* - Forum: Maintain a directed, acyclic, graph of positively and negatively weighted citations.
|
* - Forum: Maintain a directed, acyclic, graph of positively and negatively weighted citations.
|
|
@ -1,4 +1,4 @@
|
||||||
import { ReputationHolder } from './reputation-holder.js';
|
import { ReputationHolder } from '../reputation/reputation-holder.js';
|
||||||
import { Stake } from '../supporting/stake.js';
|
import { Stake } from '../supporting/stake.js';
|
||||||
import { Voter } from '../supporting/voter.js';
|
import { Voter } from '../supporting/voter.js';
|
||||||
import params from '../../params.js';
|
import params from '../../params.js';
|
|
@ -4,6 +4,15 @@ export class Action {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param src
|
||||||
|
* @param dest
|
||||||
|
* @param msg
|
||||||
|
* @param obj
|
||||||
|
* @param symbol
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
async log(src, dest, msg, obj, symbol = '->>') {
|
async log(src, dest, msg, obj, symbol = '->>') {
|
||||||
await this.scene?.sequence?.log(
|
await this.scene?.sequence?.log(
|
||||||
`${src.name} ${symbol} ${dest.name} : ${this.name} ${msg ?? ''} ${
|
`${src.name} ${symbol} ${dest.name} : ${this.name} ${msg ?? ''} ${
|
||||||
|
|
|
@ -2,16 +2,20 @@ import { DisplayValue } from './display-value.js';
|
||||||
import { randomID } from '../../util.js';
|
import { randomID } from '../../util.js';
|
||||||
|
|
||||||
export class Box {
|
export class Box {
|
||||||
constructor(name, parentEl, elementType = 'div') {
|
constructor(name, parentEl, options = {}) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.el = document.createElement(elementType);
|
this.el = document.createElement('div');
|
||||||
this.el.id = `box_${randomID()}`;
|
this.el.id = `box_${randomID()}`;
|
||||||
this.el.classList.add('box');
|
this.el.classList.add('box');
|
||||||
if (name) {
|
if (name) {
|
||||||
this.el.setAttribute('box-name', name);
|
this.el.setAttribute('box-name', name);
|
||||||
}
|
}
|
||||||
if (parentEl) {
|
if (parentEl) {
|
||||||
parentEl.appendChild(this.el);
|
if (options.prepend) {
|
||||||
|
parentEl.prepend(this.el);
|
||||||
|
} else {
|
||||||
|
parentEl.appendChild(this.el);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,8 +39,8 @@ export class Box {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
addBox(name, elementType) {
|
addBox(name) {
|
||||||
const box = new Box(name, this.el, elementType);
|
const box = new Box(name, this.el);
|
||||||
return box;
|
return box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
class Button {
|
||||||
|
constructor(innerHTML, onclick) {
|
||||||
|
this.el = document.createElement('button');
|
||||||
|
this.el.innerHTML = innerHTML;
|
||||||
|
this.el.onclick = onclick;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Controls {
|
||||||
|
constructor(parentBox) {
|
||||||
|
this.disableAutoplayButton = new Button('Disable Auto-play', () => {
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
url.searchParams.set('auto', 'false');
|
||||||
|
window.location.href = url.href;
|
||||||
|
});
|
||||||
|
this.enableAutoplayButton = new Button('Enable Auto-play', () => {
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
url.searchParams.delete('auto');
|
||||||
|
window.location.href = url.href;
|
||||||
|
});
|
||||||
|
this.stepButton = new Button('Next Action', () => {
|
||||||
|
console.log('Next Action button clicked');
|
||||||
|
document.dispatchEvent(new Event('next-action'));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (window.autoPlay) {
|
||||||
|
parentBox.el.appendChild(this.disableAutoplayButton.el);
|
||||||
|
} else {
|
||||||
|
parentBox.el.appendChild(this.enableAutoplayButton.el);
|
||||||
|
parentBox.el.appendChild(this.stepButton.el);
|
||||||
|
// Disable `stepButton` when test is complete
|
||||||
|
setInterval(() => {
|
||||||
|
this.stepButton.el.disabled = mocha._state !== 'running';
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function delayOrWait(delayMs) {
|
||||||
|
if (window.autoPlay) {
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
setTimeout(resolve, delayMs);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
document.addEventListener('next-action', () => {
|
||||||
|
console.log('next-action event received');
|
||||||
|
resolve();
|
||||||
|
}, { once: true });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,8 @@ import { MermaidDiagram } from './mermaid.js';
|
||||||
import { SequenceDiagram } from './sequence.js';
|
import { SequenceDiagram } from './sequence.js';
|
||||||
import { Table } from './table.js';
|
import { Table } from './table.js';
|
||||||
import { Flowchart } from './flowchart.js';
|
import { Flowchart } from './flowchart.js';
|
||||||
|
import { Controls } from './controls.js';
|
||||||
|
import { Box } from './box.js';
|
||||||
|
|
||||||
export class Scene {
|
export class Scene {
|
||||||
constructor(name, rootBox) {
|
constructor(name, rootBox) {
|
||||||
|
@ -24,6 +26,14 @@ export class Scene {
|
||||||
this.options = {
|
this.options = {
|
||||||
edgeNodeColor: '#4d585c',
|
edgeNodeColor: '#4d585c',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
window.autoPlay = new URL(window.location.href).searchParams.get('auto') !== 'false';
|
||||||
|
|
||||||
|
if (!window.disableSceneControls) {
|
||||||
|
this.topRail = new Box('Top rail', document.body, { prepend: true }).addClass('top-rail');
|
||||||
|
this.controlsBox = this.topRail.addBox('Controls').addClass('controls');
|
||||||
|
this.controls = new Controls(this.controlsBox);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
withSequenceDiagram() {
|
withSequenceDiagram() {
|
||||||
|
|
|
@ -42,4 +42,8 @@ export class Table {
|
||||||
cell.innerHTML = typeof value === 'number' ? displayNumber(value) : value ?? '';
|
cell.innerHTML = typeof value === 'number' ? displayNumber(value) : value ?? '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listUniqueValueKeys() {
|
||||||
|
return this.columns; // TODO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {
|
||||||
} from './message.js';
|
} from './message.js';
|
||||||
import { ForumView } from './forum-view.js';
|
import { ForumView } from './forum-view.js';
|
||||||
import { NetworkNode } from './network-node.js';
|
import { NetworkNode } from './network-node.js';
|
||||||
import { randomID } from '../../util.js';
|
import { randomID } from '../util/util.js';
|
||||||
|
|
||||||
export class ForumNode extends NetworkNode {
|
export class ForumNode extends NetworkNode {
|
||||||
constructor(name, scene) {
|
constructor(name, scene) {
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { DAO } from '../actors/dao.js';
|
||||||
|
/**
|
||||||
|
* An Exchange provides conversion between currencies / facilitates such.
|
||||||
|
* That means they carry some of the risk of managing these transactions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Offer {
|
||||||
|
constructor({
|
||||||
|
_fromType, _toType, _amount, price,
|
||||||
|
}) {
|
||||||
|
this.price = price;
|
||||||
|
// const from =
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Exchange extends DAO {
|
||||||
|
constructor(name, scene) {
|
||||||
|
super(name, scene);
|
||||||
|
this.offersByType = new Map(); // <OfferType, Map<OfferId, Offer>>
|
||||||
|
}
|
||||||
|
|
||||||
|
getOffers(offerType) {
|
||||||
|
return this.buyOffersByType.get(offerType) ?? new Map(); // <
|
||||||
|
}
|
||||||
|
|
||||||
|
addOffer(offerOptions) {
|
||||||
|
const offer = new Offer(offerOptions);
|
||||||
|
const { fromType, toType } = offer;
|
||||||
|
[fromType, toType].forEach((type) => {
|
||||||
|
this.offersByType.s();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
requestTransaction({
|
||||||
|
fromType, toType, amount, price,
|
||||||
|
}) {
|
||||||
|
// this.
|
||||||
|
}
|
||||||
|
|
||||||
|
buy(fromType, toType, _priceParameters) {
|
||||||
|
const buyOffer = {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,6 @@
|
||||||
export class Token {
|
/**
|
||||||
constructor(ownerPublicKey) {
|
* Finance does the work of analysis of the dynamics of reputation and currency exchange
|
||||||
this.ownerPublicKey = ownerPublicKey;
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
transfer(newOwnerPublicKey) {
|
export class Finance {
|
||||||
// TODO: Current owner must sign this request
|
|
||||||
this.ownerPublicKey = newOwnerPublicKey;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { randomID } from '../util/util.js';
|
||||||
|
|
||||||
|
class Pledge {
|
||||||
|
constructor({ stake, duration }) {
|
||||||
|
this.stake = stake;
|
||||||
|
this.duration = duration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Storage work is providing data availability and integrity.
|
||||||
|
* It probably makes sense to manage it in pledges of finite duration.
|
||||||
|
*/
|
||||||
|
export class Storage {
|
||||||
|
constructor() {
|
||||||
|
this.pledges = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
pledge(pledgeOptions) {
|
||||||
|
const id = randomID();
|
||||||
|
this.pledge.set(id, new Pledge(pledgeOptions));
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import { ERC721 } from './erc721.js';
|
import { ERC721 } from '../supporting/erc721.js';
|
||||||
|
|
||||||
import { EPSILON, randomID } from '../../util.js';
|
import { EPSILON, randomID } from '../../util.js';
|
||||||
|
|
||||||
|
@ -19,7 +19,14 @@ export class ReputationTokenContract extends ERC721 {
|
||||||
this.locks = new Set(); // {tokenId, amount, start, duration}
|
this.locks = new Set(); // {tokenId, amount, start, duration}
|
||||||
}
|
}
|
||||||
|
|
||||||
mint(to, value, context) {
|
/**
|
||||||
|
*
|
||||||
|
* @param to
|
||||||
|
* @param value
|
||||||
|
* @param context
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
mint(to, value, context = {}) {
|
||||||
const tokenId = `token_${randomID()}`;
|
const tokenId = `token_${randomID()}`;
|
||||||
super.mint(to, tokenId);
|
super.mint(to, tokenId);
|
||||||
this.values.set(tokenId, value);
|
this.values.set(tokenId, value);
|
|
@ -36,6 +36,17 @@ a:visited {
|
||||||
.padded {
|
.padded {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
.top-rail {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
.controls {
|
||||||
|
position: relative;
|
||||||
|
left: 150px;
|
||||||
|
}
|
||||||
svg {
|
svg {
|
||||||
width: 800px;
|
width: 800px;
|
||||||
}
|
}
|
||||||
|
@ -49,3 +60,14 @@ td {
|
||||||
.edge > rect {
|
.edge > rect {
|
||||||
fill: #216262 !important;
|
fill: #216262 !important;
|
||||||
}
|
}
|
||||||
|
button {
|
||||||
|
margin: 5px;
|
||||||
|
margin-top: 1em;
|
||||||
|
background-color: #c6f4ff;
|
||||||
|
border-color: #b6b6b6;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
button:disabled {
|
||||||
|
background-color: #2a535e;
|
||||||
|
color: #919191;
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,9 @@
|
||||||
<div id="mocha"></div>
|
<div id="mocha"></div>
|
||||||
<div id="scene"></div>
|
<div id="scene"></div>
|
||||||
</body>
|
</body>
|
||||||
|
<script>
|
||||||
|
window.disableSceneControls = true;
|
||||||
|
</script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/radash/10.7.0/radash.js"
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/radash/10.7.0/radash.js"
|
||||||
integrity="sha512-S207zKWG3iqXqe6msO7/Mr8X3DzzF4u8meFlokHjGtBPTGUhgzVo0lpcqEy0GoiMUdcoct+H+SqzoLsxXbynzg=="
|
integrity="sha512-S207zKWG3iqXqe6msO7/Mr8X3DzzF4u8meFlokHjGtBPTGUhgzVo0lpcqEy0GoiMUdcoct+H+SqzoLsxXbynzg=="
|
||||||
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
@ -32,12 +35,6 @@
|
||||||
<script defer class="mocha-init">
|
<script defer class="mocha-init">
|
||||||
mocha.setup({
|
mocha.setup({
|
||||||
ui: 'bdd',
|
ui: 'bdd',
|
||||||
globals: ['scene', 'dao', 'experts', 'posts', 'vm', 'graph', '__REACT_DEVTOOLS_*'],
|
|
||||||
});
|
});
|
||||||
mocha.checkLeaks();
|
|
||||||
window.should = chai.should();
|
window.should = chai.should();
|
||||||
</script>
|
</script>
|
||||||
<script defer class="mocha-exec">
|
|
||||||
// TODO: Weird race condition -- resolve this in a better way
|
|
||||||
setTimeout(() => mocha.run(), 1000);
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -26,12 +26,6 @@
|
||||||
<script defer class="mocha-init">
|
<script defer class="mocha-init">
|
||||||
mocha.setup({
|
mocha.setup({
|
||||||
ui: 'bdd',
|
ui: 'bdd',
|
||||||
globals: ['scene', 'dao', 'experts', 'requestor', '__REACT_DEVTOOLS_*'],
|
|
||||||
});
|
});
|
||||||
mocha.checkLeaks();
|
|
||||||
window.should = chai.should();
|
window.should = chai.should();
|
||||||
</script>
|
</script>
|
||||||
<script defer class="mocha-exec">
|
|
||||||
// TODO: Weird race condition -- resolve this in a better way
|
|
||||||
setTimeout(() => mocha.run(), 1000);
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -15,18 +15,16 @@
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/radash/10.7.0/radash.js"
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/radash/10.7.0/radash.js"
|
||||||
integrity="sha512-S207zKWG3iqXqe6msO7/Mr8X3DzzF4u8meFlokHjGtBPTGUhgzVo0lpcqEy0GoiMUdcoct+H+SqzoLsxXbynzg=="
|
integrity="sha512-S207zKWG3iqXqe6msO7/Mr8X3DzzF4u8meFlokHjGtBPTGUhgzVo0lpcqEy0GoiMUdcoct+H+SqzoLsxXbynzg=="
|
||||||
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
<script src="https://unpkg.com/mocha/mocha.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/10.2.0/mocha.min.js"
|
||||||
<script src="https://unpkg.com/chai/chai.js"></script>
|
integrity="sha512-jsP/sG70bnt0xNVJt+k9NxQqGYvRrLzWhI+46SSf7oNJeCwdzZlBvoyrAN0zhtVyolGcHNh/9fEgZppG2pH+eA=="
|
||||||
|
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/4.3.7/chai.min.js"
|
||||||
|
integrity="sha512-tfLUmTr4u39/6Pykb8v/LjLaQ9u/uSgbHtZXFCtT9bOsZd1ZPZabIrwhif/YzashftTOhwwQUC0cQyrnIC1vEQ=="
|
||||||
|
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
<script type="module" src="./scripts/business.test.js"></script>
|
<script type="module" src="./scripts/business.test.js"></script>
|
||||||
<script defer class="mocha-init">
|
<script defer class="mocha-init">
|
||||||
mocha.setup({
|
mocha.setup({
|
||||||
ui: 'bdd',
|
ui: 'bdd',
|
||||||
globals: ['scene', 'dao', 'experts', 'posts', '__REACT_DEVTOOLS_*'],
|
|
||||||
});
|
});
|
||||||
mocha.checkLeaks();
|
|
||||||
window.should = chai.should();
|
window.should = chai.should();
|
||||||
</script>
|
</script>
|
||||||
<script defer class="mocha-exec">
|
|
||||||
// TODO: Weird race condition -- resolve this in a better way
|
|
||||||
setTimeout(() => mocha.run(), 1000);
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -25,12 +25,6 @@
|
||||||
<script defer class="mocha-init">
|
<script defer class="mocha-init">
|
||||||
mocha.setup({
|
mocha.setup({
|
||||||
ui: 'bdd',
|
ui: 'bdd',
|
||||||
globals: ['scene', 'dao', 'experts', 'posts', 'vm', 'graph', '__REACT_DEVTOOLS_*'],
|
|
||||||
});
|
});
|
||||||
mocha.checkLeaks();
|
|
||||||
window.should = chai.should();
|
window.should = chai.should();
|
||||||
</script>
|
</script>
|
||||||
<script defer class="mocha-exec">
|
|
||||||
// TODO: Weird race condition -- resolve this in a better way
|
|
||||||
setTimeout(() => mocha.run(), 1000);
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -10,10 +10,10 @@
|
||||||
<div id="flowchart-test"></div>
|
<div id="flowchart-test"></div>
|
||||||
</body>
|
</body>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import { Box } from '../classes/box.js';
|
import { Box } from '../classes/display/box.js';
|
||||||
import { Scene } from '../classes/scene.js';
|
import { Scene } from '../classes/display/scene.js';
|
||||||
import { Actor } from '../classes/actor.js';
|
import { Actor } from '../classes/display/actor.js';
|
||||||
import { Action } from '../classes/action.js';
|
import { Action } from '../classes/display/action.js';
|
||||||
import { delay } from '../util.js';
|
import { delay } from '../util.js';
|
||||||
|
|
||||||
const DEFAULT_DELAY_INTERVAL = 500;
|
const DEFAULT_DELAY_INTERVAL = 500;
|
||||||
|
|
|
@ -16,18 +16,16 @@
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/radash/10.7.0/radash.js"
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/radash/10.7.0/radash.js"
|
||||||
integrity="sha512-S207zKWG3iqXqe6msO7/Mr8X3DzzF4u8meFlokHjGtBPTGUhgzVo0lpcqEy0GoiMUdcoct+H+SqzoLsxXbynzg=="
|
integrity="sha512-S207zKWG3iqXqe6msO7/Mr8X3DzzF4u8meFlokHjGtBPTGUhgzVo0lpcqEy0GoiMUdcoct+H+SqzoLsxXbynzg=="
|
||||||
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
<script src="https://unpkg.com/mocha/mocha.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/10.2.0/mocha.min.js"
|
||||||
<script src="https://unpkg.com/chai/chai.js"></script>
|
integrity="sha512-jsP/sG70bnt0xNVJt+k9NxQqGYvRrLzWhI+46SSf7oNJeCwdzZlBvoyrAN0zhtVyolGcHNh/9fEgZppG2pH+eA=="
|
||||||
|
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/4.3.7/chai.min.js"
|
||||||
|
integrity="sha512-tfLUmTr4u39/6Pykb8v/LjLaQ9u/uSgbHtZXFCtT9bOsZd1ZPZabIrwhif/YzashftTOhwwQUC0cQyrnIC1vEQ=="
|
||||||
|
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
<script type="module" src="./scripts/forum-network.test.js"></script>
|
<script type="module" src="./scripts/forum-network.test.js"></script>
|
||||||
<script defer class="mocha-init">
|
<script defer class="mocha-init">
|
||||||
mocha.setup({
|
mocha.setup({
|
||||||
ui: 'bdd',
|
ui: 'bdd',
|
||||||
globals: ['scene', 'dao', 'experts', 'posts', 'vm', 'graph', '__REACT_DEVTOOLS_*'],
|
|
||||||
});
|
});
|
||||||
mocha.checkLeaks();
|
|
||||||
window.should = chai.should();
|
window.should = chai.should();
|
||||||
</script>
|
</script>
|
||||||
<script defer class="mocha-exec">
|
|
||||||
// TODO: Weird race condition -- resolve this in a better way
|
|
||||||
setTimeout(() => mocha.run(), 1000);
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -21,12 +21,6 @@
|
||||||
<script defer class="mocha-init">
|
<script defer class="mocha-init">
|
||||||
mocha.setup({
|
mocha.setup({
|
||||||
ui: 'bdd',
|
ui: 'bdd',
|
||||||
globals: ['scene', 'dao', 'experts', 'posts', '__REACT_DEVTOOLS_*'],
|
|
||||||
});
|
});
|
||||||
mocha.checkLeaks();
|
|
||||||
chai.should();
|
chai.should();
|
||||||
</script>
|
</script>
|
||||||
<script defer class="mocha-exec">
|
|
||||||
// TODO: Weird race condition -- resolve this in a better way
|
|
||||||
setTimeout(() => mocha.run(), 1000);
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -21,12 +21,6 @@
|
||||||
<script defer class="mocha-init">
|
<script defer class="mocha-init">
|
||||||
mocha.setup({
|
mocha.setup({
|
||||||
ui: 'bdd',
|
ui: 'bdd',
|
||||||
globals: ['scene', 'dao', 'experts', 'posts', '__REACT_DEVTOOLS_*'],
|
|
||||||
});
|
});
|
||||||
mocha.checkLeaks();
|
|
||||||
chai.should();
|
chai.should();
|
||||||
</script>
|
</script>
|
||||||
<script defer class="mocha-exec">
|
|
||||||
// TODO: Weird race condition -- resolve this in a better way
|
|
||||||
setTimeout(() => mocha.run(), 1000);
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -21,12 +21,6 @@
|
||||||
<script defer class="mocha-init">
|
<script defer class="mocha-init">
|
||||||
mocha.setup({
|
mocha.setup({
|
||||||
ui: 'bdd',
|
ui: 'bdd',
|
||||||
globals: ['scene', 'dao', 'experts', 'posts', '__REACT_DEVTOOLS_*'],
|
|
||||||
});
|
});
|
||||||
mocha.checkLeaks();
|
|
||||||
chai.should();
|
chai.should();
|
||||||
</script>
|
</script>
|
||||||
<script defer class="mocha-exec">
|
|
||||||
// TODO: Weird race condition -- resolve this in a better way
|
|
||||||
setTimeout(() => mocha.run(), 1000);
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -21,12 +21,6 @@
|
||||||
<script defer class="mocha-init">
|
<script defer class="mocha-init">
|
||||||
mocha.setup({
|
mocha.setup({
|
||||||
ui: 'bdd',
|
ui: 'bdd',
|
||||||
globals: ['scene', 'dao', 'experts', 'posts', '__REACT_DEVTOOLS_*'],
|
|
||||||
});
|
});
|
||||||
mocha.checkLeaks();
|
|
||||||
chai.should();
|
chai.should();
|
||||||
</script>
|
</script>
|
||||||
<script defer class="mocha-exec">
|
|
||||||
// TODO: Weird race condition -- resolve this in a better way
|
|
||||||
setTimeout(() => mocha.run(), 1000);
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -21,12 +21,6 @@
|
||||||
<script defer class="mocha-init">
|
<script defer class="mocha-init">
|
||||||
mocha.setup({
|
mocha.setup({
|
||||||
ui: 'bdd',
|
ui: 'bdd',
|
||||||
globals: ['scene', 'dao', 'experts', 'posts', '__REACT_DEVTOOLS_*'],
|
|
||||||
});
|
});
|
||||||
mocha.checkLeaks();
|
|
||||||
chai.should();
|
chai.should();
|
||||||
</script>
|
</script>
|
||||||
<script defer class="mocha-exec">
|
|
||||||
// TODO: Weird race condition -- resolve this in a better way
|
|
||||||
setTimeout(() => mocha.run(), 1000);
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
mocha.setup({
|
mocha.setup({
|
||||||
ui: 'bdd',
|
ui: 'bdd',
|
||||||
});
|
});
|
||||||
mocha.checkLeaks();
|
|
||||||
chai.should();
|
chai.should();
|
||||||
</script>
|
</script>
|
||||||
<script src="./scripts/mocha.test.js"></script>
|
<script src="./scripts/mocha.test.js"></script>
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
<div id="scene"></div>
|
<div id="scene"></div>
|
||||||
</body>
|
</body>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import { Box } from '../classes/box.js';
|
import { Box } from '../classes/display/box.js';
|
||||||
import { Scene } from '../classes/scene.js';
|
import { Scene } from '../classes/display/scene.js';
|
||||||
// import { ValidationPool } from '../classes/validation-pool.js';
|
// import { ValidationPool } from '../classes/validation-pool.js';
|
||||||
// import { TokenHolder } from '../classes/token-holder.js';
|
// import { TokenHolder } from '../classes/token-holder.js';
|
||||||
// import { ReputationToken } from '../classes/reputation-token.js';
|
// import { ReputationToken } from '../classes/reputation-token.js';
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { Box } from '../../classes/display/box.js';
|
import { Box } from '../../classes/display/box.js';
|
||||||
import { Scene } from '../../classes/display/scene.js';
|
import { Scene } from '../../classes/display/scene.js';
|
||||||
import { Expert } from '../../classes/actors/expert.js';
|
import { Expert } from '../../classes/actors/expert.js';
|
||||||
import { delay } from '../../util.js';
|
import { DAO } from '../../classes/dao/dao.js';
|
||||||
import { DAO } from '../../classes/actors/dao.js';
|
|
||||||
import { Public } from '../../classes/actors/public.js';
|
import { Public } from '../../classes/actors/public.js';
|
||||||
import { PostContent } from '../../classes/util/post-content.js';
|
import { PostContent } from '../../classes/util/post-content.js';
|
||||||
|
import { delayOrWait } from '../../classes/display/controls.js';
|
||||||
|
import { mochaRun } from '../../util.js';
|
||||||
|
|
||||||
const DELAY_INTERVAL = 100;
|
const DELAY_INTERVAL = 100;
|
||||||
const POOL_DURATION = 200;
|
const POOL_DURATION = 200;
|
||||||
|
@ -43,7 +44,7 @@ const setup = async () => {
|
||||||
await newExpert();
|
await newExpert();
|
||||||
requestor = new Public('Public', scene);
|
requestor = new Public('Public', scene);
|
||||||
|
|
||||||
await delay(DELAY_INTERVAL);
|
await delayOrWait(DELAY_INTERVAL);
|
||||||
|
|
||||||
// Experts gain initial reputation by submitting a post with fee
|
// Experts gain initial reputation by submitting a post with fee
|
||||||
const { postId: postId1, pool: pool1 } = await experts[0].submitPostWithFee(
|
const { postId: postId1, pool: pool1 } = await experts[0].submitPostWithFee(
|
||||||
|
@ -54,10 +55,10 @@ const setup = async () => {
|
||||||
tokenLossRatio: 1,
|
tokenLossRatio: 1,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
await delay(POOL_DURATION);
|
await delayOrWait(POOL_DURATION);
|
||||||
|
|
||||||
await pool1.evaluateWinningConditions();
|
await pool1.evaluateWinningConditions();
|
||||||
await delay(DELAY_INTERVAL);
|
await delayOrWait(DELAY_INTERVAL);
|
||||||
|
|
||||||
dao.reputation.valueOwnedBy(experts[0].reputationPublicKey).should.equal(10);
|
dao.reputation.valueOwnedBy(experts[0].reputationPublicKey).should.equal(10);
|
||||||
|
|
||||||
|
@ -71,10 +72,10 @@ const setup = async () => {
|
||||||
tokenLossRatio: 1,
|
tokenLossRatio: 1,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
await delay(POOL_DURATION);
|
await delayOrWait(POOL_DURATION);
|
||||||
|
|
||||||
await pool2.evaluateWinningConditions();
|
await pool2.evaluateWinningConditions();
|
||||||
await delay(DELAY_INTERVAL);
|
await delayOrWait(DELAY_INTERVAL);
|
||||||
|
|
||||||
dao.reputation.valueOwnedBy(experts[0].reputationPublicKey).should.equal(15);
|
dao.reputation.valueOwnedBy(experts[0].reputationPublicKey).should.equal(15);
|
||||||
dao.reputation.valueOwnedBy(experts[1].reputationPublicKey).should.equal(5);
|
dao.reputation.valueOwnedBy(experts[1].reputationPublicKey).should.equal(5);
|
||||||
|
@ -106,7 +107,9 @@ const voteForWorkEvidence = async (worker, pool) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('Availability + Business', () => {
|
describe('Availability + Business', function tests() {
|
||||||
|
this.timeout(0);
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
await setup();
|
await setup();
|
||||||
});
|
});
|
||||||
|
@ -122,7 +125,7 @@ describe('Availability + Business', () => {
|
||||||
it('Experts can register their availability for some duration', async () => {
|
it('Experts can register their availability for some duration', async () => {
|
||||||
await experts[0].registerAvailability(1, 10000);
|
await experts[0].registerAvailability(1, 10000);
|
||||||
await experts[1].registerAvailability(1, 10000);
|
await experts[1].registerAvailability(1, 10000);
|
||||||
await delay(DELAY_INTERVAL);
|
await delayOrWait(DELAY_INTERVAL);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Public can submit a work request', async () => {
|
it('Public can submit a work request', async () => {
|
||||||
|
@ -131,7 +134,7 @@ describe('Availability + Business', () => {
|
||||||
{ fee: 100 },
|
{ fee: 100 },
|
||||||
{ please: 'do some work' },
|
{ please: 'do some work' },
|
||||||
);
|
);
|
||||||
await delay(DELAY_INTERVAL);
|
await delayOrWait(DELAY_INTERVAL);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Expert can submit work evidence', async () => {
|
it('Expert can submit work evidence', async () => {
|
||||||
|
@ -153,11 +156,11 @@ describe('Availability + Business', () => {
|
||||||
await voteForWorkEvidence(worker, pool3);
|
await voteForWorkEvidence(worker, pool3);
|
||||||
|
|
||||||
// Wait for validation pool duration to elapse
|
// Wait for validation pool duration to elapse
|
||||||
await delay(POOL_DURATION);
|
await delayOrWait(POOL_DURATION);
|
||||||
|
|
||||||
// Distribute reputation awards and fees
|
// Distribute reputation awards and fees
|
||||||
await pool3.evaluateWinningConditions();
|
await pool3.evaluateWinningConditions();
|
||||||
await delay(DELAY_INTERVAL);
|
await delayOrWait(DELAY_INTERVAL);
|
||||||
|
|
||||||
// This should throw an exception since the pool is already resolved
|
// This should throw an exception since the pool is already resolved
|
||||||
try {
|
try {
|
||||||
|
@ -167,3 +170,5 @@ describe('Availability + Business', () => {
|
||||||
}
|
}
|
||||||
}).timeout(10000);
|
}).timeout(10000);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mochaRun();
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import { Business } from '../../classes/actors/business.js';
|
import { Business } from '../../classes/dao/business.js';
|
||||||
import { Scene } from '../../classes/display/scene.js';
|
import { Scene } from '../../classes/display/scene.js';
|
||||||
import { Box } from '../../classes/display/box.js';
|
import { Box } from '../../classes/display/box.js';
|
||||||
|
import { mochaRun } from '../../util.js';
|
||||||
|
|
||||||
describe('Business', () => {
|
describe('Business', function tests() {
|
||||||
|
this.timeout(0);
|
||||||
let scene;
|
let scene;
|
||||||
before(async () => {
|
before(async () => {
|
||||||
const rootElement = document.getElementById('scene');
|
const rootElement = document.getElementById('scene');
|
||||||
|
@ -14,3 +16,5 @@ describe('Business', () => {
|
||||||
should.exist(business);
|
should.exist(business);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mochaRun();
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { Box } from '../../classes/display/box.js';
|
||||||
import { Scene } from '../../classes/display/scene.js';
|
import { Scene } from '../../classes/display/scene.js';
|
||||||
import { Action } from '../../classes/display/action.js';
|
import { Action } from '../../classes/display/action.js';
|
||||||
import { Actor } from '../../classes/display/actor.js';
|
import { Actor } from '../../classes/display/actor.js';
|
||||||
import { debounce, delay } from '../../util.js';
|
import { debounce, delay, mochaRun } from '../../util.js';
|
||||||
|
|
||||||
describe('Debounce', () => {
|
describe('Debounce', () => {
|
||||||
let scene;
|
let scene;
|
||||||
|
@ -70,3 +70,5 @@ describe('Debounce', () => {
|
||||||
await scene.sequence.endSection();
|
await scene.sequence.endSection();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mochaRun();
|
||||||
|
|
|
@ -4,9 +4,12 @@ import { PostContent } from '../../classes/util/post-content.js';
|
||||||
import { Expert } from '../../classes/actors/expert.js';
|
import { Expert } from '../../classes/actors/expert.js';
|
||||||
import { ForumNode } from '../../classes/forum-network/forum-node.js';
|
import { ForumNode } from '../../classes/forum-network/forum-node.js';
|
||||||
import { Network } from '../../classes/forum-network/network.js';
|
import { Network } from '../../classes/forum-network/network.js';
|
||||||
import { delay, randomID } from '../../util.js';
|
import { mochaRun, randomID } from '../../util.js';
|
||||||
|
import { delayOrWait } from '../../classes/display/controls.js';
|
||||||
|
|
||||||
|
describe('Forum Network', function tests() {
|
||||||
|
this.timeout(0);
|
||||||
|
|
||||||
describe('Forum Network', () => {
|
|
||||||
let scene;
|
let scene;
|
||||||
let author1;
|
let author1;
|
||||||
let author2;
|
let author2;
|
||||||
|
@ -58,19 +61,21 @@ describe('Forum Network', () => {
|
||||||
1.0,
|
1.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
await delay(1000);
|
await delayOrWait(1000);
|
||||||
await author1.submitPostViaNetwork(
|
await author1.submitPostViaNetwork(
|
||||||
forumNode1,
|
forumNode1,
|
||||||
post1,
|
post1,
|
||||||
50,
|
50,
|
||||||
);
|
);
|
||||||
await delay(1000);
|
await delayOrWait(1000);
|
||||||
await author2.submitPostViaNetwork(
|
await author2.submitPostViaNetwork(
|
||||||
forumNode2,
|
forumNode2,
|
||||||
post2,
|
post2,
|
||||||
100,
|
100,
|
||||||
);
|
);
|
||||||
|
|
||||||
await delay(1000);
|
await delayOrWait(1000);
|
||||||
}).timeout(10000);
|
}).timeout(10000);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mochaRun();
|
||||||
|
|
|
@ -2,9 +2,9 @@ import { Box } from '../../../classes/display/box.js';
|
||||||
import { Scene } from '../../../classes/display/scene.js';
|
import { Scene } from '../../../classes/display/scene.js';
|
||||||
import { Expert } from '../../../classes/actors/expert.js';
|
import { Expert } from '../../../classes/actors/expert.js';
|
||||||
import { PostContent } from '../../../classes/util/post-content.js';
|
import { PostContent } from '../../../classes/util/post-content.js';
|
||||||
import { delay } from '../../../util.js';
|
|
||||||
import params from '../../../params.js';
|
import params from '../../../params.js';
|
||||||
import { DAO } from '../../../classes/actors/dao.js';
|
import { DAO } from '../../../classes/dao/dao.js';
|
||||||
|
import { delayOrWait } from '../../../classes/display/controls.js';
|
||||||
|
|
||||||
export class ForumTest {
|
export class ForumTest {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
|
@ -38,10 +38,10 @@ export class ForumTest {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
this.posts.push(postId);
|
this.posts.push(postId);
|
||||||
await delay(this.options.poolDurationMs);
|
await delayOrWait(this.options.poolDurationMs);
|
||||||
await pool.evaluateWinningConditions();
|
await pool.evaluateWinningConditions();
|
||||||
await this.scene.sequence.endSection();
|
await this.scene.sequence.endSection();
|
||||||
await delay(this.options.defaultDelayMs);
|
await delayOrWait(this.options.defaultDelayMs);
|
||||||
return postId;
|
return postId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
import { mochaRun } from '../../../util.js';
|
||||||
import { ForumTest } from './forum.test-util.js';
|
import { ForumTest } from './forum.test-util.js';
|
||||||
|
|
||||||
describe('Forum', () => {
|
describe('Forum', function tests() {
|
||||||
|
this.timeout(0);
|
||||||
|
|
||||||
const forumTest = new ForumTest();
|
const forumTest = new ForumTest();
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
|
@ -37,3 +40,5 @@ describe('Forum', () => {
|
||||||
|
|
||||||
// await addPost(expert3, 'Post 4', 100, [{ postId: postId2, weight: -1 }]);
|
// await addPost(expert3, 'Post 4', 100, [{ postId: postId2, weight: -1 }]);
|
||||||
// await addPost(expert1, 'Post 5', 100, [{ postId: postId3, weight: -1 }]);
|
// await addPost(expert1, 'Post 5', 100, [{ postId: postId3, weight: -1 }]);
|
||||||
|
|
||||||
|
mochaRun();
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
import { mochaRun } from '../../../util.js';
|
||||||
import { ForumTest } from './forum.test-util.js';
|
import { ForumTest } from './forum.test-util.js';
|
||||||
|
|
||||||
describe('Forum', () => {
|
describe('Forum', function tests() {
|
||||||
|
this.timeout(0);
|
||||||
|
|
||||||
const forumTest = new ForumTest();
|
const forumTest = new ForumTest();
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
|
@ -37,3 +40,5 @@ describe('Forum', () => {
|
||||||
|
|
||||||
// await addPost(expert3, 'Post 4', 100, [{ postId: postId2, weight: -1 }]);
|
// await addPost(expert3, 'Post 4', 100, [{ postId: postId2, weight: -1 }]);
|
||||||
// await addPost(expert1, 'Post 5', 100, [{ postId: postId3, weight: -1 }]);
|
// await addPost(expert1, 'Post 5', 100, [{ postId: postId3, weight: -1 }]);
|
||||||
|
|
||||||
|
mochaRun();
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
import { mochaRun } from '../../../util.js';
|
||||||
import { ForumTest } from './forum.test-util.js';
|
import { ForumTest } from './forum.test-util.js';
|
||||||
|
|
||||||
describe('Forum', () => {
|
describe('Forum', function tests() {
|
||||||
|
this.timeout(0);
|
||||||
|
|
||||||
const forumTest = new ForumTest();
|
const forumTest = new ForumTest();
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
|
@ -40,3 +43,5 @@ describe('Forum', () => {
|
||||||
|
|
||||||
// await addPost(expert3, 'Post 4', 100, [{ postId: postId2, weight: -1 }]);
|
// await addPost(expert3, 'Post 4', 100, [{ postId: postId2, weight: -1 }]);
|
||||||
// await addPost(expert1, 'Post 5', 100, [{ postId: postId3, weight: -1 }]);
|
// await addPost(expert1, 'Post 5', 100, [{ postId: postId3, weight: -1 }]);
|
||||||
|
|
||||||
|
mochaRun();
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
import { mochaRun } from '../../../util.js';
|
||||||
import { ForumTest } from './forum.test-util.js';
|
import { ForumTest } from './forum.test-util.js';
|
||||||
|
|
||||||
describe('Forum', () => {
|
describe('Forum', function tests() {
|
||||||
|
this.timeout(0);
|
||||||
|
|
||||||
const forumTest = new ForumTest();
|
const forumTest = new ForumTest();
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
|
@ -68,3 +71,5 @@ describe('Forum', () => {
|
||||||
|
|
||||||
// await addPost(expert3, 'Post 4', 100, [{ postId: postId2, weight: -1 }]);
|
// await addPost(expert3, 'Post 4', 100, [{ postId: postId2, weight: -1 }]);
|
||||||
// await addPost(expert1, 'Post 5', 100, [{ postId: postId3, weight: -1 }]);
|
// await addPost(expert1, 'Post 5', 100, [{ postId: postId3, weight: -1 }]);
|
||||||
|
|
||||||
|
mochaRun();
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
import { mochaRun } from '../../../util.js';
|
||||||
import { ForumTest } from './forum.test-util.js';
|
import { ForumTest } from './forum.test-util.js';
|
||||||
|
|
||||||
describe('Forum', () => {
|
describe('Forum', function tests() {
|
||||||
|
this.timeout(0);
|
||||||
|
|
||||||
const forumTest = new ForumTest();
|
const forumTest = new ForumTest();
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
|
@ -57,3 +60,5 @@ describe('Forum', () => {
|
||||||
|
|
||||||
// await addPost(expert3, 'Post 4', 100, [{ postId: postId2, weight: -1 }]);
|
// await addPost(expert3, 'Post 4', 100, [{ postId: postId2, weight: -1 }]);
|
||||||
// await addPost(expert1, 'Post 5', 100, [{ postId: postId3, weight: -1 }]);
|
// await addPost(expert1, 'Post 5', 100, [{ postId: postId3, weight: -1 }]);
|
||||||
|
|
||||||
|
mochaRun();
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
/**
|
||||||
|
* We want to be able to define tests essentially as sequences of actions by actors,
|
||||||
|
* with assertions about various values after each action.
|
||||||
|
*
|
||||||
|
* We also want the following features:
|
||||||
|
* - Advance tests automatically, for use as automated regression tests.
|
||||||
|
* - Advance tests manually, for use as a visual demo on a web page.
|
||||||
|
* - Nice to have: Manually add/remove/modify action steps.
|
||||||
|
* - Nice to have: Manually rewind actions to view prior states.
|
||||||
|
* - Nice to have: Export/import sequences of action steps.
|
||||||
|
*/
|
||||||
|
export class Test {
|
||||||
|
|
||||||
|
}
|
|
@ -2,8 +2,9 @@ import { Box } from '../../classes/display/box.js';
|
||||||
import { Scene } from '../../classes/display/scene.js';
|
import { Scene } from '../../classes/display/scene.js';
|
||||||
import { Expert } from '../../classes/actors/expert.js';
|
import { Expert } from '../../classes/actors/expert.js';
|
||||||
import { PostContent } from '../../classes/util/post-content.js';
|
import { PostContent } from '../../classes/util/post-content.js';
|
||||||
import { delay } from '../../util.js';
|
import { DAO } from '../../classes/dao/dao.js';
|
||||||
import { DAO } from '../../classes/actors/dao.js';
|
import { delayOrWait } from '../../classes/display/controls.js';
|
||||||
|
import { mochaRun } from '../../util.js';
|
||||||
|
|
||||||
const POOL_DURATION_MS = 100;
|
const POOL_DURATION_MS = 100;
|
||||||
const DEFAULT_DELAY_MS = 100;
|
const DEFAULT_DELAY_MS = 100;
|
||||||
|
@ -35,10 +36,11 @@ async function setup() {
|
||||||
await newExpert();
|
await newExpert();
|
||||||
await newExpert();
|
await newExpert();
|
||||||
|
|
||||||
await delay(DEFAULT_DELAY_MS);
|
await delayOrWait(DEFAULT_DELAY_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('Validation Pool', () => {
|
describe('Validation Pool', function tests() {
|
||||||
|
this.timeout(0);
|
||||||
before(async () => {
|
before(async () => {
|
||||||
await setup();
|
await setup();
|
||||||
});
|
});
|
||||||
|
@ -73,9 +75,9 @@ describe('Validation Pool', () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await scene.sequence.endSection();
|
await scene.sequence.endSection();
|
||||||
await delay(POOL_DURATION_MS);
|
await delayOrWait(POOL_DURATION_MS);
|
||||||
await pool.evaluateWinningConditions(); // Vote passes
|
await pool.evaluateWinningConditions(); // Vote passes
|
||||||
await delay(DEFAULT_DELAY_MS);
|
await delayOrWait(DEFAULT_DELAY_MS);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Failure example: second expert can not self-approve', async () => {
|
it('Failure example: second expert can not self-approve', async () => {
|
||||||
|
@ -85,9 +87,9 @@ describe('Validation Pool', () => {
|
||||||
duration: POOL_DURATION_MS,
|
duration: POOL_DURATION_MS,
|
||||||
tokenLossRatio: 1,
|
tokenLossRatio: 1,
|
||||||
});
|
});
|
||||||
await delay(POOL_DURATION_MS);
|
await delayOrWait(POOL_DURATION_MS);
|
||||||
await pool.evaluateWinningConditions(); // Quorum not met!
|
await pool.evaluateWinningConditions(); // Quorum not met!
|
||||||
await delay(DEFAULT_DELAY_MS);
|
await delayOrWait(DEFAULT_DELAY_MS);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
e.message.should.match(/Quorum is not met/);
|
e.message.should.match(/Quorum is not met/);
|
||||||
}
|
}
|
||||||
|
@ -104,8 +106,10 @@ describe('Validation Pool', () => {
|
||||||
amount: 4,
|
amount: 4,
|
||||||
lockingTime: 0,
|
lockingTime: 0,
|
||||||
});
|
});
|
||||||
await delay(POOL_DURATION_MS);
|
await delayOrWait(POOL_DURATION_MS);
|
||||||
await pool.evaluateWinningConditions(); // Stake passes
|
await pool.evaluateWinningConditions(); // Stake passes
|
||||||
await delay(DEFAULT_DELAY_MS);
|
await delayOrWait(DEFAULT_DELAY_MS);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mochaRun();
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { Actor } from '../../classes/display/actor.js';
|
||||||
import { Box } from '../../classes/display/box.js';
|
import { Box } from '../../classes/display/box.js';
|
||||||
import { Scene } from '../../classes/display/scene.js';
|
import { Scene } from '../../classes/display/scene.js';
|
||||||
import { VM } from '../../classes/supporting/vm.js';
|
import { VM } from '../../classes/supporting/vm.js';
|
||||||
|
import { mochaRun } from '../../util.js';
|
||||||
|
|
||||||
const contractIds = ['contract-id-1', 'contract-id-2'];
|
const contractIds = ['contract-id-1', 'contract-id-2'];
|
||||||
|
|
||||||
|
@ -29,7 +30,9 @@ class Repeater extends Actor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('VM', () => {
|
describe('VM', function tests() {
|
||||||
|
this.timeout(0);
|
||||||
|
|
||||||
let vm;
|
let vm;
|
||||||
let sender;
|
let sender;
|
||||||
let vmHandle;
|
let vmHandle;
|
||||||
|
@ -68,3 +71,5 @@ describe('VM', () => {
|
||||||
.should.equal('Repeater world: good day');
|
.should.equal('Repeater world: good day');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mochaRun();
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
import { Box } from '../../classes/display/box.js';
|
import { Box } from '../../classes/display/box.js';
|
||||||
import { Scene } from '../../classes/display/scene.js';
|
import { Scene } from '../../classes/display/scene.js';
|
||||||
import { WDAG } from '../../classes/supporting/wdag.js';
|
import { WDAG } from '../../classes/supporting/wdag.js';
|
||||||
|
import { mochaRun } from '../../util.js';
|
||||||
|
|
||||||
const rootElement = document.getElementById('scene');
|
const rootElement = document.getElementById('scene');
|
||||||
const rootBox = new Box('rootBox', rootElement).flex();
|
const rootBox = new Box('rootBox', rootElement).flex();
|
||||||
window.scene = new Scene('WDAG test', rootBox);
|
window.scene = new Scene('WDAG test', rootBox);
|
||||||
|
|
||||||
describe('Query the graph', () => {
|
describe('Query the graph', function tests() {
|
||||||
|
this.timeout(0);
|
||||||
|
|
||||||
let graph;
|
let graph;
|
||||||
|
|
||||||
before(() => {
|
before(() => {
|
||||||
|
@ -43,3 +46,5 @@ describe('Query the graph', () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mochaRun();
|
||||||
|
|
|
@ -25,12 +25,6 @@
|
||||||
<script defer class="mocha-init">
|
<script defer class="mocha-init">
|
||||||
mocha.setup({
|
mocha.setup({
|
||||||
ui: 'bdd',
|
ui: 'bdd',
|
||||||
globals: ['scene', 'dao', 'experts', 'posts', '__REACT_DEVTOOLS_*'],
|
|
||||||
});
|
});
|
||||||
mocha.checkLeaks();
|
|
||||||
chai.should();
|
chai.should();
|
||||||
</script>
|
</script>
|
||||||
<script defer class="mocha-exec">
|
|
||||||
// TODO: Weird race condition -- resolve this in a better way
|
|
||||||
setTimeout(() => mocha.run(), 1000);
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -21,12 +21,6 @@
|
||||||
<script defer class="mocha-init">
|
<script defer class="mocha-init">
|
||||||
mocha.setup({
|
mocha.setup({
|
||||||
ui: 'bdd',
|
ui: 'bdd',
|
||||||
globals: ['vm', '__REACT_DEVTOOLS_*'],
|
|
||||||
});
|
});
|
||||||
mocha.checkLeaks();
|
|
||||||
window.should = chai.should();
|
window.should = chai.should();
|
||||||
</script>
|
</script>
|
||||||
<script defer class="mocha-exec">
|
|
||||||
// TODO: Weird race condition -- resolve this in a better way
|
|
||||||
setTimeout(() => mocha.run(), 1000);
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -21,13 +21,7 @@
|
||||||
<script defer class="mocha-init">
|
<script defer class="mocha-init">
|
||||||
mocha.setup({
|
mocha.setup({
|
||||||
ui: 'bdd',
|
ui: 'bdd',
|
||||||
globals: ['graph', '__REACT_DEVTOOLS_*'],
|
|
||||||
});
|
});
|
||||||
mocha.checkLeaks();
|
|
||||||
chai.should();
|
chai.should();
|
||||||
</script>
|
</script>
|
||||||
<script type="module" src="./scripts/wdag.test.js"></script>
|
<script type="module" src="./scripts/wdag.test.js"></script>
|
||||||
<script defer class="mocha-exec">
|
|
||||||
// TODO: Weird race condition -- resolve this in a better way
|
|
||||||
setTimeout(() => mocha.run(), 1000);
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -38,3 +38,9 @@ export const displayNumber = (value, decimals = 2) => (value.toString().length >
|
||||||
: value);
|
: value);
|
||||||
|
|
||||||
export const randomID = () => CryptoUtil.randomUUID().replaceAll('-', '').slice(0, 8);
|
export const randomID = () => CryptoUtil.randomUUID().replaceAll('-', '').slice(0, 8);
|
||||||
|
|
||||||
|
export const mochaRun = () => {
|
||||||
|
if (mocha._state !== 'running') {
|
||||||
|
mocha.run();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue