Full Code of decentraland/mana for AI

master d92bba7f43d8 cached
32 files
36.6 KB
10.1k tokens
7 symbols
1 requests
Download .txt
Repository: decentraland/mana
Branch: master
Commit: d92bba7f43d8
Files: 32
Total size: 36.6 KB

Directory structure:
gitextract_8qja0b87/

├── .babelrc
├── .circleci/
│   └── config.yml
├── .editorconfig
├── .eslintrc
├── .flowconfig
├── .gitattributes
├── .gitignore
├── .npmignore
├── .travis.yml
├── LICENSE
├── README.md
├── contracts/
│   ├── BurnableToken.sol
│   ├── ContinuousSale.sol
│   ├── MANAContinuousSale.sol
│   ├── MANACrowdsale.sol
│   ├── MANAToken.sol
│   ├── Migrations.sol
│   └── WhitelistedCrowdsale.sol
├── flow-typed/
│   └── defs.js
├── migrations/
│   ├── 1_initial_migration.js
│   └── 2_deploy_contracts.js
├── package.json
├── scripts/
│   └── test.sh
├── test/
│   ├── BurnableToken.js
│   ├── MANAContinuousSale.js
│   ├── MANACrowdsale.js
│   ├── MANAToken.js
│   ├── WhitelistedCrowdsale.js
│   ├── helpers/
│   │   ├── BurnableTokenMock.sol
│   │   └── WhitelistedCrowdsaleImpl.sol
│   └── utils.js
└── truffle.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .babelrc
================================================
{
  "presets": ["flow", "env"]
}


================================================
FILE: .circleci/config.yml
================================================
version: 2
jobs:
  build:
    docker:
      # specify the version you desire here
      - image: circleci/node:10.2-stretch

    working_directory: ~/repo

    steps:
      - checkout

      # Download and cache dependencies
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "package-lock.json" }}
            # fallback to using the latest cache if no exact match is found
            - v1-dependencies-

      - run:
          name: Install packages
          command: npm install

      - save_cache:
          paths:
            - node_modules
          key: v1-dependencies-{{ checksum "package-lock.json" }}

      # run tests!
      - run:
          name: Run tests
          command: npm run test
  release:
    docker:
      # specify the version you desire here
      - image: circleci/node:10.2-stretch

    working_directory: ~/repo

    steps:
      - checkout
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "package-lock.json" }}
            # fallback to using the latest cache if no exact match is found
            - v1-dependencies-

      - run:
          name: Install packages
          command: npm install

      # Compile contracts!
      - run:
          name: Compile contracts
          command: npm run compile

      - run:
          name: Semantic release
          command: npm run semantic-release

workflows:
  version: 2
  test-build-release:
    jobs:
      - build
      - release:
          requires:
            - build
          filters:
            branches:
              only:
                - master


================================================
FILE: .editorconfig
================================================
root = true

