GithubHelp home page GithubHelp logo

edgeware-lockdrop's Introduction

edgeware-lockdrop

This repo contains the smart contracts and scripts for the Edgeware lockdrop.

The lockdrop contract enables users to lock ETH for 3, 6, or 12 months or signal a balance. Users also specify a 32-byte Edgeware public key, and a boolean for whether they would like to be a validator upon network launch (in which case, they must submit 3 public keys).

Use node v11.6.0

Usage

yarn global add truffle
yarn install

To test, use ganache-cli and truffle

truffle test

To deploy locally against ganache-cli:

truffle deploy

Create a file named .env with the following information

# ETH config
ETH_PRIVATE_KEY=<ETHEREUM_PRIVATE_KEY_HEX>

# Node/provider config
INFURA_PATH=https://ropsten.infura.io/v3/<INFURA_API_KEY>

# Lockdrop config
LOCKDROP_CONTRACT_ADDRESSES=<LOCKDROP_ADDRESS>,<LOCKDROP_ADDRESS>

# Edgeware config
EDGEWARE_PUBLIC_KEY=0xa469e40f0a073be5b28e2df6e746ce6519260cdd764bc5f6b3fb3aac5cda3c35

To successfully run /scripts/lockdrop.js, ensure you've deployed to the correct network, and run:

truffle compile
node ./scripts/lockdrop.js --help

Key generation

You must generate a keypair (public key and private key) to receive EDG. The easiest way to generate a keypair is using the subkey utility:

  1. Install rust here
  2. Install subkey
cargo install --force --git https://github.com/paritytech/substrate subkey
  1. Run subkey from your command line in order to generate a key. For example:
subkey generate
 Phrase `meadow clip planet heavy afford rifle viable bus fury satoshi blue impose` is account:
  Seed: 0x225967f0f82c4958179f9ba1c9b8823b0bc87fca650d7f3181bd2131f54276ec
  Public key (hex): 0xc2e973c4d848d25613141ef883bf97d35b513230427f52c56d2bf92bc4fa365c
  Address (SS58): 5GUGVkn5Zpfej7EC8WEsoJ38QFqu5cWvTx3WYFBKznLQkMAH

Important notice for validators!

If you would like to run a validating node when the network launches, you will need to create three keypairs, two using SR25519 and one using ED25519 cryptography.

To create two SR25519 keys:

subkey generate
 Phrase `meadow clip planet heavy afford rifle viable bus fury satoshi blue impose` is account:
  Seed: 0x225967f0f82c4958179f9ba1c9b8823b0bc87fca650d7f3181bd2131f54276ec
  Public key (hex): 0xc2e973c4d848d25613141ef883bf97d35b513230427f52c56d2bf92bc4fa365c
  Address (SS58): 5GUGVkn5Zpfej7EC8WEsoJ38QFqu5cWvTx3WYFBKznLQkMAH
subkey generate
 Phrase `outer mixture phrase prepare beauty horse shift about story onion duty vacant` is account:
  Seed: 0x866c461e8a5b602c755f6babd442f36992238f8e1f604a022a7e753c8a8efdea
  Public key (hex): 0xfeba4989f1de5fe7aa911f9abed67742b93099701d4f9b0e07b8ac35e2f78131
  Address (SS58): 5HphMm6GrQzXw7ZP2UEXatKgusbhNLj7AhRdgmmCp4H9Hojz

To create one ED25519 key:

subkey -e generate
Phrase `vacant paddle daring vacant rude release dutch morning cushion pledge traffic armor` is account:
  Seed: 0x6c38500811b6ea3a46214531adac0fe67e18ba543fc2fc17ceeccc2b155568be
  Public key (hex): 0x16ca51710516a648e016b00b8872cb37946dc1aabd531021d593e1d76604cf40
  Address (SS58): 5Cab1dV9g8hb2MrBcVUjCyFEJBqBWZZ4djHRE4pBYHbk4kyB

