Coder Social home page Coder Social logo

radicle-contracts's Introduction

Radicle Ethereum Contracts

See DEVELOPING.md for the developer manual.

See how_the_pool_works.md for the introduction to how the funding pool contract works.

Installation

We provide a tarball of the package through our CI. See the “Artifacts” section of a build.

Deployment

Run one of the following commands and follow the instructions provided:

yarn deploy:claims
yarn deploy:erc20FundingPool
yarn deploy:phase0
yarn deploy:playground
yarn deploy:testEns
yarn deploy:vestingTokens

Contracts deployed on Mainnet

  • claims: 0x4a7DFda4F2e9F062965cC87f775841fB58AEA83e at height 12613127
  • RAD token: 0x31c8EAcBFFdD875c74b94b077895Bd78CF1E64A3 at height 11863739

Contracts deployed on Goerli

  • phase0: 0x4a7DFda4F2e9F062965cC87f775841fB58AEA83e at height 7751624
  • RAD token: 0x3EE94D192397aAFAe438C9803825eb1Aa4402e09 at height 7751624
  • timelock: 0x5815Ec3BaA7392c4b52A94F4Bda6B0aA09563428 at height 7751624
  • governor: 0xc1DB01b8a3cD5ef52f7a83798Ee21EdC7A7e9668 at height 7751624
  • ENS registrar: 0xD88303A92577bFDF5A82FddeF342F3A27A972405 at height 7757112
    • controller -> radicle-goerli.eth
  • vesting:
    • 0x9c882463B02221b0558112dec05F60D5B3D99b6a
    • 0xAADcbc69f955523B0ff0A271229961E950538EbE
    • 0x27BCA0692e13C122E6Fc105b3974B5df7246D464
    • 0x13b2Fc1f601Fb72b86BFAB59090f22bB6E73005A

radicle-contracts's People

Contributors

cloudhead avatar codesandwich avatar d-xo avatar mrchico avatar nunoalexandre avatar rudolfs avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

radicle-contracts's Issues

User Attestations

To verify that a user of radicle's funding contracts is the same user as a user on the radicle-link level, we need some kind of proof that is verifiable by any client, given a connection to both Ethereum and the Radicle Link network.

The use-cases are the following:

  • Given the maintainer of a radicle link project, find their Ethereum donation address.
  • Given an Ethereum address, find out if it belongs to any user of radicle link.

Basically, we'd like any client (eg. upstream) to easily relate and link Ethereum addresses with radicle link (stable) identifiers.

The proposed method only requires state on Ethereum.


Proposal

To create the link between the two networks, the user creates an attestation on chain (Ethereum). This attestation is essentially a signature of the radicle link id, stored in the Ethereum state and associated with the user's Ethereum account, by means of the transaction author (msg.sender in solidity).

// Mapping of all attestations.
mapping(address => Attestation) attestations;

struct Attestation {
  bytes32 id; // The radicle-link id (root hash)
  bytes64 signature; // signature using one of the device keys (certifiers) under the radicle identity
  bytes32 publicKey; // the public (device) key associated with the above signature
}

The signature is created off-chain like so:

signature = secretKey.sign(ethereumAccountId + radicleId)

And stored on chain, using the transaction author as the associated ethereum account. Eg.

function attest(bytes32 id, bytes64 signature, bytes32 publicKey) {
  attestations[msg.sender] = Attestation { id, signature, publicKey };
}

To verify the attestation:

  1. Get the latest set of public keys under the radicle link identity being verified.
  2. Get the attestation from the Ethereum state. (Eg. using the radicle link id via the reverse index)
  3. Verify that the public key in the attestation is one of the keys authorized to sign on behalf of the identity in (1)
  4. Verify the attestation signature using the public key in the attestation, and a concatination of the radicle id with the ethereum account id. ie. public_key.verify(attestation.signature, &[ethereum_account_id, attestation.id])

If the device key used to attest is lost, a new attestation should be made. This way, the device key can be revoked with no problem.

Note also that with this method, the identity doc on radicle link doesn't need to be updated when an attestation is made.

Orgs

The idea behind the Orgs feature is to keep a canonical list of projects under control of an entity, whether it be a DAO, a user or a set of users. The umbrella under which these projects are kept is called an "Org". Some key features:

  • An org has a unique ENS-compatible name, eg. monadic.radicle.eth.
  • Orgs are controlled by an Ethereum address. This can be a regular address, or a smart contract address.
  • Projects can be registered under an org.
  • Projects registered under an org can have their state (or commit) hash anchored on-chain.
  • Orgs have an account balance.
  • Clients (eg. Upstream) should display Orgs as a list of projects, each with their latest anchored hash.
  • Projects can be registered under multiple orgs.