[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8

[*.sol]
indent_style = space
indent_size = 4


================================================
FILE: .eslintrc
================================================
{
  "extends": ["standard"],
  "env": {
    "node": true,
    "jasmine": true
  },
  "globals": {
    "web3": false,
    "artifacts": false,
    "contract": false
  }
}


================================================
FILE: .flowconfig
================================================
[ignore]

[include]

[libs]

[options]

[lints]


================================================
FILE: .gitattributes
================================================
*.sol linguist-language=Solidity
*.js linguist-vendored


================================================
FILE: .gitignore
================================================
node_modules/
build/


================================================
FILE: .npmignore
================================================
migrations
test
zos.*
scripts 
flow-typed


================================================
FILE: .travis.yml
================================================
language: node_js
node_js:
  - "7"
cache:
  directories:
    - "node_modules"


================================================
FILE: LICENSE
================================================
Copyright 2017 The Decentraland Team

Licensed under the Apache License, Version 2.0 (the "License");
you may not use files included in this repository except in compliance
with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


================================================
FILE: README.md
================================================
![](https://decentraland.org/favicon.ico)

Decentraland MANA Token
=======================

[![Build Status](https://travis-ci.org/decentraland/mana.svg?branch=master)](https://travis-ci.org/decentraland/mana)

Solidity smart contracts for the Decentraland Crowdsale and MANA Token


================================================
FILE: contracts/BurnableToken.sol
================================================
pragma solidity ^0.4.11;

import 'zeppelin-solidity/contracts/token/StandardToken.sol';

/**
 * @title Burnable Token
 * @dev A token that can be irreversibly burned.
 */
contract BurnableToken is StandardToken {

    event Burn(address indexed burner, uint256 value);

    /**
     * @dev Burns a specified amount of tokens.
     * @param _value The amount of tokens to burn. 
     */
    function burn(uint256 _value) public {
        require(_value > 0);

        address burner = msg.sender;
        balances[burner] = balances[burner].sub(_value);
        totalSupply = totalSupply.sub(_value);
        Burn(msg.sender, _value);
    }

}


================================================
FILE: contracts/ContinuousSale.sol
================================================
pragma solidity ^0.4.11;

import "zeppelin-solidity/contracts/token/MintableToken.sol";

/**
 * @title ContinuousSale
 * @dev ContinuousSale implements a contract for managing a continuous token sale
 */
contract ContinuousSale {
    using SafeMath for uint256;

    // time bucket size
    uint256 public constant BUCKET_SIZE = 12 hours;

    // the token being sold
    MintableToken public token;

    // address where funds are collected
    address public wallet;

    // amount of tokens emitted per wei
    uint256 public rate;

    // amount of raised money in wei
    uint256 public weiRaised;

    // max amount of tokens to mint per time bucket
    uint256 public issuance;

    // last time bucket from which tokens have been purchased
    uint256 public lastBucket = 0;

    // amount issued in the last bucket
    uint256 public bucketAmount = 0;

    event TokenPurchase(address indexed investor, address indexed beneficiary, uint256 weiAmount, uint256 tokens);

    function ContinuousSale(
        uint256 _rate,
        address _wallet,
        MintableToken _token
    ) {
        require(_rate != 0);
        require(_wallet != 0);
        // require(address(token) != 0x0);

        rate = _rate;
        wallet = _wallet;
        token = _token;
    }

    function() payable {
        buyTokens(msg.sender);
    }

    function buyTokens(address beneficiary) public payable {
        require(beneficiary != 0x0);
        require(msg.value != 0);

        prepareContinuousPurchase();
        uint256 tokens = processPurchase(beneficiary);
        checkContinuousPurchase(tokens);
    }

    function prepareContinuousPurchase() internal {
        uint256 timestamp = block.timestamp;
        uint256 bucket = timestamp - (timestamp % BUCKET_SIZE);

        if (bucket > lastBucket) {
            lastBucket = bucket;
            bucketAmount = 0;
        }
    }

    function checkContinuousPurchase(uint256 tokens) internal {
        uint256 updatedBucketAmount = bucketAmount.add(tokens);
        require(updatedBucketAmount <= issuance);

        bucketAmount = updatedBucketAmount;
    }

    function processPurchase(address beneficiary) internal returns(uint256) {
        uint256 weiAmount = msg.value;

        // calculate token amount to be created
        uint256 tokens = weiAmount.mul(rate);

        // update state
        weiRaised = weiRaised.add(weiAmount);

        token.mint(beneficiary, tokens);
        TokenPurchase(msg.sender, beneficiary, weiAmount, tokens);

        forwardFunds();

        return tokens;
    }

    function forwardFunds() internal {
        wallet.transfer(msg.value);
    }
}


================================================
FILE: contracts/MANAContinuousSale.sol
================================================
pragma solidity ^0.4.11;

import "zeppelin-solidity/contracts/ownership/Ownable.sol";
import "./ContinuousSale.sol";
import "./MANAToken.sol";

contract MANAContinuousSale is ContinuousSale, Ownable {

    uint256 public constant INFLATION = 8;

    bool public started = false;

    event RateChange(uint256 amount);

    event WalletChange(address wallet);

    function MANAContinuousSale(
        uint256 _rate,
        address _wallet,
        MintableToken _token
    ) ContinuousSale(_rate, _wallet, _token) {
    }

    modifier whenStarted() {
        require(started);
        _;
    }

    function start() onlyOwner {
        require(!started);

        // initialize issuance
        uint256 finalSupply = token.totalSupply();
        uint256 annualIssuance = finalSupply.mul(INFLATION).div(100);
        issuance = annualIssuance.mul(BUCKET_SIZE).div(1 years);

        started = true;
    }

    function buyTokens(address beneficiary) whenStarted public payable {
        super.buyTokens(beneficiary);
    }

    function setWallet(address _wallet) onlyOwner {
        require(_wallet != 0x0);
        wallet = _wallet;
        WalletChange(_wallet);
    }

    function setRate(uint256 _rate) onlyOwner {
        rate = _rate;
        RateChange(_rate);
    }

    function unpauseToken() onlyOwner {
        MANAToken(token).unpause();
    }

    function pauseToken() onlyOwner {
        MANAToken(token).pause();
    }
}


================================================
FILE: contracts/MANACrowdsale.sol
================================================
pragma solidity ^0.4.11;

import "zeppelin-solidity/contracts/crowdsale/CappedCrowdsale.sol";
import "zeppelin-solidity/contracts/crowdsale/Crowdsale.sol";
import "zeppelin-solidity/contracts/crowdsale/FinalizableCrowdsale.sol";
import "./WhitelistedCrowdsale.sol";
import "./MANAContinuousSale.sol";
import "./MANAToken.sol";

contract MANACrowdsale is WhitelistedCrowdsale, CappedCrowdsale, FinalizableCrowdsale {

    uint256 public constant TOTAL_SHARE = 100;
    uint256 public constant CROWDSALE_SHARE = 40;
    uint256 public constant FOUNDATION_SHARE = 60;

    // price at which whitelisted buyers will be able to buy tokens
    uint256 public preferentialRate;

    // customize the rate for each whitelisted buyer
    mapping (address => uint256) public buyerRate;

    // initial rate at which tokens are offered
    uint256 public initialRate;

    // end rate at which tokens are offered
    uint256 public endRate;

    // continuous crowdsale contract
    MANAContinuousSale public continuousSale;

    event WalletChange(address wallet);

    event PreferentialRateChange(address indexed buyer, uint256 rate);

    event InitialRateChange(uint256 rate);

    event EndRateChange(uint256 rate);

    function MANACrowdsale(
        uint256 _startBlock,
        uint256 _endBlock,
        uint256 _initialRate,
        uint256 _endRate,
        uint256 _preferentialRate,
        address _wallet
    )
        CappedCrowdsale(86206 ether)
        WhitelistedCrowdsale()
        FinalizableCrowdsale()
        Crowdsale(_startBlock, _endBlock, _initialRate, _wallet)
    {
        require(_initialRate > 0);
        require(_endRate > 0);
        require(_preferentialRate > 0);

        initialRate = _initialRate;
        endRate = _endRate;
        preferentialRate = _preferentialRate;

        continuousSale = createContinuousSaleContract();

        MANAToken(token).pause();
    }

    function createTokenContract() internal returns(MintableToken) {
        return new MANAToken();
    }

    function createContinuousSaleContract() internal returns(MANAContinuousSale) {
        return new MANAContinuousSale(rate, wallet, token);
    }

    function setBuyerRate(address buyer, uint256 rate) onlyOwner public {
        require(rate != 0);
        require(isWhitelisted(buyer));
        require(block.number < startBlock);

        buyerRate[buyer] = rate;

        PreferentialRateChange(buyer, rate);
    }

    function setInitialRate(uint256 rate) onlyOwner public {
        require(rate != 0);
        require(block.number < startBlock);

        initialRate = rate;

        InitialRateChange(rate);
    }

    function setEndRate(uint256 rate) onlyOwner public {
        require(rate != 0);
        require(block.number < startBlock);

        endRate = rate;

        EndRateChange(rate);
    }

    function getRate() internal returns(uint256) {
        // some early buyers are offered a discount on the crowdsale price
        if (buyerRate[msg.sender] != 0) {
            return buyerRate[msg.sender];
        }

        // whitelisted buyers can purchase at preferential price before crowdsale ends
        if (isWhitelisted(msg.sender)) {
            return preferentialRate;
        }

        // otherwise compute the price for the auction
        uint256 elapsed = block.number - startBlock;
        uint256 rateRange = initialRate - endRate;
        uint256 blockRange = endBlock - startBlock;

        return initialRate.sub(rateRange.mul(elapsed).div(blockRange));
    }

    // low level token purchase function
    function buyTokens(address beneficiary) payable {
        require(beneficiary != 0x0);
        require(validPurchase());

        uint256 weiAmount = msg.value;
        uint256 updatedWeiRaised = weiRaised.add(weiAmount);

        uint256 rate = getRate();
        // calculate token amount to be created
        uint256 tokens = weiAmount.mul(rate);

        // update state
        weiRaised = updatedWeiRaised;

        token.mint(beneficiary, tokens);
        TokenPurchase(msg.sender, beneficiary, weiAmount, tokens);

        forwardFunds();
    }

    function setWallet(address _wallet) onlyOwner public {
        require(_wallet != 0x0);
        wallet = _wallet;
        continuousSale.setWallet(_wallet);
        WalletChange(_wallet);
    }

    function unpauseToken() onlyOwner {
        require(isFinalized);
        MANAToken(token).unpause();
    }

    function pauseToken() onlyOwner {
        require(isFinalized);
        MANAToken(token).pause();
    }


    function beginContinuousSale() onlyOwner public {
        require(isFinalized);

        token.transferOwnership(continuousSale);

        continuousSale.start();
        continuousSale.transferOwnership(owner);
    }

    function finalization() internal {
        uint256 totalSupply = token.totalSupply();
        uint256 finalSupply = TOTAL_SHARE.mul(totalSupply).div(CROWDSALE_SHARE);

        // emit tokens for the foundation
        token.mint(wallet, FOUNDATION_SHARE.mul(finalSupply).div(TOTAL_SHARE));

        // NOTE: cannot call super here because it would finish minting and
        // the continuous sale would not be able to proceed
    }

}


================================================
FILE: contracts/MANAToken.sol
================================================
pragma solidity ^0.4.11;

import "zeppelin-solidity/contracts/token/PausableToken.sol";
import "zeppelin-solidity/contracts/token/MintableToken.sol";
import "./BurnableToken.sol";

contract MANAToken is BurnableToken, PausableToken, MintableToken {

    string public constant symbol = "MANA";

    string public constant name = "Decentraland MANA";

    uint8 public constant decimals = 18;

    function burn(uint256 _value) whenNotPaused public {
        super.burn(_value);
    }
}


================================================
FILE: contracts/Migrations.sol
================================================
pragma solidity ^0.4.4;

contract Migrations {
  address public owner;
  uint public last_completed_migration;

  modifier restricted() {
    if (msg.sender == owner) _;
  }

  function Migrations() {
    owner = msg.sender;
  }

  function setCompleted(uint completed) restricted {
    last_completed_migration = completed;
  }

  function upgrade(address new_address) restricted {
    Migrations upgraded = Migrations(new_address);
    upgraded.setCompleted(last_completed_migration);
  }
}


================================================
FILE: contracts/WhitelistedCrowdsale.sol
================================================
pragma solidity ^0.4.11;

import 'zeppelin-solidity/contracts/math/SafeMath.sol';
import 'zeppelin-solidity/contracts/crowdsale/Crowdsale.sol';

/**
 * @title WhitelistedCrowdsale
 * @dev Extension of Crowsdale where an owner can whitelist addresses
 * which can buy in crowdsale before it opens to the public 
 */
contract WhitelistedCrowdsale is Crowdsale, Ownable {
    using SafeMath for uint256;

    // list of addresses that can purchase before crowdsale opens
    mapping (address => bool) public whitelist;

    function addToWhitelist(address buyer) public onlyOwner {
        require(buyer != 0x0);
        whitelist[buyer] = true; 
    }

    // @return true if buyer is whitelisted
    function isWhitelisted(address buyer) public constant returns (bool) {
        return whitelist[buyer];
    }

    // overriding Crowdsale#validPurchase to add whitelist logic
    // @return true if buyers can buy at the moment
    function validPurchase() internal constant returns (bool) {
        // [TODO] issue with overriding and associativity of logical operators
        return super.validPurchase() || (!hasEnded() && isWhitelisted(msg.sender)); 
    }

}


================================================
FILE: flow-typed/defs.js
================================================
declare var contract: (string, Function) => void
declare var it: (string, Function) => void
declare var describe: (string, Function) => void
declare var beforeEach: Function => void

declare var artifacts: {
  require: string => any
}

declare var web3: any


================================================
FILE: migrations/1_initial_migration.js
================================================
var Migrations = artifacts.require("./Migrations.sol");

module.exports = function(deployer) {
  deployer.deploy(Migrations);
};


================================================
FILE: migrations/2_deploy_contracts.js
================================================
const MANACrowdsale = artifacts.require("./MANACrowdsale.sol");

module.exports = function(deployer) {
  // deployer.deploy(MANACrowdsale);
};


================================================
FILE: package.json
================================================
{
  "name": "decentraland-mana",
  "version": "0.0.0-semantic-release",
  "description": "Solidity Contracts for the Decentraland MANA Token",
  "main": "y",
  "directories": {
    "test": "test"
  },
  "dependencies": {
    "sha3": "^1.2.1",
    "truffle-hdwallet-provider": "0.0.3",
    "zeppelin-solidity": "1.2.0"
  },
  "devDependencies": {
    "babel-polyfill": "^6.26.0",
    "babel-preset-env": "^1.6.1",
    "babel-preset-flow": "^6.23.0",
    "babel-register": "^6.26.0",
    "chai": "^4.1.2",
    "chai-as-promised": "^7.1.1",
    "chai-bignumber": "^2.0.2",
    "eslint": "^4.19.1",
    "eslint-config-standard": "^10.2.1",
    "eslint-plugin-import": "^2.11.0",
    "eslint-plugin-node": "^5.2.1",
    "eslint-plugin-promise": "^3.7.0",
    "eslint-plugin-standard": "^3.1.0",
    "ganache-cli": "^6.1.0",
    "husky": "^1.3.1",
    "semantic-release": "^15.13.3",
    "truffle": "^3.4.11",
    "validate-commit-msg": "^2.14.0"
  },
  "scripts": {
    "test": "./scripts/test.sh",
    "eslint": "eslint test/",
    "semantic-release": "semantic-release",
    "commit-msg": "validate-commit-msg",
    "compile": "truffle compile"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/decentraland/mana.git"
  },
  "keywords": [
    "decentraland",
    "mana",
    "solidity",
    "truffle",
    "crowdsale"
  ],
  "author": "Federico Bond",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/decentraland/mana/issues"
  },
  "homepage": "https://github.com/decentraland/mana#readme"
}


================================================
FILE: scripts/test.sh
================================================
#!/usr/bin/env bash

# Executes cleanup function at script exit.
trap cleanup EXIT

cleanup() {
  # Kill the testrpc instance that we started (if we started one and if it's still running).
  if [ -n "$testrpc_pid" ] && ps -p $testrpc_pid > /dev/null; then
    kill -9 $testrpc_pid
  fi
}

testrpc_running() {
  nc -z localhost 8545
}

if testrpc_running; then
  echo "Using existing testrpc instance"
else
  echo "Starting our own testrpc instance"
  # We define 10 accounts with balance 1M ether, needed for high-value tests.
  ganache-cli -l 10000000 \
    --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501200,1000000000000000000000000"  \
    --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501201,1000000000000000000000000"  \
    --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501202,1000000000000000000000000"  \
    --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501203,1000000000000000000000000"  \
    --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501204,1000000000000000000000000"  \
    --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501205,1000000000000000000000000"  \
    --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501206,1000000000000000000000000"  \
    --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501207,1000000000000000000000000"  \
    --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501208,1000000000000000000000000"  \
    --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501209,1000000000000000000000000"  \
  > /dev/null &
  testrpc_pid=$!
fi

node_modules/.bin/truffle test "$@"


================================================
FILE: test/BurnableToken.js
================================================
// @flow
'use strict'

const { should, EVMThrow } = require('./utils.js')
const BurnableTokenMock = artifacts.require('./helpers/BurnableTokenMock.sol')

const BigNumber = web3.BigNumber

contract('BurnableToken', function (accounts) {
  let token
  let expectedTokenSupply = new BigNumber(900)

  beforeEach(async function () {
    token = await BurnableTokenMock.new(accounts[1], 1000)
  })

  it('owner should be able to burn tokens', async function () {
    const { logs } = await token.burn(100, { from: accounts[1] })

    const balance = await token.balanceOf(accounts[1])
    balance.should.be.bignumber.equal(expectedTokenSupply)

    const totalSupply = await token.totalSupply()
    totalSupply.should.be.bignumber.equal(expectedTokenSupply)

    const event = logs.find(e => e.event === 'Burn')
    should.exist(event)
  })

  it('cannot burn more tokens that you have', async function () {
    await token.burn(2000, { from: accounts[1] })
      .should.be.rejectedWith(EVMThrow)
  })
})


================================================
FILE: test/MANAContinuousSale.js
================================================
// @flow
'use strict'

const expect = require('chai').expect
const { advanceTime, EVMRevert } = require('./utils')
const MANAContinuousSale = artifacts.require('./MANAContinuousSale.sol')
const MANAToken = artifacts.require('./MANAToken.sol')

const BigNumber = web3.BigNumber

contract('MANAContinuousSale', function([owner, wallet, buyer, wallet2]) {
  const rate = new BigNumber(1)
  const newRate = new BigNumber(2)
  const value = new BigNumber(100)

  let token, sale

  beforeEach(async function() {
    token = await MANAToken.new()
    await token.pause()
    await token.mint(owner, new BigNumber(1000000))

    sale = await MANAContinuousSale.new(rate, wallet, token.address)
    await token.transferOwnership(sale.address)
  })

  it('should start with continuous sale disabled', async function() {
    let started = await sale.started()
    started.should.equal(false)

    await sale.start()
    started = await sale.started()
    started.should.equal(true)
  })

  it('owner should be able to pause/unpause token', async function() {
    await sale.unpauseToken().should.be.fulfilled
    let paused = await token.paused()
    paused.should.equal(false)

    await sale.pauseToken().should.be.fulfilled
    paused = await token.paused()
    paused.should.equal(true)
  })

  it('non-owners should not be able to pause/unpause token', async function() {
    await sale.unpauseToken({ from: buyer }).should.be.rejectedWith(EVMRevert)

    await sale.unpauseToken({ from: owner })
    await sale.pauseToken({ from: buyer }).should.be.rejectedWith(EVMRevert)
  })

  it('should accept payments only if sale has started', async function() {
    await sale.send(value, { from: buyer }).should.be.rejectedWith(EVMRevert)
    await sale.start().should.be.fulfilled
    await sale.buyTokens(buyer, {
      value: new BigNumber(100),
      from: buyer
    }).should.be.fulfilled
  })

  it('only owner can change rate', async function() {
    await sale
      .setRate(newRate, { from: buyer })
      .should.be.rejectedWith(EVMRevert)

    const { logs } = await sale.setRate(newRate)

    const event = logs.find(e => e.event === 'RateChange')
    expect(event).to.exist

    const updatedRate = await sale.rate()
    updatedRate.should.be.bignumber.equal(newRate)
  })

  it('only owner can change wallet', async function() {
    await sale
      .setRate(newRate, { from: buyer })
      .should.be.rejectedWith(EVMRevert)

    const { logs } = await sale.setRate(newRate)

    const event = logs.find(e => e.event === 'RateChange')
    expect(event).to.exist

    const updatedRate = await sale.rate()
    updatedRate.should.be.bignumber.equal(newRate)
  })

  it('should reject payments if amount of tokens is bigger than block bucket', async function() {
    await sale.start()
    await sale
      .send(new BigNumber(1000), { from: buyer })
      .should.be.rejectedWith(EVMRevert)
  })

  it('should start with a fixed issuance rate', async function() {
    // total tokens emitted are 1000000 so issuance must be:
    //
    // seconds in 12 hours: 43200
    // seconds in a year: 31536000
    // 1000000 * 0.08 * 43200 / 31536000 = 109
    let issuance = await sale.issuance()
    issuance.should.be.bignumber.equal(new BigNumber(0))

    await sale.start()
    issuance = await sale.issuance()
    issuance.should.be.bignumber.equal(new BigNumber(109))
  })

  it('should handle time buckets for token issuance', async function() {
    await sale.start()

    await sale.buyTokens(buyer, { value, from: buyer }).should.be.fulfilled
    await sale
      .buyTokens(buyer, { value, from: buyer })
      .should.be.rejectedWith(EVMRevert)

    const bucketSize = await sale.BUCKET_SIZE()
    await advanceTime(bucketSize)

    await sale.buyTokens(buyer, { value, from: buyer }).should.be.fulfilled
  })
})


================================================
FILE: test/MANACrowdsale.js
================================================
// @flow
'use strict'

const expect = require('chai').expect

const { advanceToBlock, ether, should, EVMRevert } = require('./utils')
const MANACrowdsale = artifacts.require('./MANACrowdsale.sol')
const MANAContinuousSale = artifacts.require('./MANAContinuousSale.sol')
const MANAToken = artifacts.require('./MANAToken.sol')

const BigNumber = web3.BigNumber

contract('MANACrowdsale', function([
  _,
  wallet,
  wallet2,
  buyer,
  purchaser,
  buyer2,
  purchaser2
]) {
  const initialRate = new BigNumber(1000)
  const endRate = new BigNumber(900)

  const newRate = new BigNumber(500)
  const preferentialRate = new BigNumber(2000)
  const value = ether(1)

  const expectedFoundationTokens = new BigNumber(6000)
  const expectedTokenSupply = new BigNumber(10000)

  let startBlock, endBlock
  let crowdsale, token

  beforeEach(async function() {
    startBlock = web3.eth.blockNumber + 10
    endBlock = web3.eth.blockNumber + 20

    crowdsale = await MANACrowdsale.new(
      startBlock,
      endBlock,
      initialRate,
      endRate,
      preferentialRate,
      wallet
    )
    token = MANAToken.at(await crowdsale.token())
  })

  it('starts with token paused', async function() {
    const paused = await token.paused()
    paused.should.equal(true)
  })

  it('owner should be able to change wallet', async function() {
    await crowdsale.setWallet(wallet2)
    let wallet = await crowdsale.wallet()
    wallet.should.equal(wallet2)

    const continuousSale = MANAContinuousSale.at(
      await crowdsale.continuousSale()
    )
    wallet = await continuousSale.wallet()
    wallet.should.equal(wallet2)
  })

  it('non-owner should not be able to change wallet', async function() {
    await crowdsale
      .setWallet(wallet2, { from: purchaser })
      .should.be.rejectedWith(EVMRevert)
  })

  it('owner should be able to start continuous sale', async function() {
    await crowdsale.beginContinuousSale().should.be.rejectedWith(EVMRevert)

    await advanceToBlock(endBlock)
    await crowdsale.finalize()

    const sale = MANAContinuousSale.at(await crowdsale.continuousSale())

    let started = await sale.started()
    started.should.equal(false)

    await crowdsale.beginContinuousSale().should.be.fulfilled

    started = await sale.started()
    started.should.equal(true)
  })

  it('owner should be able to unpause token after crowdsale ends', async function() {
    await advanceToBlock(endBlock)

    await crowdsale.unpauseToken().should.be.rejectedWith(EVMRevert)

    await crowdsale.finalize()

    let paused = await token.paused()
    paused.should.equal(true)

    await crowdsale.unpauseToken()

    paused = await token.paused()
    paused.should.equal(false)
  })

  it('non-owners should not be able to start continuous sale', async function() {
    await crowdsale
      .beginContinuousSale({ from: purchaser })
      .should.be.rejectedWith(EVMRevert)
  })

  describe('rate during auction should decrease at a fixed step every block', async function() {
    let balance, startBlock, endBlock

    let initialRate = 9166
    let endRate = 5500
    let preferentialRate = initialRate
    const rateAtBlock10 = new BigNumber(9165)
    const rateAtBlock20 = new BigNumber(9164)
    const rateAtBlock100 = new BigNumber(9155)
    const rateAtBlock2 = new BigNumber(9166)
    const rateAtBlock10000 = new BigNumber(7973)
    const rateAtBlock30000 = new BigNumber(5586)

    beforeEach(async function() {
      startBlock = web3.eth.blockNumber + 10
      endBlock = web3.eth.blockNumber + 10 + 30720

      crowdsale = await MANACrowdsale.new(
        startBlock,
        endBlock,
        initialRate,
        endRate,
        preferentialRate,
        wallet
      )
      token = MANAToken.at(await crowdsale.token())
    })
    it('at start', async function() {
      await advanceToBlock(startBlock - 1)

      await crowdsale.buyTokens(buyer, { value, from: purchaser })
      balance = await token.balanceOf(buyer)
      balance.should.be.bignumber.equal(value.mul(initialRate))
    })

    it('at block 10', async function() {
      await advanceToBlock(startBlock + 9)

      await crowdsale.buyTokens(buyer2, { value, from: purchaser2 })
      balance = await token.balanceOf(buyer2)

      balance.should.be.bignumber.equal(value.mul(rateAtBlock10))
    })

    it('at block 20', async function() {
      await advanceToBlock(startBlock + 19)

      await crowdsale.buyTokens(buyer2, { value, from: purchaser2 })
      balance = await token.balanceOf(buyer2)

      balance.should.be.bignumber.equal(value.mul(rateAtBlock20))
    })

    it('at block 100', async function() {
      await advanceToBlock(startBlock + 99)

      await crowdsale.buyTokens(buyer2, { value, from: purchaser2 })
      balance = await token.balanceOf(buyer2)

      balance.should.be.bignumber.equal(value.mul(rateAtBlock100))
    })

    it('at block 2', async function() {
      await advanceToBlock(startBlock + 1)

      await crowdsale.buyTokens(buyer2, { value, from: purchaser2 })
      balance = await token.balanceOf(buyer2)

      balance.should.be.bignumber.equal(value.mul(rateAtBlock2))
    })

    it.skip('at block 10000', async function() {
      await advanceToBlock(startBlock + 9999)

      await crowdsale.buyTokens(buyer2, { value, from: purchaser2 })
      balance = await token.balanceOf(buyer2)

      balance.should.be.bignumber.equal(value.mul(rateAtBlock10000))
    })

    it.skip('at block 30000', async function() {
      await advanceToBlock(startBlock + 29999)

      await crowdsale.buyTokens(buyer2, { value, from: purchaser2 })
      balance = await token.balanceOf(buyer2)

      balance.should.be.bignumber.equal(value.mul(rateAtBlock30000))
    })
  })

  it('whitelisted buyers should access tokens at reduced price until end of auction', async function() {
    await crowdsale.addToWhitelist(buyer)

    await crowdsale.buyTokens(buyer, { value, from: buyer })
    const balance = await token.balanceOf(buyer)
    balance.should.be.bignumber.equal(value.mul(preferentialRate))
  })

  it('whitelisted big whale investor should not exceed the cap', async function() {
    const cap = await crowdsale.cap()
    const overCap = cap.mul(2)
    await crowdsale.addToWhitelist(buyer)
    await crowdsale
      .buyTokens(buyer, { value: overCap, from: buyer })
      .should.be.rejectedWith(EVMRevert)
    const balance = await token.balanceOf(buyer)
    const raised = await crowdsale.weiRaised()
    balance.should.be.bignumber.equal(0)
    raised.should.be.bignumber.most(cap)
  })

  it('owner can set the price for a particular buyer', async function() {
    await crowdsale.addToWhitelist(buyer)

    const preferentialRateForBuyer = new BigNumber(200)
    const { logs } = await crowdsale.setBuyerRate(
      buyer,
      preferentialRateForBuyer
    )

    const event = logs.find(e => e.event === 'PreferentialRateChange')
    expect(event).to.exist

    await crowdsale.buyTokens(buyer, { value, from: buyer })
    const balance = await token.balanceOf(buyer)
    balance.should.be.bignumber.equal(value.mul(preferentialRateForBuyer))
    balance.should.not.be.bignumber.equal(value.mul(preferentialRate))

    // cannot change rate after crowdsale starts
    await advanceToBlock(startBlock - 1)
    await crowdsale
      .setBuyerRate(buyer, preferentialRateForBuyer)
      .should.be.rejectedWith(EVMRevert)
  })

  it('owner cannot set a custom rate before whitelisting a buyer', async function() {
    await crowdsale
      .setBuyerRate(buyer, new BigNumber(200))
      .should.be.rejectedWith(EVMRevert)
  })

  it('beneficiary is not the same as buyer', async function() {
    const beneficiary = buyer2

    await crowdsale.addToWhitelist(buyer)
    await crowdsale.addToWhitelist(beneficiary)

    const preferentialRateForBuyer = new BigNumber(200)
    const invalidRate = new BigNumber(100)
    await crowdsale.setBuyerRate(buyer, preferentialRateForBuyer)
    await crowdsale.setBuyerRate(beneficiary, invalidRate)

    await crowdsale.buyTokens(beneficiary, { value, from: buyer })
    const balance = await token.balanceOf(beneficiary)
    balance.should.be.bignumber.equal(value.mul(preferentialRateForBuyer))
  })

  it('tokens should be assigned correctly to foundation when finalized', async function() {
    await advanceToBlock(startBlock - 1)

    // since price at first block is 1000, total tokens emitted will be 4000
    await crowdsale.buyTokens(buyer, { value: 4, from: purchaser })

    await advanceToBlock(endBlock)
    await crowdsale.finalize()

    const balance = await token.balanceOf(wallet)
    balance.should.be.bignumber.equal(expectedFoundationTokens)

    const totalSupply = await token.totalSupply()
    totalSupply.should.be.bignumber.equal(expectedTokenSupply)
  })
})


================================================
FILE: test/MANAToken.js
================================================
// @flow
'use strict'

const { EVMRevert } = require('./utils')
const MANAToken = artifacts.require('./MANAToken.sol')

const BigNumber = web3.BigNumber

contract('MANACrowdsale', function([owner, holder]) {
  let token

  beforeEach(async function() {
    token = await MANAToken.new()
  })

  it('cannot burn tokens while paused', async function() {
    await token.mint(holder, 1000)
    await token.pause()
    await token.burn(500, { from: holder }).should.be.rejectedWith(EVMRevert)

    await token.unpause()
    await token.burn(500, { from: holder }).should.be.fulfilled
  })
})


================================================
FILE: test/WhitelistedCrowdsale.js
================================================
// @flow
import { ether, EVMRevert } from './utils'

const BigNumber = web3.BigNumber

const WhitelistedCrowdsale = artifacts.require(
  './helpers/WhitelistedCrowdsaleImpl.sol'
)
const MintableToken = artifacts.require(
  'zeppelin-solidity/contracts/tokens/MintableToken'
)

contract('WhitelistCrowdsale', function([
  _,
  owner,
  wallet,
  beneficiary,
  sender
]) {
  const rate = new BigNumber(1000)

  beforeEach(async function() {
    this.startBlock = web3.eth.blockNumber + 10
    this.endBlock = this.startBlock + 10

    this.crowdsale = await WhitelistedCrowdsale.new(
      this.startBlock,
      this.endBlock,
      rate,
      wallet,
      { from: owner }
    )

    this.token = MintableToken.at(await this.crowdsale.token())
  })

  describe('whitelisting', function() {
    const amount = ether(1)

    it('should add address to whitelist', async function() {
      let whitelisted = await this.crowdsale.isWhitelisted(sender)
      whitelisted.should.equal(false)
      await this.crowdsale.addToWhitelist(sender, { from: owner })
      whitelisted = await this.crowdsale.isWhitelisted(sender)
      whitelisted.should.equal(true)
    })

    it('should reject non-whitelisted sender', async function() {
      await this.crowdsale
        .buyTokens(beneficiary, { value: amount, from: sender })
        .should.be.rejectedWith(EVMRevert)
    })

    it('should sell to whitelisted address', async function() {
      await this.crowdsale.addToWhitelist(sender, { from: owner })
      await this.crowdsale.buyTokens(beneficiary, {
        value: amount,
        from: sender
      }).should.be.fulfilled
    })
  })
})


================================================
FILE: test/helpers/BurnableTokenMock.sol
================================================
pragma solidity ^0.4.11;

import '../../contracts/BurnableToken.sol';

contract BurnableTokenMock is BurnableToken {

  function BurnableTokenMock(address initialAccount, uint initialBalance) {
    balances[initialAccount] = initialBalance;
    totalSupply = initialBalance;
  }

}


================================================
FILE: test/helpers/WhitelistedCrowdsaleImpl.sol
================================================
pragma solidity ^0.4.11;


import '../../contracts/WhitelistedCrowdsale.sol';


contract WhitelistedCrowdsaleImpl is WhitelistedCrowdsale {

  function WhitelistedCrowdsaleImpl (
    uint256 _startBlock,
    uint256 _endBlock,
    uint256 _rate,
    address _wallet
  )
    Crowdsale(_startBlock, _endBlock, _rate, _wallet)
    WhitelistedCrowdsale() 
  {
  }

}


================================================
FILE: test/utils.js
================================================
// @flow

const BigNumber = web3.BigNumber

export const should = require('chai')
  .use(require('chai-as-promised'))
  .use(require('chai-bignumber')(BigNumber))
  .should()

type RPCParams = {
  method: string,
  params?: Array<mixed>
}

function rpcCall(call: RPCParams) {
  const payload: any = Object.assign(
    {},
    {
      jsonrpc: '2.0',
      id: Date.now()
    },
    call
  )

  return new Promise((resolve, reject) => {
    web3.currentProvider.sendAsync(payload, (err, res) => {
      return err ? reject(err) : resolve(res)
    })
  })
}

export function advanceBlock() {
  return rpcCall({ method: 'evm_mine' })
}

export function increaseTime(seconds: number) {
  return rpcCall({ method: 'evm_increaseTime', params: [+seconds] })
}

// Advances the block number so that the last mined block is `number`.
export async function advanceToBlock(number: number) {
  if (web3.eth.blockNumber > number) {
    throw Error(
      `block number ${number} is in the past (current is ${
        web3.eth.blockNumber
      })`
    )
  }

  while (web3.eth.blockNumber < number) {
    await advanceBlock()
  }
}

export async function advanceToTime(timestamp: number) {
  const block = await web3.eth.getBlock('latest')
  if (block.timestamp > timestamp) {
    throw Error(
      `time ${timestamp} is in the past (current is ${block.timestamp})`
    )
  }

  await advanceTime(timestamp - block.timestamp)
}

export async function advanceTime(time: number) {
  await increaseTime(time)
  await advanceBlock()
}

export function ether(n: number) {
  return new web3.BigNumber(web3.toWei(n, 'ether'))
}

export const EVMThrow = 'invalid opcode'
export const EVMRevert = 'revert'


================================================
FILE: truffle.js
================================================
require('babel-register');
require('babel-polyfill');

module.exports = {
  networks: {
    livenet: {
      host: "localhost",
      port: 8546,
      network_id: "1" // Match any network id
    },
    development: {
      host: "localhost",
      port: 8545,
      gas: 10000000,
      network_id: "*" // Match any network id
    }
  }
};
Download .txt
gitextract_8qja0b87/

├── .babelrc
├── .circleci/
│   └── config.yml
├── .editorconfig
├── .eslintrc
├── .flowconfig
├── .gitattributes
├── .gitignore
├── .npmignore
├── .travis.yml
├── LICENSE
├── README.md
├── contracts/
│   ├── BurnableToken.sol
│   ├── ContinuousSale.sol
│   ├── MANAContinuousSale.sol
│   ├── MANACrowdsale.sol
│   ├── MANAToken.sol
│   ├── Migrations.sol
│   └── WhitelistedCrowdsale.sol
├── flow-typed/
│   └── defs.js
├── migrations/
│   ├── 1_initial_migration.js
│   └── 2_deploy_contracts.js
├── package.json
├── scripts/
│   └── test.sh
├── test/
│   ├── BurnableToken.js
│   ├── MANAContinuousSale.js
│   ├── MANACrowdsale.js
│   ├── MANAToken.js
│   ├── WhitelistedCrowdsale.js
│   ├── helpers/
│   │   ├── BurnableTokenMock.sol
│   │   └── WhitelistedCrowdsaleImpl.sol
│   └── utils.js
└── truffle.js
Download .txt
SYMBOL INDEX (7 symbols across 1 files)

FILE: test/utils.js
  function rpcCall (line 15) | function rpcCall(call: RPCParams) {
  function advanceBlock (line 32) | function advanceBlock() {
  function increaseTime (line 36) | function increaseTime(seconds: number) {
  function advanceToBlock (line 41) | async function advanceToBlock(number: number) {
  function advanceToTime (line 55) | async function advanceToTime(timestamp: number) {
  function advanceTime (line 66) | async function advanceTime(time: number) {
  function ether (line 71) | function ether(n: number) {
Condensed preview — 32 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (41K chars).
[
  {
    "path": ".babelrc",
    "chars": 33,
    "preview": "{\n  \"presets\": [\"flow\", \"env\"]\n}\n"
  },
  {
    "path": ".circleci/config.yml",
    "chars": 1609,
    "preview": "version: 2\njobs:\n  build:\n    docker:\n      # specify the version you desire here\n      - image: circleci/node:10.2-stre"
  },
  {
    "path": ".editorconfig",
    "chars": 124,
    "preview": "root = true\n\n[*]\nend_of_line = lf\ninsert_final_newline = true\ncharset = utf-8\n\n[*.sol]\nindent_style = space\nindent_size "
  },
  {
    "path": ".eslintrc",
    "chars": 169,
    "preview": "{\n  \"extends\": [\"standard\"],\n  \"env\": {\n    \"node\": true,\n    \"jasmine\": true\n  },\n  \"globals\": {\n    \"web3\": false,\n   "
  },
  {
    "path": ".flowconfig",
    "chars": 48,
    "preview": "[ignore]\n\n[include]\n\n[libs]\n\n[options]\n\n[lints]\n"
  },
  {
    "path": ".gitattributes",
    "chars": 56,
    "preview": "*.sol linguist-language=Solidity\n*.js linguist-vendored\n"
  },
  {
    "path": ".gitignore",
    "chars": 21,
    "preview": "node_modules/\nbuild/\n"
  },
  {
    "path": ".npmignore",
    "chars": 42,
    "preview": "migrations\ntest\nzos.*\nscripts \nflow-typed\n"
  },
  {
    "path": ".travis.yml",
    "chars": 78,
    "preview": "language: node_js\nnode_js:\n  - \"7\"\ncache:\n  directories:\n    - \"node_modules\"\n"
  },
  {
    "path": "LICENSE",
    "chars": 586,
    "preview": "Copyright 2017 The Decentraland Team\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use fi"
  },
  {
    "path": "README.md",
    "chars": 282,
    "preview": "![](https://decentraland.org/favicon.ico)\n\nDecentraland MANA Token\n=======================\n\n[![Build Status](https://tra"
  },
  {
    "path": "contracts/BurnableToken.sol",
    "chars": 643,
    "preview": "pragma solidity ^0.4.11;\n\nimport 'zeppelin-solidity/contracts/token/StandardToken.sol';\n\n/**\n * @title Burnable Token\n *"
  },
  {
    "path": "contracts/ContinuousSale.sol",
    "chars": 2648,
    "preview": "pragma solidity ^0.4.11;\n\nimport \"zeppelin-solidity/contracts/token/MintableToken.sol\";\n\n/**\n * @title ContinuousSale\n *"
  },
  {
    "path": "contracts/MANAContinuousSale.sol",
    "chars": 1441,
    "preview": "pragma solidity ^0.4.11;\n\nimport \"zeppelin-solidity/contracts/ownership/Ownable.sol\";\nimport \"./ContinuousSale.sol\";\nimp"
  },
  {
    "path": "contracts/MANACrowdsale.sol",
    "chars": 5201,
    "preview": "pragma solidity ^0.4.11;\n\nimport \"zeppelin-solidity/contracts/crowdsale/CappedCrowdsale.sol\";\nimport \"zeppelin-solidity/"
  },
  {
    "path": "contracts/MANAToken.sol",
    "chars": 486,
    "preview": "pragma solidity ^0.4.11;\n\nimport \"zeppelin-solidity/contracts/token/PausableToken.sol\";\nimport \"zeppelin-solidity/contra"
  },
  {
    "path": "contracts/Migrations.sol",
    "chars": 493,
    "preview": "pragma solidity ^0.4.4;\n\ncontract Migrations {\n  address public owner;\n  uint public last_completed_migration;\n\n  modifi"
  },
  {
    "path": "contracts/WhitelistedCrowdsale.sol",
    "chars": 1164,
    "preview": "pragma solidity ^0.4.11;\n\nimport 'zeppelin-solidity/contracts/math/SafeMath.sol';\nimport 'zeppelin-solidity/contracts/cr"
  },
  {
    "path": "flow-typed/defs.js",
    "chars": 258,
    "preview": "declare var contract: (string, Function) => void\ndeclare var it: (string, Function) => void\ndeclare var describe: (strin"
  },
  {
    "path": "migrations/1_initial_migration.js",
    "chars": 129,
    "preview": "var Migrations = artifacts.require(\"./Migrations.sol\");\n\nmodule.exports = function(deployer) {\n  deployer.deploy(Migrati"
  },
  {
    "path": "migrations/2_deploy_contracts.js",
    "chars": 143,
    "preview": "const MANACrowdsale = artifacts.require(\"./MANACrowdsale.sol\");\n\nmodule.exports = function(deployer) {\n  // deployer.dep"
  },
  {
    "path": "package.json",
    "chars": 1532,
    "preview": "{\n  \"name\": \"decentraland-mana\",\n  \"version\": \"0.0.0-semantic-release\",\n  \"description\": \"Solidity Contracts for the Dec"
  },
  {
    "path": "scripts/test.sh",
    "chars": 1748,
    "preview": "#!/usr/bin/env bash\n\n# Executes cleanup function at script exit.\ntrap cleanup EXIT\n\ncleanup() {\n  # Kill the testrpc ins"
  },
  {
    "path": "test/BurnableToken.js",
    "chars": 1001,
    "preview": "// @flow\n'use strict'\n\nconst { should, EVMThrow } = require('./utils.js')\nconst BurnableTokenMock = artifacts.require('."
  },
  {
    "path": "test/MANAContinuousSale.js",
    "chars": 3820,
    "preview": "// @flow\n'use strict'\n\nconst expect = require('chai').expect\nconst { advanceTime, EVMRevert } = require('./utils')\nconst"
  },
  {
    "path": "test/MANACrowdsale.js",
    "chars": 8798,
    "preview": "// @flow\n'use strict'\n\nconst expect = require('chai').expect\n\nconst { advanceToBlock, ether, should, EVMRevert } = requi"
  },
  {
    "path": "test/MANAToken.js",
    "chars": 588,
    "preview": "// @flow\n'use strict'\n\nconst { EVMRevert } = require('./utils')\nconst MANAToken = artifacts.require('./MANAToken.sol')\n\n"
  },
  {
    "path": "test/WhitelistedCrowdsale.js",
    "chars": 1642,
    "preview": "// @flow\nimport { ether, EVMRevert } from './utils'\n\nconst BigNumber = web3.BigNumber\n\nconst WhitelistedCrowdsale = arti"
  },
  {
    "path": "test/helpers/BurnableTokenMock.sol",
    "chars": 282,
    "preview": "pragma solidity ^0.4.11;\n\nimport '../../contracts/BurnableToken.sol';\n\ncontract BurnableTokenMock is BurnableToken {\n\n  "
  },
  {
    "path": "test/helpers/WhitelistedCrowdsaleImpl.sol",
    "chars": 363,
    "preview": "pragma solidity ^0.4.11;\n\n\nimport '../../contracts/WhitelistedCrowdsale.sol';\n\n\ncontract WhitelistedCrowdsaleImpl is Whi"
  },
  {
    "path": "test/utils.js",
    "chars": 1685,
    "preview": "// @flow\n\nconst BigNumber = web3.BigNumber\n\nexport const should = require('chai')\n  .use(require('chai-as-promised'))\n  "
  },
  {
    "path": "truffle.js",
    "chars": 341,
    "preview": "require('babel-register');\nrequire('babel-polyfill');\n\nmodule.exports = {\n  networks: {\n    livenet: {\n      host: \"loca"
  }
]

About this extraction

This page contains the full source code of the decentraland/mana GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 32 files (36.6 KB), approximately 10.1k tokens, and a symbol index with 7 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!