Then, concatenate the public keys together, removing the 0x in front of all intermediate elements. This string should be 194 characters.

let CONCATENATED_PUBLIC_KEYS = `${0xc2e973c4d848d25613141ef883bf97d35b513230427f52c56d2bf92bc4fa365c}
                                ${feba4989f1de5fe7aa911f9abed67742b93099701d4f9b0e07b8ac35e2f78131}
                                ${16ca51710516a648e016b00b8872cb37946dc1aabd531021d593e1d76604cf40}`

If you intend to be a validator, submit THIS concatenated string as your --edgewarePublicKey. You can add it to your .env or specify it as a CLI argument.

Examples

Locking

  1. Locking up 1 ETH for 3 months with no intent to validate
node scripts/lockdrop.js -l --lockValue 1 --lockLength 3 --edgewarePublicKey 0xa469e40f0a073be5b28e2df6e746ce6519260cdd764bc5f6b3fb3aac5cda3c35
  1. Locking up 0.025 ETH for 6 months with no intent to validate and public key stored in .env file.
node scripts/lockdrop.js -l --lockValue 0.025 --lockLength 6
  1. Locking up 50 ETH for 12 months with no intent to validate against a local node.
node scripts/lockdrop.js -r http://localhost:8545 -l --lockValue 50 --lockLength 12 --edgewarePublicKey 0xa469e40f0a073be5b28e2df6e746ce6519260cdd764bc5f6b3fb3aac5cda3c35
  1. Locking up 1 ETH for 0.1 for 12 months with intent to validate and 3 Public keys conconatenated.
node scripts/lockdrop.js --lock --lockLength 12 --lockValue 0.1 --edgewarePublicKey $CONCATENATED_PUBLIC_KEYS --isValidator

Signaling

  1. Signaling from an non-contract Ethereum user address
node scripts/lockdrop.js -s 0x2d65a140446894Ef1E71C333ecaA5BD8b5e6D568 -n 0 --edgewarePublicKey 0xa469e40f0a073be5b28e2df6e746ce6519260cdd764bc5f6b3fb3aac5cda3c35
  1. Signaling from an Ethereum contract address created from nonce 101, using a local node
node scripts/lockdrop.js -r http://localhost:8545 --signal 0x2d65a140446894Ef1E71C333ecaA5BD8b5e6D568 -n 101 --edgewarePublicKey 0xa469e40f0a073be5b28e2df6e746ce6519260cdd764bc5f6b3fb3aac5cda3c35

Unlocking

  1. Unlocking all Lock User Contracts (LUCs) for the address of the private key hex in .env
node scripts/lockdrop.js --unlockAll
  1. Unlocking a specific Lock User Contract (LUC), from local node
node scripts/lockdrop.js -r http://localhost:8545 --unlock 0x0830135aabcebf1e9d08ea6ff50ffa7222e45a43

Utilities

  1. Get the ending time of the Lockdrop contract stored in file .env
node scripts/lockdrop.js --ending
  1. Get a list of all Lock User Contracts (LUCs) for a particular address
node scripts/lockdrop.js --locksForAddress 0x329dcd85e6eec8b25c310279b9c1518f86153eee
  1. Get the balance of the Lockdrop Contract stored in the file .env
node scripts/lockdrop.js --balance

API

Usage: lockdrop [options]

Options:
  -V, --version                     output the version number
  -b, --balance                     Get the total balance across all locks
  -l, --lock                        Lock ETH with the lockdrop
  -s, --signal <contractAddress>    Signal a contract balance in the lockdrop
  -n, --nonce <nonce>               Transaction nonce that created a specific contract address
  -u, --unlock <contractAddress>    Unlock ETH from a specific lock contract
  -r, --remoteUrl <url>             The remote URL of an Ethereum node (defaults to localhost:8545)
  --unlockAll                       Unlock all locks from the locally stored Ethereum address
  --lockdropContractAddress <addr>  The Ethereum address for the target Lockdrop (THIS IS A LOCKDROP CONTRACT)
  --allocation                      Get the allocation for the current set of lockers
  --ending                          Get the remaining time of the lockdrop
  --lockLength <length>             The desired lock length - (3, 6, or 12)
  --lockValue <value>               The amount of Ether to lock
  --edgewarePublicKey <publicKey>   Edgeware Public Key
  --isValidator                     A boolean flag indicating intent to be a validator
  --locksForAddress <userAddress>   Returns the history of lock contracts for a participant in the lockdrop
  -h, --help                        output usage information