Orgs can be implemented by deploying an Org contract for each org:

contract Org {  
  struct Project {
    bytes32 id; // radicle link id
    bytes32 hash; // HEAD
  }

  Project[] projects; // Projects under this org
  address owner; // Org admin user/contract
  mapping(bytes32 => uint) index; // Project index

  constructor() {
    owner = msg.sender;
  }

  function anchorProject(bytes32 id, bytes32 hash) {
    require(msg.sender == owner);
    projects[index[id]].hash = hash;
  }
}

It's then possible to send/withdraw money to/from an org.

Define Org ABI/Interface

To allow any compatible contract to be deployed as an "Org", we should clearly define an Org interface that can be implemented by developers, and by our default org contract. This should take the form of Solidity interface definition.

Make pools ERC-20 compatible

We need to be able to deploy a pool contract, which will be pushing donations in arbitrary ERC-20 tokens. The token contract can be passed during construction, it's fine to have deployed one per token.

Contract updates

We need a way to update the contracts. This consists of 2 problems:

  • Swapping out the contract itself
  • Preserving the storage

Optimize gas usage of attestations

After testing the storage of the signature component with a bytes32 tuple instead of a byte[64] array, it looks like we can save a lot of gas. This should be investigated more and changed if it makes sense. Another alternative is for the attest function to take the Attestation object as an input, via ABIEncoderV2.

Can't build in Radicle Upstream since eb43a39

Through bisecting, I found that from eb43a39 onward, building this lib in Radicle Upstream fails with an error like so:

Log
 yarn install                                                                                                                                ~/upstream  nuno/attestations-flow 