Edgeware blockchain

To align incentives, the Edgeware network will be launched with a lockdrop of EDG tokens to Ether holders. A lockdrop happens where token holders on one network timelock their tokens in a smart contract to receive balances on another. Ether holders are able to lock their tokens for as short as 3 months or as long as one year, with longer timelocks corresponding to receiving proportionally more Edgeware tokens.

Explainer on Medium

edgeware-lockdrop's People

Contributors

dependabot[bot] avatar dillchen avatar drewstone avatar raykyri avatar soc1c 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

Watchers

 avatar  avatar  avatar  avatar  avatar

edgeware-lockdrop's Issues

SHA-256 hash mismatch

What I do:

wget https://raw.githubusercontent.com/hicommonwealth/edgeware-lockdrop/master/contracts/Lockdrop.sol

sha256sum Lockdrop.sol
155e969ad7b2266bdf1a6f8be7a7b2606bca2f7fd9003d9c0191bcc8e033ffb9 Lockdrop.sol

SHA-256 hash should be:
b3089fc52a09660f632e308089af690aee2475e1ecfaec53301e886214f71251 ./contracts/Lockdrop.sol

Source: Appendix Section
https://arena-attachments.s3.amazonaws.com/4282493/a155dc84aa1dfba4cfd3dc6be1e1ebdc.pdf?1557965252

Also in this document:

"2019-04-08 - Reviewed report based on commit 51478f1"

But there is no such commit in this branch, only in another branch?

And if you changed Lockdrop.sol since the audit, what did you change?

Thanks for clarif!

UnhandledPromiseRejectionWarning: Error: Requested data size exceeds limit of 1000 blocks.

Hi, trying to query my balance:

~/.opt/edge-lockdrop master
❯ node ./scripts/lockdrop.js --balance
Fetching Lockdrop balance...

(node:29824) UnhandledPromiseRejectionWarning: Error: Returned error: Requested data size exceeds limit of 1000 blocks.
    at Object.ErrorResponse (/home/user/.opt/edge-lockdrop/node_modules/web3-core-helpers/src/errors.js:29:16)
    at /home/user/.opt/edge-lockdrop/node_modules/web3-core-requestmanager/src/index.js:140:36
    at XMLHttpRequest.request.onreadystatechange (/home/user/.opt/edge-lockdrop/node_modules/web3-providers-http/src/index.js:96:13)
    at XMLHttpRequestEventTarget.dispatchEvent (/home/user/.opt/edge-lockdrop/node_modules/xhr2-cookies/dist/xml-http-request-event-target.js:34:22)
    at XMLHttpRequest._setReadyState (/home/user/.opt/edge-lockdrop/node_modules/xhr2-cookies/dist/xml-http-request.js:208:14)
    at XMLHttpRequest._onHttpResponseEnd (/home/user/.opt/edge-lockdrop/node_modules/xhr2-cookies/dist/xml-http-request.js:318:14)
    at IncomingMessage.<anonymous> (/home/user/.opt/edge-lockdrop/node_modules/xhr2-cookies/dist/xml-http-request.js:289:61)
    at IncomingMessage.emit (events.js:194:15)
    at endReadableNT (_stream_readable.js:1125:12)
    at process._tickCallback (internal/process/next_tick.js:63:19)
(node:29824) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:29824) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Truffle 5, Node 10, Arch Linux:

~/.opt/edge-lockdrop 15s
❯ uname -a
Linux ceres 4.20.13-arch1-1-ARCH #1 SMP PREEMPT Wed Feb 27 19:10:28 UTC 2019 x86_64 GNU/Linux

~/.opt/edge-lockdrop
❯ yarn --version
1.15.2

~/.opt/edge-lockdrop
❯ node --version
v10.15.3

~/.opt/edge-lockdrop
❯ truffle version  
Truffle v5.0.8 (core: 5.0.8)
Solidity v0.5.0 (solc-js)
Node v10.15.3
Web3.js v1.0.0-beta.37

Connected to a Parity default-config light node on mainnet:

❯ parity --light
2019-03-18 10:01:43  Starting Parity-Ethereum/v2.3.5-stable-ebd0fd0117-20190227/x86_64-linux-gnu/rustc1.32.0
2019-03-18 10:01:43  Keys path /home/user/.local/share/io.parity.ethereum/keys/ethereum
2019-03-18 10:01:43  DB path /home/user/.local/share/io.parity.ethereum/chains_light/ethereum/db/906a34e69aec8c0d
2019-03-18 10:01:43  Running in experimental Light Client mode.
2019-03-18 10:01:43  Debug API is not available in light client mode.
2019-03-18 10:01:43  Debug API is not available in light client mode.
2019-03-18 10:01:43  Public node URL: enode://e2ea472bcbf28c3a5784e34f6ca05cca9c87779885af013eaf3ecc4d0f213e19a20f4170b83945631507b84187368df51dcb15011da4f2c125e9a1e58f258934@192.168.0.196:30303
2019-03-18 10:01:46  Imported #7391983 0xe123…9b58 (8.00 Mgas)
2019-03-18 10:02:03  Imported #7391992 0xd180…fc66 (7.99 Mgas)
2019-03-18 10:02:13  Imported #7391993 0x6065…7e13 (7.99 Mgas)

index is Undefined in lockdropHelper

The lockdropHelper iterates through index of the lockdropContracts that is passed into the function here https://github.com/hicommonwealth/edgeware-lockdrop/blob/master/helpers/lockdropHelper.js#L71, but in most of the tests we're only passing in a single contract https://github.com/hicommonwealth/edgeware-lockdrop/blob/master/test/1-lockdrop.spec.js#L144 that's generated here https://github.com/hicommonwealth/edgeware-lockdrop/blob/master/test/1-lockdrop.spec.js#L21, instead of passing in an array of them.

Error: Expected parameter 'from' not passed to function.

Hi, truffle test fails for me:

~/.opt/edge-lockdrop
❯ truffle test

Compiling your contracts...
===========================
> Compiling ./contracts/Lockdrop.sol
> Compiling ./contracts/Migrations.sol
> Compiling openzeppelin-solidity/contracts/math/SafeMath.sol
> Compiling openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
> Compiling openzeppelin-solidity/contracts/token/ERC20/IERC20.sol
> Artifacts written to /tmp/test-119218-14740-9n3ssj.1pl7n
> Compiled successfully using:
   - solc: 0.5.0+commit.1d4f565a.Emscripten.clang

Error: Expected parameter 'from' not passed to function.
    at /home/user/.config/yarn/global/node_modules/truffle/build/webpack:/packages/truffle-expect/index.js:5:1
    at Array.forEach (<anonymous>)
    at Object.options (/home/user/.config/yarn/global/node_modules/truffle/build/webpack:/packages/truffle-expect/index.js:3:1)
    at Object.run (/home/user/.config/yarn/global/node_modules/truffle/build/webpack:/packages/truffle-migrate/index.js:53:1)
    at /home/user/.config/yarn/global/node_modules/truffle/build/webpack:/packages/truffle-core/lib/test.js:172:1
    at new Promise (<anonymous>)
    at Object.performInitialDeploy (/home/user/.config/yarn/global/node_modules/truffle/build/webpack:/packages/truffle-core/lib/test.js:171:1)
    at /home/user/.config/yarn/global/node_modules/truffle/build/webpack:/packages/truffle-core/lib/test.js:107:1
    at process._tickCallback (internal/process/next_tick.js:68:7)