yarn install v1.22.5
[1/4] Resolving packages...
[2/4] Fetching packages...
[1/4] Resolving packages...
[2/4] Fetching packages...
info fsevents@1.2.13: The platform "linux" is incompatible with this module.
info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
info fsevents@2.1.3: The platform "linux" is incompatible with this module.
info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
info fsevents@2.3.1: The platform "linux" is incompatible with this module.
info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...warning "@walletconnect/web3-provider > web3-provider-engine > eth-block-tracker > @babel/[email protected]" has unmet peer dependency "@babel/core@^7.0.0-0".
[4/4] Building fresh packages...
[9/14]  truffle
[7/14]  scrypt
[-/14] ⢀ waiting...
[8/14]  node-sasserror /home/nuno/.cache/yarn/v6/.tmp/246d2cc3fc99dab9e122a4f57f553419.eb43a390f853947146166e613c7a4282aae39d80.prepare/node_modules/scrypt: Command failed.
Exit code: 1
Command: node-gyp rebuild
Arguments:
Directory: /home/nuno/.cache/yarn/v6/.tmp/246d2cc3fc99dab9e122a4f57f553419.eb43a390f853947146166e613c7a4282aae39d80.prepare/node_modules/scrypt
Output:
gyp info it worked if it ends with ok
gyp info using node-gyp@7.1.2
gyp info using node@12.18.3 | linux | x64
gyp info find Python using Python version 3.7.5 found at "/usr/bin/python3"
gyp info spawn /usr/bin/python3
gyp info spawn args [
gyp info spawn args   '/home/nuno/.nvm/versions/node/v12.18.3/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py',
gyp info spawn args   'binding.gyp',
gyp info spawn args   '-f',
gyp info spawn args   'make',
gyp info spawn args   '-I',
gyp info spawn args   '/home/nuno/.cache/yarn/v6/.tmp/246d2cc3fc99dab9e122a4f57f553419.eb43a390f853947146166e613c7a4282aae39d80.prepare/node_modules/scrypt/build/config.gypi',
gyp info spawn args   '-I',
gyp info spawn args   '/home/nuno/.nvm/versions/node/v12.18.3/lib/node_modules/npm/node_modules/node-gyp/addon.gypi',
gyp info spawn args   '-I',
gyp info spawn args   '/home/nuno/.cache/node-gyp/12.18.3/include/node/common.gypi',
gyp info spawn args   '-Dlibrary=shared_library',
gyp info spawn args   '-Dvisibility=default',
gyp info spawn args   '-Dnode_root_dir=/home/nuno/.cache/node-gyp/12.18.3',
gyp info spawn args   '-Dnode_gyp_dir=/home/nuno/.nvm/versions/node/v12.18.3/lib/node_modules/npm/node_modules/node-gyp',
gyp info spawn args   '-Dnode_lib_file=/home/nuno/.cache/node-gyp/12.18.3/<(target_arch)/node.lib',
gyp info spawn args   '-Dmodule_root_dir=/home/nuno/.cache/yarn/v6/.tmp/246d2cc3fc99dab9e122a4f57f553419.eb43a390f853947146166e613c7a4282aae39d80.prepare/node_modules/scrypt',
gyp info spawn args   '-Dnode_engine=v8',
gyp info spawn args   '--depth=.',
gyp info spawn args   '--no-parallel',
gyp info spawn args   '--generator-output',
gyp info spawn args   'build',
gyp info spawn args   '-Goutput_dir=.'
gyp info spawn args ]
gyp info spawn make
gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
make: Entering directory '/home/nuno/.cache/yarn/v6/.tmp/246d2cc3fc99dab9e122a4f57f553419.eb43a390f853947146166e613c7a4282aae39d80.prepare/node_modules/scrypt/build'
SOLINK_MODULE(target) Release/obj.target/copied_files.node
COPY Release/copied_files.node
CC(target) Release/obj.target/scrypt_wrapper/src/util/memlimit.o
CC(target) Release/obj.target/scrypt_wrapper/src/scryptwrapper/keyderivation.o
CC(target) Release/obj.target/scrypt_wrapper/src/scryptwrapper/pickparams.o
CC(target) Release/obj.target/scrypt_wrapper/src/scryptwrapper/hash.o
AR(target) Release/obj.target/scrypt_wrapper.a
COPY Release/scrypt_wrapper.a
CC(target) Release/obj.target/scrypt_lib/scrypt/scrypt-1.2.0/lib/crypto/crypto_scrypt.o
CC(target) Release/obj.target/scrypt_lib/scrypt/scrypt-1.2.0/lib/crypto/crypto_scrypt_smix.o
CC(target) Release/obj.target/scrypt_lib/scrypt/scrypt-1.2.0/libcperciva/util/warnp.o
CC(target) Release/obj.target/scrypt_lib/scrypt/scrypt-1.2.0/libcperciva/alg/sha256.o
CC(target) Release/obj.target/scrypt_lib/scrypt/scrypt-1.2.0/libcperciva/util/insecure_memzero.o
CC(target) Release/obj.target/scrypt_lib/scrypt/scrypt-1.2.0/lib/scryptenc/scryptenc_cpuperf.o
AR(target) Release/obj.target/scrypt_lib.a
COPY Release/scrypt_lib.a
CXX(target) Release/obj.target/scrypt/src/node-boilerplate/scrypt_common.o
CXX(target) Release/obj.target/scrypt/src/node-boilerplate/scrypt_params_async.o
In file included from ../src/node-boilerplate/inc/scrypt_async.h:28,
               from ../src/node-boilerplate/inc/scrypt_params_async.h:28,
               from ../src/node-boilerplate/scrypt_params_async.cc:4:
../src/node-boilerplate/inc/scrypt_common.h: In constructor ‘NodeScrypt::Params::Params(const v8::Local<v8::Object>&):
../src/node-boilerplate/inc/scrypt_common.h:39:48: warning: ‘v8::Local<v8::Value> v8::Object::Get(v8::Local<v8::Value>) is deprecated: Use maybe version [-Wdeprecated-declarations]
 39 |       N(obj->Get(Nan::New("N").ToLocalChecked())->Uint32Value()),
    |                                                ^
In file included from /home/nuno/.cache/node-gyp/12.18.3/include/node/v8-internal.h:14,
               from /home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:27,
               from /home/nuno/.cache/node-gyp/12.18.3/include/node/node.h:67,
               from ../../nan/nan.h:56,
               from ../src/node-boilerplate/scrypt_params_async.cc:1:
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:3553:51: note: declared here
3553 |   V8_DEPRECATED("Use maybe version", Local<Value> Get(Local<Value> key));
    |                                                   ^~~
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8config.h:328:3: note: in definition of macro ‘V8_DEPRECATED’
328 |   declarator __attribute__((deprecated(message)))
    |   ^~~~~~~~~~
In file included from ../src/node-boilerplate/inc/scrypt_async.h:28,
               from ../src/node-boilerplate/inc/scrypt_params_async.h:28,
               from ../src/node-boilerplate/scrypt_params_async.cc:4:
../src/node-boilerplate/inc/scrypt_common.h:39:63: error: no matching function for call to ‘v8::Value::Uint32Value()
 39 |       N(obj->Get(Nan::New("N").ToLocalChecked())->Uint32Value()),
    |                                                               ^
In file included from /home/nuno/.cache/node-gyp/12.18.3/include/node/node.h:67,
               from ../../nan/nan.h:56,
               from ../src/node-boilerplate/scrypt_params_async.cc:1:
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:2707:41: note: candidate: ‘v8::Maybe<unsigned int> v8::Value::Uint32Value(v8::Local<v8::Context>) const’
2707 |   V8_WARN_UNUSED_RESULT Maybe<uint32_t> Uint32Value(
    |                                         ^~~~~~~~~~~
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:2707:41: note:   candidate expects 1 argument, 0 provided
In file included from ../src/node-boilerplate/inc/scrypt_async.h:28,
               from ../src/node-boilerplate/inc/scrypt_params_async.h:28,
               from ../src/node-boilerplate/scrypt_params_async.cc:4:
../src/node-boilerplate/inc/scrypt_common.h:40:48: warning: ‘v8::Local<v8::Value> v8::Object::Get(v8::Local<v8::Value>) is deprecated: Use maybe version [-Wdeprecated-declarations]
 40 |       r(obj->Get(Nan::New("r").ToLocalChecked())->Uint32Value()),
    |                                                ^
In file included from /home/nuno/.cache/node-gyp/12.18.3/include/node/v8-internal.h:14,
               from /home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:27,
               from /home/nuno/.cache/node-gyp/12.18.3/include/node/node.h:67,
               from ../../nan/nan.h:56,
               from ../src/node-boilerplate/scrypt_params_async.cc:1:
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:3553:51: note: declared here
3553 |   V8_DEPRECATED("Use maybe version", Local<Value> Get(Local<Value> key));
    |                                                   ^~~
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8config.h:328:3: note: in definition of macro ‘V8_DEPRECATED’
328 |   declarator __attribute__((deprecated(message)))
    |   ^~~~~~~~~~
In file included from ../src/node-boilerplate/inc/scrypt_async.h:28,
               from ../src/node-boilerplate/inc/scrypt_params_async.h:28,
               from ../src/node-boilerplate/scrypt_params_async.cc:4:
../src/node-boilerplate/inc/scrypt_common.h:40:63: error: no matching function for call to ‘v8::Value::Uint32Value()
 40 |       r(obj->Get(Nan::New("r").ToLocalChecked())->Uint32Value()),
    |                                                               ^
In file included from /home/nuno/.cache/node-gyp/12.18.3/include/node/node.h:67,
               from ../../nan/nan.h:56,
               from ../src/node-boilerplate/scrypt_params_async.cc:1:
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:2707:41: note: candidate: ‘v8::Maybe<unsigned int> v8::Value::Uint32Value(v8::Local<v8::Context>) const’
2707 |   V8_WARN_UNUSED_RESULT Maybe<uint32_t> Uint32Value(
    |                                         ^~~~~~~~~~~
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:2707:41: note:   candidate expects 1 argument, 0 provided
In file included from ../src/node-boilerplate/inc/scrypt_async.h:28,
               from ../src/node-boilerplate/inc/scrypt_params_async.h:28,
               from ../src/node-boilerplate/scrypt_params_async.cc:4:
../src/node-boilerplate/inc/scrypt_common.h:41:48: warning: ‘v8::Local<v8::Value> v8::Object::Get(v8::Local<v8::Value>) is deprecated: Use maybe version [-Wdeprecated-declarations]
 41 |       p(obj->Get(Nan::New("p").ToLocalChecked())->Uint32Value()) {}
    |                                                ^
In file included from /home/nuno/.cache/node-gyp/12.18.3/include/node/v8-internal.h:14,
               from /home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:27,
               from /home/nuno/.cache/node-gyp/12.18.3/include/node/node.h:67,
               from ../../nan/nan.h:56,
               from ../src/node-boilerplate/scrypt_params_async.cc:1:
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:3553:51: note: declared here
3553 |   V8_DEPRECATED("Use maybe version", Local<Value> Get(Local<Value> key));
    |                                                   ^~~
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8config.h:328:3: note: in definition of macro ‘V8_DEPRECATED’
328 |   declarator __attribute__((deprecated(message)))
    |   ^~~~~~~~~~
In file included from ../src/node-boilerplate/inc/scrypt_async.h:28,
               from ../src/node-boilerplate/inc/scrypt_params_async.h:28,
               from ../src/node-boilerplate/scrypt_params_async.cc:4:
../src/node-boilerplate/inc/scrypt_common.h:41:63: error: no matching function for call to ‘v8::Value::Uint32Value()
 41 |       p(obj->Get(Nan::New("p").ToLocalChecked())->Uint32Value()) {}
    |                                                               ^
In file included from /home/nuno/.cache/node-gyp/12.18.3/include/node/node.h:67,
               from ../../nan/nan.h:56,
               from ../src/node-boilerplate/scrypt_params_async.cc:1:
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:2707:41: note: candidate: ‘v8::Maybe<unsigned int> v8::Value::Uint32Value(v8::Local<v8::Context>) const’
2707 |   V8_WARN_UNUSED_RESULT Maybe<uint32_t> Uint32Value(
    |                                         ^~~~~~~~~~~
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:2707:41: note:   candidate expects 1 argument, 0 provided
In file included from ../src/node-boilerplate/inc/scrypt_params_async.h:28,
               from ../src/node-boilerplate/scrypt_params_async.cc:4:
../src/node-boilerplate/inc/scrypt_async.h: In member function ‘virtual void ScryptAsyncWorker::HandleErrorCallback():
../src/node-boilerplate/inc/scrypt_async.h:53:29: warning: ‘v8::Local<v8::Value> Nan::Callback::Call(int, v8::Local<v8::Value>*) const’ is deprecated [-Wdeprecated-declarations]
 53 |       callback->Call(1, argv);
    |                             ^
In file included from ../src/node-boilerplate/scrypt_params_async.cc:1:
../../nan/nan.h:1742:3: note: declared here
1742 |   Call(int argc, v8::Local<v8::Value> argv[]) const {
    |   ^~~~
In file included from ../src/node-boilerplate/scrypt_params_async.cc:4:
../src/node-boilerplate/inc/scrypt_params_async.h: In constructor ‘ScryptParamsAsyncWorker::ScryptParamsAsyncWorker(Nan::NAN_METHOD_ARGS_TYPE):
../src/node-boilerplate/inc/scrypt_params_async.h:35:36: error: no matching function for call to ‘v8::Value::NumberValue()
 35 |       maxtime(info[0]->NumberValue()),
    |                                    ^
In file included from /home/nuno/.cache/node-gyp/12.18.3/include/node/node.h:67,
               from ../../nan/nan.h:56,
               from ../src/node-boilerplate/scrypt_params_async.cc:1:
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:2704:39: note: candidate: ‘v8::Maybe<double> v8::Value::NumberValue(v8::Local<v8::Context>) const’
2704 |   V8_WARN_UNUSED_RESULT Maybe<double> NumberValue(Local<Context> context) const;
    |                                       ^~~~~~~~~~~
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:2704:39: note:   candidate expects 1 argument, 0 provided
In file included from ../src/node-boilerplate/scrypt_params_async.cc:4:
../src/node-boilerplate/inc/scrypt_params_async.h:36:39: error: no matching function for call to ‘v8::Value::NumberValue()
 36 |       maxmemfrac(info[1]->NumberValue()),
    |                                       ^
In file included from /home/nuno/.cache/node-gyp/12.18.3/include/node/node.h:67,
               from ../../nan/nan.h:56,
               from ../src/node-boilerplate/scrypt_params_async.cc:1:
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:2704:39: note: candidate: ‘v8::Maybe<double> v8::Value::NumberValue(v8::Local<v8::Context>) const’
2704 |   V8_WARN_UNUSED_RESULT Maybe<double> NumberValue(Local<Context> context) const;
    |                                       ^~~~~~~~~~~
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:2704:39: note:   candidate expects 1 argument, 0 provided
In file included from ../src/node-boilerplate/scrypt_params_async.cc:4:
../src/node-boilerplate/inc/scrypt_params_async.h:37:36: error: no matching function for call to ‘v8::Value::IntegerValue()
 37 |       maxmem(info[2]->IntegerValue()),
    |                                    ^
In file included from /home/nuno/.cache/node-gyp/12.18.3/include/node/node.h:67,
               from ../../nan/nan.h:56,
               from ../src/node-boilerplate/scrypt_params_async.cc:1:
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:2705:40: note: candidate: ‘v8::Maybe<long int> v8::Value::IntegerValue(v8::Local<v8::Context>) const’
2705 |   V8_WARN_UNUSED_RESULT Maybe<int64_t> IntegerValue(
    |                                        ^~~~~~~~~~~~
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:2705:40: note:   candidate expects 1 argument, 0 provided
In file included from ../src/node-boilerplate/scrypt_params_async.cc:4:
../src/node-boilerplate/inc/scrypt_params_async.h:38:39: error: no matching function for call to ‘v8::Value::IntegerValue()
 38 |       osfreemem(info[3]->IntegerValue())
    |                                       ^
In file included from /home/nuno/.cache/node-gyp/12.18.3/include/node/node.h:67,
               from ../../nan/nan.h:56,
               from ../src/node-boilerplate/scrypt_params_async.cc:1:
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:2705:40: note: candidate: ‘v8::Maybe<long int> v8::Value::IntegerValue(v8::Local<v8::Context>) const’
2705 |   V8_WARN_UNUSED_RESULT Maybe<int64_t> IntegerValue(
    |                                        ^~~~~~~~~~~~
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:2705:40: note:   candidate expects 1 argument, 0 provided
../src/node-boilerplate/scrypt_params_async.cc: In member function ‘virtual void ScryptParamsAsyncWorker::HandleOKCallback():
../src/node-boilerplate/scrypt_params_async.cc:23:67: warning: ‘bool v8::Object::Set(v8::Local<v8::Value>, v8::Local<v8::Value>) is deprecated: Use maybe version [-Wdeprecated-declarations]
 23 |   obj->Set(Nan::New("N").ToLocalChecked(), Nan::New<Integer>(logN));
    |                                                                   ^
In file included from /home/nuno/.cache/node-gyp/12.18.3/include/node/v8-internal.h:14,
               from /home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:27,
               from /home/nuno/.cache/node-gyp/12.18.3/include/node/node.h:67,
               from ../../nan/nan.h:56,
               from ../src/node-boilerplate/scrypt_params_async.cc:1:
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:3499:22: note: declared here
3499 |                 bool Set(Local<Value> key, Local<Value> value));
    |                      ^~~
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8config.h:328:3: note: in definition of macro ‘V8_DEPRECATED’
328 |   declarator __attribute__((deprecated(message)))
    |   ^~~~~~~~~~
../src/node-boilerplate/scrypt_params_async.cc:24:64: warning: ‘bool v8::Object::Set(v8::Local<v8::Value>, v8::Local<v8::Value>) is deprecated: Use maybe version [-Wdeprecated-declarations]
 24 |   obj->Set(Nan::New("r").ToLocalChecked(), Nan::New<Integer>(r));
    |                                                                ^
In file included from /home/nuno/.cache/node-gyp/12.18.3/include/node/v8-internal.h:14,
               from /home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:27,
               from /home/nuno/.cache/node-gyp/12.18.3/include/node/node.h:67,
               from ../../nan/nan.h:56,
               from ../src/node-boilerplate/scrypt_params_async.cc:1:
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:3499:22: note: declared here
3499 |                 bool Set(Local<Value> key, Local<Value> value));
    |                      ^~~
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8config.h:328:3: note: in definition of macro ‘V8_DEPRECATED’
328 |   declarator __attribute__((deprecated(message)))
    |   ^~~~~~~~~~
../src/node-boilerplate/scrypt_params_async.cc:25:64: warning: ‘bool v8::Object::Set(v8::Local<v8::Value>, v8::Local<v8::Value>) is deprecated: Use maybe version [-Wdeprecated-declarations]
 25 |   obj->Set(Nan::New("p").ToLocalChecked(), Nan::New<Integer>(p));
    |                                                                ^
In file included from /home/nuno/.cache/node-gyp/12.18.3/include/node/v8-internal.h:14,
               from /home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:27,
               from /home/nuno/.cache/node-gyp/12.18.3/include/node/node.h:67,
               from ../../nan/nan.h:56,
               from ../src/node-boilerplate/scrypt_params_async.cc:1:
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8.h:3499:22: note: declared here
3499 |                 bool Set(Local<Value> key, Local<Value> value));
    |                      ^~~
/home/nuno/.cache/node-gyp/12.18.3/include/node/v8config.h:328:3: note: in definition of macro ‘V8_DEPRECATED’
328 |   declarator __attribute__((deprecated(message)))
    |   ^~~~~~~~~~
../src/node-boilerplate/scrypt_params_async.cc:32:25: warning: ‘v8::Local<v8::Value> Nan::Callback::Call(int, v8::Local<v8::Value>*) const’ is deprecated [-Wdeprecated-declarations]
 32 |   callback->Call(2, argv);
    |                         ^
In file included from ../src/node-boilerplate/scrypt_params_async.cc:1:
../../nan/nan.h:1742:3: note: declared here
1742 |   Call(int argc, v8::Local<v8::Value> argv[]) const {
    |   ^~~~
make: *** [scrypt.target.mk:131: Release/obj.target/scrypt/src/node-boilerplate/scrypt_params_async.o] Error 1
make: Leaving directory '/home/nuno/.cache/yarn/v6/.tmp/246d2cc3fc99dab9e122a4f57f553419.eb43a390f853947146166e613c7a4282aae39d80.prepare/node_modules/scrypt/build'
gyp ERR! build error
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack     at ChildProcess.onExit (/home/nuno/.nvm/versions/node/v12.18.3/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:194:23)
gyp ERR! stack     at ChildProcess.emit (events.js:315:20)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:275:12)
gyp ERR! System Linux 5.3.0-64-generic
gyp ERR! command "/home/nuno/.nvm/versions/node/v12.18.3/bin/node" "/home/nuno/.nvm/versions/node/v12.18.3/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /home/nuno/.cache/yarn/v6/.tmp/246d2cc3fc99dab9e122a4f57f553419.eb43a390f853947146166e613c7a4282aae39d80.prepare/node_modules/scrypt

I have tried several things to fix this, such as cleaning yarn's cache, deleting node-modules, deleting node-gyp, yarn upgrade, different versions of node, pretty much every suggestion in nodejs/node-gyp#809.

Switch pool from using blocks to timestamps

The pool measures the passage of time by looking at the block number. It would be much better if it looked at the block timestamp. It's more precise, easier to manage and more future proof. The switch should introduce no significant changes in how the contract works, because both of these values are monotonic and fit in 64 bits.

Explore signed revocations

See #28 (comment)

It may be interesting, for additional trust, to allow for signed revocations. The question is, in what situation would you revoke a link key, while still controlling it?

Testnet Faucet Contract

I start with this issue to talk about a possible Rinkeby RAD Faucet.
We have an issue open in the radicle-interface repo, where the front-end implementation will happen: https://github.com/radicle-dev/radicle-interface/issues/69

Here I think should be the part of the contract, due to the need of using the RadicleToken and the ENS contract.

Some things I'd like to track:

  • Implement a withdraw limit based on ENS names.
    • The withdrawal limit could be time locked and the time would be proportional to the amount requested. eg: 3 RAD / 8 hours; 7.5 RAD / 1 day; 18 RAD / 3 days
    • Withdrawal amount could also be determined by the activity of funding vs. withdrawal and use a type of bonding curve mechanism, e.g.: more withdrawal than funding activity, smaller amounts to withdraw vs. more funding than withdrawal activity able to withdraw larger amounts.
  • Allow the faucet to be funded by the owner or third party actors.
  • If the faucet gets drained pause the activity and await to pass a funding threshold.

Cleanup repository

We should move big features into their own sub-folder, as it's getting a bit hard to manage. For now, just creating a Funding folder and a Registrar folder will make things cleaner.

Create governance system

To be able to update our contracts, we need a governance system that uses the radicle token to vote. We're going to be forking the compound governance modules for this, and the COMP token.

  • Create governor contract (#72)
  • Create timelock contract (#72)
  • Update token contract
  • Create proxy contract
  • Set correct governance parameters for Radicle

Vesting contract tracking issue

  • Update vesting contract to only handle one beneficiary
  • Allow termination to be set in the future
  • Implement cliff
  • Add tests

Add batch sender update

The sender has to make at least 3 steps to start donating: set a per month rate, top up the account and configure a list of receivers, which itself can take up to tens of transactions. This is a slow and expensive process.

We need a batch update transaction, which can take all these parameters and set them all at once.

Move from ethers.js to web3.js

Two prominent JavaScript libraries for talking to Ethereum are ethers.js and web3.js. In this repository we’re using ethers while Upstream will use web3 because WalletConnect has built-in integration with it and not with ethers. Since there are no big differences between the two libraries I suggest we us web3 in this repository, too to avoid fragmenting the libraries.

Improvements to vesting contract

A couple of things that need to be done for the VRad.sol contract:

  • More tests
  • redeemMax / redeemVested function
  • burnUnvested function

api: Make withdraw argument optional

At the moment, the withdraw function takes an argument that specifies how much to withdraw.

As discussed by call, having the user specifying that amount is dangerous since the user might specify, say, the "current" pool remaining balance (i.e, the user wants to withdraw all the funds), but it might occur that by the time the withdraw transaction is processed that said balance has reduced, causing the transaction to fail. That'd mean the user would pay for that transaction and get nothing out of it.

My suggestion is to make that argument optional. If not specified, all the remaining funds available by the time the tx is processed are withdrawn. In other words, by default withdrawing would mean "withdraw everything".

The idea with making it optional is to still allow the user to specify a custom amount. We could offer only the "withdraw everything" variant in the first release and "withdraw x" in an upcoming release.

@CodeSandwich thoughts?

Read every slot only once when iterating

The implementation of iterable list in the pool contract is always reading the same slot twice, once to read the value and once to read next. Because it happens in separate iteration steps, it's probably not optimized away.

Audit checklist (v0)

  • VestingToken.sol (df01a09)
    • Based on the melonport vesting contract
    • Update for solidity 0.7.5
    • Added cliff period and removed unused/redundant functionality
  • RadicleToken.sol (7a1d8d8)
    • Based on the Compound COMP token with adjusted totalSupply
    • Added burnFrom method and made fully EIP20 compatible
    • Updated for solidity 0.7.5
  • Treasury.sol (a47f0c7)
  • Governor.sol (d09ae0d)
    • Based on the Compound Governor Alpha contract
    • A few modifications to make solidity 0.7.5 compatible
    • Updated voting thresholds
  • Timelock.sol (5d11d22)
    • Based on the Compound Timelock contract
    • Updated to make solidity 0.7.5 compatible

EVM tracing not available for tests

The Buidler EVM we use for testing supports solidity stack traces. In our setup the tracing does not work, however. We get the following message

The Buidler EVM tracing engine could not be initialized. Run Buidler with --verbose to learn more.
  buidler:core:buidler-evm:node Buidler EVM tracing disabled: ContractsIdentifier failed to be initialized. Please report this to help us improve Buidler.
  buidler:core:buidler-evm:node  TypeError: Cannot read property 'startsWith' of undefined
    at toCanonicalAbiType (radicle-contracts/node_modules/@nomiclabs/buidler/src/internal/buidler-evm/stack-traces/compiler-to-model.ts:474:12)
    at astFunctionDefinitionToSelector (radicle-contracts/node_modules/@nomiclabs/buidler/src/internal/buidler-evm/stack-traces/compiler-to-model.ts:453:21)
    at processFunctionDefinitionAstNode (radicle-contracts/node_modules/@nomiclabs/buidler/src/internal/buidler-evm/stack-traces/compiler-to-model.ts:179:9)
    at processContractAstNode (radicle-contracts/node_modules/@nomiclabs/buidler/src/internal/buidler-evm/stack-traces/compiler-to-model.ts:126:7)
    at createSourcesModelFromAst (radicle-contracts/node_modules/@nomiclabs/buidler/src/internal/buidler-evm/stack-traces/compiler-to-model.ts:80:7)
    at Object.createModelsAndDecodeBytecodes (radicle-contracts/node_modules/@nomiclabs/buidler/src/internal/buidler-evm/stack-traces/compiler-to-model.ts:32:3)
    at new BuidlerNode (radicle-contracts/node_modules/@nomiclabs/buidler/src/internal/buidler-evm/provider/node.ts:322:25)
    at Function.create (radicle-contracts/node_modules/@nomiclabs/buidler/src/internal/buidler-evm/provider/node.ts:228:18)
    at BuidlerEVMProvider._init (radicle-contracts/node_modules/@nomiclabs/buidler/src/internal/buidler-evm/provider/provider.ts:269:28)
    at BuidlerEVMProvider._send (radicle-contracts/node_modules/@nomiclabs/buidler/src/internal/buidler-evm/provider/provider.ts:188:5) +0ms

Get all recipients and funds per block of my pool

In upstream we want to show all recipients of a user’s pool and the funds per block that the pool disburses. For this the contract should expose a view that returns at least all recipient addresses. As a follow-up we would also need the recipient weights.

Tests don’t compile the first time after contract API changes

Changes in the contract APIs should be reflected in the TypeScript contract bindinings for ethers. However, these changes are not picked up by yarn test when run for the first time.

When we make a change to a contract yarn test will recompile the contract and generate bindings with typechain. Then the tests, which import the bindings, are typechecked and run. However the tests are typechecked against the bindings from the unchanged contracts.

A second invocation of yarn test picks up the changed bindings that were build in the previous invocation.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.