Truffle v5.0.8 (core: 5.0.8)
Node v10.15.3

Truffle 5, Node 10, Arch Linux:

~/.opt/edge-lockdrop 15s
❯ uname -a
Linux ceres 4.20.13-arch1-1-ARCH #1 SMP PREEMPT Wed Feb 27 19:10:28 UTC 2019 x86_64 GNU/Linux

~/.opt/edge-lockdrop
❯ yarn --version
1.15.2

~/.opt/edge-lockdrop
❯ node --version
v10.15.3

~/.opt/edge-lockdrop
❯ truffle version  
Truffle v5.0.8 (core: 5.0.8)
Solidity v0.5.0 (solc-js)
Node v10.15.3
Web3.js v1.0.0-beta.37

Error: ENOENT: no such file or directory, open './build/contracts/Lockdrop.json'

Hi, the lockdrop script does not execute:

~/.opt/edge-lockdrop
❯ yarn install
yarn install v1.15.2
warning package.json: No license field
warning No license field
[1/4] Resolving packages...
success Already up-to-date.
Done in 0.28s.

~/.opt/edge-lockdrop
❯ node ./scripts/lockdrop.js 
fs.js:114
    throw err;
    ^

Error: ENOENT: no such file or directory, open './build/contracts/Lockdrop.json'
    at Object.openSync (fs.js:438:3)
    at Object.readFileSync (fs.js:343:35)
    at Object.<anonymous> (/home/user/.opt/edge-lockdrop/scripts/lockdrop.js:9:37)
    at Module._compile (internal/modules/cjs/loader.js:701:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
    at Module.load (internal/modules/cjs/loader.js:600:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
    at Function.Module._load (internal/modules/cjs/loader.js:531:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:754:12)
    at startup (internal/bootstrap/node.js:283:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)

Truffle 5, Node 10, Arch Linux:

~/.opt/edge-lockdrop 15s
❯ uname -a
Linux ceres 4.20.13-arch1-1-ARCH #1 SMP PREEMPT Wed Feb 27 19:10:28 UTC 2019 x86_64 GNU/Linux

~/.opt/edge-lockdrop
❯ yarn --version
1.15.2

~/.opt/edge-lockdrop
❯ node --version
v10.15.3

~/.opt/edge-lockdrop
❯ truffle version  
Truffle v5.0.8 (core: 5.0.8)
Solidity v0.5.0 (solc-js)
Node v10.15.3
Web3.js v1.0.0-beta.37

Light client support

Suggestion to use Parity Light.js instead of Web3.js so users can connect to a Parity "Light Client" Node instead of having to use a "Full Node" that we trust, or having to fallback to Infura.

See https://matrix.to/#/!AtgPynFxLJGFYkAZEl:matrix.parity.io/$1559688870138068XFOqe:matrix.org?via=matrix.parity.io&via=matrix.org

For example, if I run a Parity Ethereum "Light Client" Node that's fully synchronised with ./target/release/parity --light --chain ropsten and then query balances with Edgeware CLI with node scripts/lockdrop.js --balance it returns:

Fetching Lockdrop balance from lockdrop contract 0x111ee804560787E0bFC1898ed79DAe24F2457a04

Error: Unknown block number
    at /home/me/code/github/me/edgeware-lockdrop/node_modules/truffle-hdwallet-provider/dist/index.js:15:625714
    at e.i.onreadystatechange (/home/me/code/github/me/edgeware-lockdrop/node_modules/truffle-hdwallet-provider/dist/index.js:15:780374)
    at e.t.dispatchEvent (/home/me/code/github/me/edgeware-lockdrop/node_modules/truffle-hdwallet-provider/dist/index.js:1:156918)
    at e._setReadyState (/home/me/code/github/me/edgeware-lockdrop/node_modules/truffle-hdwallet-provider/dist/index.js:15:785136)
    at e._onHttpResponseEnd (/home/me/code/github/me/edgeware-lockdrop/node_modules/truffle-hdwallet-provider/dist/index.js:15:788221)
    at IncomingMessage.<anonymous> (/home/me/code/github/me/edgeware-lockdrop/node_modules/truffle-hdwallet-provider/dist/index.js:15:787479)
    at IncomingMessage.emit (events.js:198:15)
    at endReadableNT (_stream_readable.js:1139:12)
    at processTicksAndRejections (internal/process/task_queues.js:81:17)
(node:9739) UnhandledPromiseRejectionWarning: Error: Requested data size exceeds limit of 1000 blocks.
...

But if I run a Parity Ethereum "Full Node" with ``./target/release/parity --chain ropstenand then query balances with Edgeware CLI withnode scripts/lockdrop.js --balance` it correctly returns the balances:

Total ETH locked: 7.601
Total ETH signaled: 0.69685286

Interpretation of decoding using bs58, stripping its last 6 bits, and re-encoding with Polkadot.js keyring encode instead of bs58's encode

When I run this test https://github.com/hicommonwealth/edgeware-lockdrop/blob/master/test/2-lockdrop.spec.js#L107 it fails with error on line assert.equal(elt[0], constants.FIXTURES[inx].base58Address);:

       should ensure base58 encodings are valid to submit:

      AssertionError: expected '2afa34ee0f034817963d83845920938c1d23bd7f7d146f588ff0e0f608fd3b6d' to equal '5HimYxXdszMgAbPQD49kLbgaBb274ubQpRNDJmZD4fA7KrJq'
      + expected - actual

      -2afa34ee0f034817963d83845920938c1d23bd7f7d146f588ff0e0f608fd3b6d
      +5HimYxXdszMgAbPQD49kLbgaBb274ubQpRNDJmZD4fA7KrJq

Shouldn't we be encoding the value elt[0] like the following?

const strippedKey = elt[0];
const bytes = Buffer.from(strippedKey, 'hex');
const encodedKey = bs58.encode(bytes);
assert.equal(encodedKey, constants.FIXTURES[inx].base58Address);

Also, why are we decoding using bs58.decode ..., but then encoding using Polkadot.js here https://github.com/hicommonwealth/edgeware-lockdrop/blob/master/helpers/lockdropHelper.js#L272 with const encoded = keyring.encodeAddress(key);, but not using the encoded` variable anyway?

And why are we removing the last 6 bits from the edgewareAddr public key (without preceding 0x) here https://github.com/hicommonwealth/edgeware-lockdrop/blob/master/helpers/lockdropHelper.js#L186, is this the checksum mentioned here https://github.com/paritytech/substrate/wiki/External-Address-Format-(SS58)? It causes the value to be shortened to '2afa34ee0f034817963d83845920938c1d23bd7f7d146f588ff0e0f608fd3b6d' instead of '2afa34ee0f034817963d83845920938c1d23bd7f7d146f588ff0e0f608fd3b6d4ec0be', so we can't encode it back again using the approach mentioned above using bs58.encode ...

Also, why do we decode with bs58.decode here https://github.com/hicommonwealth/edgeware-lockdrop/blob/master/test/2-lockdrop.spec.js#L78, instead of with Polkadot.js's decodeAddress?

const { decodeAddress } = require('@polkadot/util-crypto');
...
      return await lockdrop.lock(TWELVE_MONTHS, `0x${decodeAddress(constants.FIXTURES[inx].base58Address, true).toString('hex')}`, (Math.random() > 0.5) ? true : false, {

transaction underpriced

This is my first attempt to use truffle etc, but I seemed to have done all right with truffle test and deploy etc, but then

node ./scripts/lockdrop.js --remoteUrl https://ropsten.infura.io --lock --lockLength 3 --lockValue 0.5

seems not to be paying the right fee, and your APi at least does not have a gas limit parameter, even though the manual instructions suggest to increase the gas limit. Truth be told, I mainly switched to this package because the MyCrypto instructions also did not work for me, so far.

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.