├── .env ├── .gitignore ├── book.json ├── tests ├── test │ ├── vesting │ │ ├── index.js │ │ ├── vestingSchedule100.js │ │ └── vestingSchedule20-80.js │ ├── multi-pool.js │ ├── stake.js │ ├── erc20.js │ ├── nft-whitelist.js │ └── nft-erc20.js ├── index.js └── utils │ ├── index.js │ ├── numbers.js │ └── signer.js ├── help.txt ├── tooling └── docs │ └── jsdoc.json ├── index.js ├── docs ├── SUMMARY.md ├── README.md ├── WALLET.md ├── NUMBERS.md ├── NETWORK.md ├── APPLICATION.md ├── STAKING.md ├── SIGNER.md ├── IDOSTAKING.md ├── NFT_SWAP.md └── BASE_SWAP.md ├── src ├── interfaces │ ├── oldredeemmethod.json │ └── index.js ├── services │ └── DeploymentService.js ├── models │ ├── base │ │ ├── Addresses.js │ │ ├── Account.js │ │ ├── Contract.js │ │ ├── ERC20TokenContract.js │ │ └── Staking.js │ ├── index.js │ └── contracts │ │ ├── IDOStaking.js │ │ └── FixedNFTSwapContract.js └── utils │ ├── Wallet.js │ ├── Client.js │ ├── Network.js │ ├── Numbers.js │ ├── Chains.js │ └── Signer.js ├── VERSIONS.md ├── LICENSE ├── .circleci └── config.yml ├── README.md └── package.json /.env: -------------------------------------------------------------------------------- 1 | TEST_PRIVATE_KEY=0xfdf5475fe6be966cf39e533e5b478b2e10d04e5e966be18f45714550d2429d21 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | node_modules 3 | out 4 | _book 5 | .DS_Store 6 | .nyc_output -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "gitbook": "3.2.2", 3 | "root": "./docs", 4 | "structure": { 5 | "readme": "README.md" 6 | } 7 | } -------------------------------------------------------------------------------- /tests/test/vesting/index.js: -------------------------------------------------------------------------------- 1 | context('Vesting', async () => { 2 | require('./vestingSchedule20-80'); 3 | require('./vestingSchedule100'); 4 | }); -------------------------------------------------------------------------------- /help.txt: -------------------------------------------------------------------------------- 1 | // Update Github 2 | ``git push origin master`` 3 | 4 | // Create a new version 5 | ``npm version VERSION``` 6 | 7 | // Publish new version 8 | ``npm publish`` -------------------------------------------------------------------------------- /tooling/docs/jsdoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["node_modules/babel-core", "node_modules/babel-register"], 3 | "babel": { 4 | "presets": [ "es2015" ] 5 | } 6 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | let index = { 2 | FixedSwapContract : require("./src/models/contracts/FixedSwapContract"), 3 | Application : require("./src/models/index"), 4 | ERC20TokenContract : require("./src/models/base/ERC20TokenContract") 5 | }; 6 | 7 | module.exports = index; 8 | -------------------------------------------------------------------------------- /docs/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | ### Getting Started 4 | 5 | * [Application](APPLICATION.md) 6 | * [Fixed Swap](SWAP.md) 7 | * [Numbers Utils](NUMBERS.md) 8 | * [Signer](SIGNER.md) 9 | * [Network Utils](NETWORK.md) 10 | * [Staking](STAKING.md) 11 | * [IDO Staking](IDOSTAKING.md) 12 | * [Wallet Utils](WALLET.md) -------------------------------------------------------------------------------- /src/interfaces/oldredeemmethod.json: -------------------------------------------------------------------------------- 1 | { 2 | "inputs": [], 3 | "name": "unsoldTokensReedemed", 4 | "outputs": [ 5 | { 6 | "internalType": "bool", 7 | "name": "", 8 | "type": "bool" 9 | } 10 | ], 11 | "stateMutability": "view", 12 | "type": "function" 13 | } -------------------------------------------------------------------------------- /VERSIONS.md: -------------------------------------------------------------------------------- 1 | ## Polkastarter JS Versions 2 | 3 | | PSJS | Swap SC | Compatible with SC versions | 4 | |:---------|:--------------|:-----------------------------| 5 | | 1.2.7 | v2.1 | v2.1, v2.0 | 6 | | 1.2.8 | v3.0-RC5 | v3.0-RC5, v2.1, v2.0 | 7 | | 2.0.0 | v3.0.0 | v3.0.0, v2.1, v2.0 | 8 | -------------------------------------------------------------------------------- /tests/index.js: -------------------------------------------------------------------------------- 1 | context('Tests', async () => { 2 | require('./utils/numbers'); 3 | require('./utils/signer'); 4 | require('./test/eth'); 5 | require('./test/stake'); 6 | require('./test/nft'); 7 | require('./test/nft-whitelist'); 8 | require('./test/nft-erc20'); 9 | //require('./test/vesting'); 10 | //require('./test/erc20'); 11 | }); 12 | -------------------------------------------------------------------------------- /src/services/DeploymentService.js: -------------------------------------------------------------------------------- 1 | 2 | class DeploymentService { 3 | 4 | async deploy(account, contract, params, callback) { 5 | return await contract.deploy( 6 | account, 7 | contract.getABI(), 8 | contract.getJSON().bytecode, 9 | params, 10 | callback 11 | ) 12 | }; 13 | 14 | } 15 | 16 | export default DeploymentService; -------------------------------------------------------------------------------- /tests/utils/index.js: -------------------------------------------------------------------------------- 1 | export const mochaAsync = (fn) => { 2 | return done => { 3 | fn.call().then(done, err => { 4 | done(err); 5 | }); 6 | }; 7 | }; 8 | 9 | export const detectValidationErrors = (res) => { 10 | if(res.message == 'Validation errors'){ 11 | console.log(res.errors[0]); 12 | return true; 13 | }else{ 14 | return false; 15 | } 16 | } -------------------------------------------------------------------------------- /src/models/base/Addresses.js: -------------------------------------------------------------------------------- 1 | class addresses { 2 | tokenAddresses = { 3 | 'BSC': '0x7e624fa0e1c4abfd309cc15719b7e2580887f570', 4 | 'ETH': '0x83e6f1E41cdd28eAcEB20Cb649155049Fac3D5Aa' 5 | }; 6 | tokenTestAddresses = { 7 | 'BSC': '0xcfd314B14cAB8c3e36852A249EdcAa1D3Dd05055', 8 | 'ETH': '0x03EF180c07D30E46CAc83e5b9E282a9B295ca8A9' 9 | }; 10 | } 11 | 12 | let Addresses = new addresses() 13 | 14 | export default Addresses -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Polkastarter JS Docs 2 | 3 | Welcome to the Polkastarter JS doc to integrate Polkastarter. 4 | 5 | #### [Application](/docs/APPLICATION.md) 6 | 7 | #### [FixedSwap](/docs/SWAP.md) 8 | 9 | #### [FixedNFTSwap](/docs/NFT_SWAP.md) 10 | 11 | #### [Numbers Utils](/docs/NUMBERS.md) 12 | 13 | #### [Signer](/docs/SIGNER.md) 14 | 15 | #### [Network Utils](/docs/NETWORK.md) 16 | 17 | #### [Staking](/docs/STAKING.md) 18 | 19 | #### [IDO Staking](/docs/IDOSTAKING.md) 20 | 21 | #### [Wallet](/docs/WALLET.md) -------------------------------------------------------------------------------- /src/interfaces/index.js: -------------------------------------------------------------------------------- 1 | const fixedswap = () => { 2 | const originalJson = require("./fixedswap.json"); 3 | originalJson.abi.push(require("./oldredeemmethod.json")); 4 | return originalJson; 5 | } 6 | 7 | let index = { 8 | fixedswap: fixedswap(), 9 | fixednftswap: require("./fixednftswap.json"), 10 | fixedswap_legacy: require("./fixedswap_legacy.json"), 11 | ierc20: require("./ierc20token.json"), 12 | staking: require("./staking.json"), 13 | idostaking: require("./idostaking.json"), 14 | }; 15 | 16 | module.exports = index; 17 | -------------------------------------------------------------------------------- /docs/WALLET.md: -------------------------------------------------------------------------------- 1 | ## Classes 2 | 3 |
Adds POLS token to user's wallet
13 |ETH \| BSC \| MATIC \| DOT | The network where the token contract is. (Default: ETH) |
29 | | [test] | Boolean | ? Specifies if we're on test env (Default: false) |
30 |
31 |
32 |
33 | ## addTokenToWallet()
34 | Adds POLS token to user's wallet
35 |
36 | **Kind**: global function
37 |
--------------------------------------------------------------------------------
/src/models/base/Account.js:
--------------------------------------------------------------------------------
1 | class Account{
2 |
3 | constructor(web3, account){
4 | this.web3 = web3;
5 | this.account = account;
6 | }
7 |
8 |
9 | async getBalance(){
10 | let wei = await this.web3.eth.getBalance(this.getAddress());
11 | return this.web3.utils.fromWei(wei, 'ether')
12 | }
13 |
14 | getAddress(){
15 | return this.account.address;
16 | }
17 |
18 | getPrivateKey(){
19 | return this.account.privateKey;
20 | }
21 |
22 | getAccount(){
23 | return this.account
24 | }
25 |
26 | async sendEther(amount, address, data=null){
27 | let tx = {
28 | data : data,
29 | from : this.getAddress(),
30 | to : address,
31 | gas : 443000,
32 | value: amount
33 | }
34 | let result = await this.account.signTransaction(tx);
35 | let transaction = await this.web3.eth.sendSignedTransaction(result.rawTransaction);
36 | return transaction;
37 | }
38 | }
39 |
40 |
41 | export default Account;
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Polkastarter
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/utils/Wallet.js:
--------------------------------------------------------------------------------
1 | /* istanbul ignore file */
2 |
3 | import Addresses from "../models/base/Addresses";
4 |
5 | import Chains from "./Chains";
6 |
7 | /**
8 | * Wallet utils object
9 | * @constructor Wallet
10 | * @param {(ETH|BSC|MATIC|DOT)=} network The network where the token contract is. (Default: ETH)
11 | * @param {Boolean=} test ? Specifies if we're on test env (Default: false)
12 | */
13 | class Wallet {
14 |
15 | constructor(network='ETH', test = false) {
16 | Chains.checkIfNetworkIsSupported(network);
17 | this.network = network;
18 | this.test = test;
19 | if (test) {
20 | this.tokenAddress = Addresses.tokenTestAddresses;
21 | } else {
22 | this.tokenAddress = Addresses.tokenAddresses;
23 | }
24 |
25 | }
26 |
27 | /**
28 | * @function addTokenToWallet
29 | * @description Adds POLS token to user's wallet
30 | */
31 | async addTokenToWallet() {
32 | if (window.ethereum) {
33 | await window.ethereum.request({
34 | method: 'metamask_watchAsset',
35 | params: {
36 | "type": "ERC20",
37 | "options": {
38 | "address": this.tokenAddress,
39 | "symbol": "POLS",
40 | "decimals": 18
41 | },
42 | },
43 | });
44 | }
45 | }
46 |
47 | }
48 |
49 | export default Wallet;
--------------------------------------------------------------------------------
/src/utils/Client.js:
--------------------------------------------------------------------------------
1 | /* istanbul ignore file */
2 |
3 | /**
4 | * Client utils object
5 | * @constructor Network
6 | */
7 | class Client {
8 | metamaskCall = async ({ f, acc, value, callback=()=> {} }) => {
9 | return new Promise( (resolve, reject) => {
10 | // Detect possible error on tx
11 | f.estimateGas({gas: 5000000}, (error, gasAmount) => {
12 | //if(error){reject("Transaction will fail : " + error);}
13 | if(gasAmount >= 5000000){
14 | reject("Transaction will fail, too much gas");
15 | }
16 |
17 | // all alright
18 | f.send({
19 | from: acc,
20 | value: value,
21 | })
22 | .on("confirmation", (confirmationNumber, receipt) => {
23 | callback(confirmationNumber)
24 | if (confirmationNumber > 0) {
25 | resolve(receipt);
26 | }
27 | })
28 | .on("error", (err) => {
29 | reject(err);
30 | });
31 | });
32 | });
33 | };
34 |
35 | sendTx = async (web3, acc, contract, f, call = false, value, callback=()=>{}) => {
36 | var res;
37 | if (!acc && !call) {
38 | const accounts = await web3.eth.getAccounts();
39 | res = await this.metamaskCall({ f, acc: accounts[0], value, callback });
40 | } else if (acc && !call) {
41 | let data = f.encodeABI();
42 | res = await contract.send(
43 | acc.getAccount(),
44 | data,
45 | value
46 | );
47 | } else if (acc && call) {
48 | res = await f.call({ from: acc.getAddress() });
49 | } else {
50 | res = await f.call();
51 | }
52 | return res;
53 | };
54 | }
55 | export default Client;
56 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2.1 # use CircleCI 2.1
2 | jobs: # a collection of steps
3 | build: # runs not using Workflows must have a `build` job as entry point
4 | working_directory: ~/mern-starter # directory where steps will run
5 | docker: # run the steps with Docker
6 | - image: circleci/node:10.13.0 # ...with this image as the primary container; this is where all `steps` will run
7 | steps: # a collection of executable commands
8 | - checkout # special step to check out source code to working directory
9 | - run:
10 | name: update-npm
11 | command: 'sudo npm install -g npm@latest'
12 | - restore_cache: # special step to restore the dependency cache
13 | # Read about caching dependencies: https://circleci.com/docs/2.0/caching/
14 | key: dependency-cache-{{ checksum "package.json" }}
15 | - run:
16 | name: install-npm-wee
17 | command: npm install
18 | - run: # run tests
19 | name: test
20 | command: npm run test
21 | - save_cache: # special step to save the dependency cache
22 | key: dependency-cache-{{ checksum "package.json" }}
23 | paths:
24 | - ./node_modules
25 | - store_artifacts: # special step to save test results as as artifact
26 | # Upload test summary for display in Artifacts: https://circleci.com/docs/2.0/artifacts/
27 | path: test-results.xml
28 | prefix: tests
29 | - store_artifacts: # for display in Artifacts: https://circleci.com/docs/2.0/artifacts/
30 | path: coverage
31 | prefix: coverage
32 | - store_test_results: # for display in Test Summary: https://circleci.com/docs/2.0/collect-test-data/
33 | path: test-results.xml
34 | # See https://circleci.com/docs/2.0/deployment-integrations/ for deploy examples
35 |
--------------------------------------------------------------------------------
/tests/utils/numbers.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 | import { Decimal } from 'decimal.js';
3 |
4 | import chai from 'chai';
5 | import Numbers from '../../src/utils/Numbers';
6 | import { mochaAsync } from '../utils';
7 |
8 | const ERC20TokenAddress = '0x7a7748bd6f9bac76c2f3fcb29723227e3376cbb2';
9 | var contractAddress = '0x420751cdeb28679d8e336f2b4d1fc61df7439b5a';
10 | var userPrivateKey = process.env.TEST_PRIVATE_KEY || '0x7f76de05082c4d578219ca35a905f8debe922f1f00b99315ebf0706afc97f132';
11 |
12 | const expect = chai.expect;
13 |
14 | context('Numbers', async () => {
15 | var app;
16 |
17 | it('should get a Fixed Value', mochaAsync(async () => {
18 | expect(Numbers.toSmartContractDecimals(new Decimal(0.087).plus(0.01), 18)).to.equal("97000000000000000");
19 | expect(Numbers.toSmartContractDecimals(new Decimal(0.087234523452345).plus(0.01), 18)).to.equal("97234523452345000");
20 | expect(Numbers.toSmartContractDecimals(new Decimal(0.007234523453345333).plus(0.01), 18)).to.equal("17234523453345333");
21 | expect(Numbers.fromDecimals("97000000000000000", 18)).to.equal("0.097");
22 | }));
23 |
24 | it('should make divisions', mochaAsync(async () => {
25 | const res = Numbers.safeDivide(1, 1092.25);
26 | expect(Numbers.safeDivide(1, res)).to.equal(1092.25);
27 | }));
28 |
29 | it('should convert hex to string', mochaAsync(async () => {
30 | const res = Numbers.fromHex(0x01);
31 | expect(res).to.equal('1');
32 | }));
33 |
34 | it('should convert to float', mochaAsync(async () => {
35 | const res = Numbers.toFloat('1.1413');
36 | expect(res).to.equal(1.14);
37 | }));
38 |
39 | it('should convert time to smart contract time', mochaAsync(async () => {
40 | const res = Numbers.timeToSmartContractTime(new Date('2022-02-20 10:00:00'));
41 | expect(res).to.equal(1645347600);
42 | }));
43 |
44 | });
45 |
--------------------------------------------------------------------------------
/docs/NUMBERS.md:
--------------------------------------------------------------------------------
1 | ## Classes
2 |
3 | stringConverts a "human" number to the minimum unit.
13 |FloatPerforms a safe division
16 |stringConverts a number from his minimum unit to a human readable one.
19 |string
34 | Converts a "human" number to the minimum unit.
35 |
36 | **Kind**: global function
37 |
38 | | Param | Type | Description |
39 | | --- | --- | --- |
40 | | value | Float | The number that you want to convert |
41 | | decimals | Integer | Number of decimals |
42 |
43 |
44 |
45 | ## safeDivide(value, valueToDivideTo) ⇒ Float
46 | Performs a safe division
47 |
48 | **Kind**: global function
49 |
50 | | Param | Type | Description |
51 | | --- | --- | --- |
52 | | value | Float | The number that you want to divide |
53 | | valueToDivideTo | Float | The number that you want to divide to |
54 |
55 |
56 |
57 | ## fromDecimals(value, decimals) ⇒ string
58 | Converts a number from his minimum unit to a human readable one.
59 |
60 | **Kind**: global function
61 |
62 | | Param | Type | Description |
63 | | --- | --- | --- |
64 | | value | Float | The number that you want to convert |
65 | | decimals | Integer | Number of decimals |
66 |
67 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # polkastarter-js
2 |
3 | polkastarter-js is package to integrate Polkastarter Ethereum Integrations
4 |
5 | ## Installation
6 |
7 | Use the package manager [npm] to install npm.
8 |
9 | ```bash
10 | npm i polkastarter-js
11 | ```
12 |
13 | ## Docs
14 |
15 | [Docs](/docs)
16 |
17 | ## Usage
18 |
19 | ```javascript
20 | import moment from 'moment';
21 | import Application from 'polkastarter-js/src/models';
22 |
23 | /* Test Version */
24 | let app = new Application({test : true});
25 |
26 | /* Create Contract */
27 | let swapContract = app.getFixedSwapContract({tokenAddress : '0x3237fff7f25a354f68b2054a019c5a00135a8955', decimals : 18});
28 |
29 | /* Deploy */
30 | await swapContract.deploy({
31 | tradeValue : 0.001,
32 | tokensForSale : 100,
33 | startDate : moment().add(6, 'hours'),
34 | endDate : moment().add(16, 'hours'),
35 | isETHTrade : true // isETHTrade,
36 | ERC20TradingAddress : // optional,
37 | isPOLSWhitelist : false // optional (default : false)
38 | });
39 |
40 | /* User Swap */
41 |
42 | /* a) (isETHTrade == false) */
43 | /* 1 - swap */
44 | await swapContract.swap({
45 | tokenAmount : 10
46 | });
47 |
48 | /* b) (isETHTrade == false) */
49 | /* 1 - verify if approved */
50 | await swapContract.isApprovedSwapERC20({
51 | tokenAmount : 10 ,
52 | address : /* address to be approved - user address */
53 | });
54 |
55 | /* 2 - approve tx (if not approved) */
56 | await swapContract.approveSwapERC20({
57 | tokenAmount : 10
58 | });
59 |
60 | /* 3 - swap */
61 | await swapContract.swap({
62 | tokenAmount : 10
63 | });
64 |
65 | ```
66 |
67 | ## Testing
68 |
69 | To run the test suite vs a local chain (ganache):
70 |
71 | ```bash
72 | npm test
73 | ```
74 |
75 | To run the test suite vs a testnet real chain (Kovan, BSC Testnet, etc):
76 |
77 | ```bash
78 | CHAIN_NAME=ETH npm test
79 | ```
80 |
81 | ## Testing old deployed pools
82 |
83 | This test will check that the current PSJS doesn't break the read method from already deployed pools, legacy or not.
84 |
85 | ```bash
86 | npm run test-pools
87 | ```
88 |
89 | ## License
90 |
91 | [MIT](https://choosealicense.com/licenses/mit/)
--------------------------------------------------------------------------------
/src/utils/Network.js:
--------------------------------------------------------------------------------
1 | /* istanbul ignore file */
2 |
3 | import Chains from "./Chains";
4 |
5 | /**
6 | * Network utils object
7 | * @constructor Network
8 | * @param {(ETH|BSC|MATIC|DOT)=} network The network where the staking contract is. (Default: ETH)
9 | * @param {Boolean=} test ? Specifies if we're on test env (Default: false)
10 | */
11 | class Network {
12 |
13 | constructor(network='ETH', test = false, getETHNetwork) {
14 | Chains.checkIfNetworkIsSupported(network);
15 | this.network = network;
16 | this.test = test;
17 | this.getETHNetwork = getETHNetwork;
18 | }
19 |
20 | /**
21 | * Callback when networks changes
22 | *
23 | * @callback onChainChangedCallback
24 | * @param {string} network - Network name
25 | */
26 |
27 |
28 | /**
29 | * @function onChainChanged
30 | * @param {onChainChangedCallback} callback
31 | * @description Triggers the callback after the users changes their chain
32 | */
33 | async onChainChanged({callback}) {
34 | window.ethereum.on('chainChanged', async () => {
35 | callback(await this.getETHNetwork());
36 | });
37 | }
38 |
39 | /**
40 | * @function changeToCurrentNetwork
41 | * @description Request the wallet to change to the current chain
42 | */
43 | async changeToCurrentNetwork() {
44 | await switchToNetwork(this.network)
45 | }
46 |
47 | /**
48 | * @function switchToNetwork
49 | * @description Request switch to the Avalanche chain
50 | */
51 | async switchToNetwork(chain) {
52 | if (window.ethereum && chain !== undefined) {
53 | var chain = Chains.getChainData(chain, !this.test)
54 |
55 | await window.ethereum.request({
56 | method: 'wallet_addEthereumChain',
57 | params: [
58 | {
59 | chainId: '0x' + chain.chainId.toString(16).toUpperCase(),
60 | chainName: chain.name,
61 | nativeCurrency: {
62 | name: chain.name,
63 | symbol: chain.currency,
64 | decimals: 18
65 | },
66 | rpcUrls: [chain.rpc],
67 | blockExplorerUrls: [chain.explorer]
68 | },
69 | ],
70 | });
71 | }
72 | }
73 | }
74 |
75 | export default Network;
--------------------------------------------------------------------------------
/src/models/base/Contract.js:
--------------------------------------------------------------------------------
1 | class Contract {
2 | constructor(web3, contract_json, address) {
3 | this.web3 = web3;
4 | this.json = contract_json;
5 | this.abi = contract_json.abi;
6 | this.address = address;
7 | this.contract = new web3.eth.Contract(contract_json.abi, address);
8 | }
9 |
10 | async deploy(account, abi, byteCode, args = [], callback=()=>{}) {
11 | try{
12 | var res;
13 | this.contract = new this.web3.eth.Contract(abi);
14 | if(account){
15 | let txSigned = await account.getAccount().signTransaction({
16 | data : this.contract.deploy({
17 | data : byteCode,
18 | arguments: args
19 | }).encodeABI(),
20 | from : account.getAddress(),
21 | gas : 6913388
22 | }
23 | );
24 | res = await this.web3.eth.sendSignedTransaction(txSigned.rawTransaction);
25 | }else{
26 | const accounts = await this.web3.eth.getAccounts();
27 | res = await this.__metamaskDeploy({byteCode, args, acc : accounts[0], callback});
28 | }
29 | this.address = res.contractAddress;
30 | return res;
31 | }catch(err){
32 | console.log("err", err);
33 | throw err;
34 | }
35 | }
36 |
37 | __metamaskDeploy = async ({byteCode, args, acc, callback = () => {}}) => {
38 | return new Promise ((resolve, reject) => {
39 | try{
40 | this.getContract()
41 | .deploy({
42 | data: byteCode,
43 | arguments: args,
44 | }).send({from : acc})
45 | .on('confirmation', (confirmationNumber, receipt) => {
46 | callback(confirmationNumber)
47 | if(confirmationNumber > 0){
48 | resolve(receipt);
49 | }
50 | })
51 | .on('error', err => {reject(err)});
52 | }catch(err){
53 | reject(err);
54 | }
55 | })
56 | }
57 |
58 | async use(contract_json, address) {
59 | this.json = contract_json;
60 | this.abi = contract_json.abi;
61 | this.address = address ? address : this.address;
62 | this.contract = new this.web3.eth.Contract(
63 | contract_json.abi,
64 | this.address
65 | );
66 | }
67 |
68 | async send(account, byteCode, value='0x0', callback=() => {}){
69 | return new Promise( async (resolve, reject) => {
70 | let tx = {
71 | data : byteCode,
72 | from : account.address,
73 | to : this.address,
74 | gas : 4430000,
75 | gasPrice : 25000000000,
76 | value: value ? value : '0x0'
77 | }
78 |
79 | let result = await account.signTransaction(tx);
80 | this.web3.eth.sendSignedTransaction(result.rawTransaction)
81 | .on('confirmation', (confirmationNumber, receipt) => {
82 | callback(confirmationNumber);
83 | if(confirmationNumber > 0){
84 | resolve(receipt);
85 | }
86 | })
87 | .on('error', err => {reject(err)});
88 | })
89 |
90 | }
91 |
92 | getContract() {
93 | return this.contract;
94 | }
95 |
96 | getABI() {
97 | return this.abi;
98 | }
99 |
100 | getJSON() {
101 | return this.json;
102 | }
103 |
104 | getAddress() {
105 | return this.address;
106 | }
107 | }
108 |
109 | export default Contract;
110 |
--------------------------------------------------------------------------------
/tests/test/multi-pool.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 |
3 | import Web3 from "web3";
4 | import chai from 'chai';
5 | import { mochaAsync } from '../utils';
6 | import Application from '../../src/models';
7 | var userPrivateKey = '0x7f76de05082c4d578219ca35a905f8debe922f1f00b99315ebf0706afc97f132';
8 |
9 | const expect = chai.expect;
10 |
11 |
12 | context('Multi pool tests', async () => {
13 |
14 |
15 | const getApp = ({chain}) => {
16 | return new Application({test: true, mainnet: true, network: chain, web3: undefined})
17 | }
18 |
19 | const getPool = async ({contractAddress, chain}) => {
20 | let swapContract = await getApp({chain}).getFixedSwapContract({contractAddress});
21 | swapContract.__init__();
22 | await swapContract.assertERC20Info();
23 | return swapContract;
24 | }
25 |
26 | const getUserAllocationsByPoolId = async ({ poolContract }) => {
27 | const purchases = await poolContract.getPurchaseIds();
28 | return await Promise.all(
29 | purchases.map(
30 | async(p) =>
31 | await poolContract.getPurchase({
32 | purchase_id: p,
33 | })
34 | )
35 | );
36 | }
37 |
38 | it('should read data from BSC', mochaAsync(async () => {
39 | const swapContract = await getPool({chain: 'BSC', contractAddress: '0xeE62650fA45aC0deb1B24Ec19f983A8f85B727aB'});
40 | expect(await swapContract.minimumReached()).to.equal(true);
41 | expect(swapContract.version).to.equal("2.0");
42 | expect(swapContract).to.not.equal(false);
43 | const allocation = (await getUserAllocationsByPoolId({poolContract: swapContract}))[3];
44 | expect(allocation._id).to.equal(3);
45 | expect(allocation.amount).to.equal('1999.68912');
46 | expect(allocation.purchaser).to.equal('0x458c107a047Bb98e5d7C4a574A742D5003baf957');
47 | expect(allocation.costAmount).to.equal('0.873989999999999874');
48 | }));
49 |
50 | it('should read data from old ETH pool', mochaAsync(async () => {
51 | const swapContract = await getPool({chain: 'ETH', contractAddress: '0x868Be4f80bB166a09489822C322deb3163B5025B'});
52 | expect(await swapContract.minimumReached()).to.equal(true);
53 | expect(swapContract.version).to.equal("1.0");
54 | expect(swapContract).to.not.equal(false);
55 | const allocation = (await getUserAllocationsByPoolId({poolContract: swapContract}))[6];
56 | expect(allocation._id).to.equal('6');
57 | expect(allocation.amount).to.equal('10683.89316');
58 | expect(allocation.purchaser).to.equal('0xab5C49e981Fd7F3cA3bdfDE1fFEBF38723446629');
59 | expect(allocation.costAmount).to.equal('0.224364');
60 | }));
61 |
62 | it('should read data from polygon', mochaAsync(async () => {
63 | const swapContract = await getPool({chain: 'MATIC', contractAddress: '0x18E98c89d3D0E7eDe0f6E8af32c6117c3eDbb8C6'});
64 | expect(await swapContract.minimumReached()).to.equal(true);
65 | expect(swapContract.version).to.equal("2.0");
66 | expect(swapContract).to.not.equal(false);
67 | const allocation = (await getUserAllocationsByPoolId({poolContract: swapContract}))[3];
68 | expect(allocation._id).to.equal('3');
69 | expect(allocation.amount).to.equal('1041.65625');
70 | expect(allocation.purchaser).to.equal('0xDab6AdACCaf60960E9B9C0c32C3C8C564F2db890');
71 | expect(allocation.costAmount).to.equal('333.33');
72 | }));
73 | });
74 |
--------------------------------------------------------------------------------
/src/models/base/ERC20TokenContract.js:
--------------------------------------------------------------------------------
1 | import contract from "./Contract";
2 | import { ierc20 } from "../../interfaces";
3 | import Numbers from "../../utils/Numbers";
4 | import Client from "../../utils/Client";
5 | let self;
6 |
7 | class ERC20TokenContract {
8 | constructor({contractAddress, web3, acc}) {
9 | if(acc){
10 | this.acc = acc;
11 | }
12 | this.params = {
13 | web3 : web3,
14 | contractAddress : contractAddress,
15 | contract: new contract(web3, ierc20, contractAddress),
16 | decimals : null
17 | };
18 | self = {
19 | contract: new contract(web3, ierc20, contractAddress)
20 | };
21 | this.client = new Client();
22 | }
23 |
24 | __assert() {
25 | this.params.contract.use(ierc20, this.getAddress());
26 | }
27 |
28 | getContract() {
29 | return this.params.contract.getContract();
30 | }
31 |
32 | getAddress() {
33 | return this.params.contractAddress;
34 | }
35 |
36 | setNewOwner = async ({ address }) => {
37 | try {
38 | return await this.client.sendTx(
39 | this.params.web3,
40 | this.acc,
41 | this.params.contract,
42 | this.params.contract
43 | .getContract()
44 | .methods.transferOwnership(address)
45 | );
46 | } catch (err) {
47 | console.log(err);
48 | }
49 | };
50 |
51 | async transferTokenAmount({ toAddress, tokenAmount}) {
52 | let amountWithDecimals = Numbers.toSmartContractDecimals(
53 | tokenAmount,
54 | await this.getDecimals()
55 | );
56 | return await this.client.sendTx(
57 |
58 | this.params.web3,
59 | this.acc,
60 | this.params.contract,
61 | this.params.contract
62 | .getContract()
63 | .methods.transfer(toAddress, amountWithDecimals)
64 | );
65 | }
66 |
67 | async getTokenAmount(address) {
68 | return Numbers.fromDecimals(
69 | await this.getContract().methods.balanceOf(address).call(),
70 | await this.getDecimals()
71 | );
72 | }
73 |
74 | async totalSupply() {
75 | return await this.getContract().methods.totalSupply().call();
76 | }
77 |
78 | getABI() {
79 | return self.contract;
80 | }
81 |
82 | async getDecimals(){
83 | if (!this.params.decimals) {
84 | this.params.decimals = parseInt(await this.getContract().methods.decimals().call());
85 | }
86 | return this.params.decimals;
87 | }
88 |
89 | async isApproved({ address, amount, spenderAddress, callback }) {
90 | try {
91 | let res = await this.client.sendTx(
92 | this.params.web3,
93 | this.acc,
94 | this.params.contract,
95 | this.params.contract
96 | .getContract()
97 | .methods.allowance(address, spenderAddress),
98 | true,
99 | null,
100 | callback
101 | );
102 |
103 | let approvedAmount = Numbers.fromDecimals(res, await this.getDecimals());
104 | if (typeof amount === 'string' || amount instanceof String) {
105 | amount = parseFloat(amount);
106 | }
107 | return (approvedAmount >= amount);
108 | } catch (err) {
109 | throw err;
110 | }
111 | }
112 |
113 | async approve({ address, amount, callback }) {
114 | try {
115 | let amountWithDecimals = Numbers.toSmartContractDecimals(
116 | amount,
117 | await this.getDecimals()
118 | );
119 | return await this.client.sendTx(
120 | this.params.web3,
121 | this.acc,
122 | this.params.contract,
123 | this.params.contract
124 | .getContract()
125 | .methods.approve(address, amountWithDecimals),
126 | null,
127 | null,
128 | callback
129 | );
130 | } catch (err) {
131 | throw err;
132 | }
133 | }
134 | }
135 |
136 | export default ERC20TokenContract;
137 |
--------------------------------------------------------------------------------
/docs/NETWORK.md:
--------------------------------------------------------------------------------
1 | ## Classes
2 |
3 | Triggers the callback after the users changes their chain
13 |Request the wallet to change to the current chain
16 |Request switch to the ETH chain
19 |Request switch to the Avalanche chain
22 |Request switch to the Moonbeam chain
25 |Request switch to the Celo chain
28 |Request switch to the Polygon chain
31 |Request switch to the Binance smart chain
34 |functionCallback when networks changes
42 |ETH \| BSC \| MATIC \| DOT | The network where the staking contract is. (Default: ETH) |
58 | | [test] | Boolean | ? Specifies if we're on test env (Default: false) |
59 |
60 |
61 |
62 | ## onChainChanged(callback)
63 | Triggers the callback after the users changes their chain
64 |
65 | **Kind**: global function
66 |
67 | | Param | Type |
68 | | --- | --- |
69 | | callback | [onChainChangedCallback](#onChainChangedCallback) |
70 |
71 |
72 |
73 | ## changeToCurrentNetwork()
74 | Request the wallet to change to the current chain
75 |
76 | **Kind**: global function
77 |
78 |
79 | ## switchToEthereum()
80 | Request switch to the ETH chain
81 |
82 | **Kind**: global function
83 |
84 |
85 | ## switchToAvalanche()
86 | Request switch to the Avalanche chain
87 |
88 | **Kind**: global function
89 |
90 |
91 | ## switchToMoonbeam()
92 | Request switch to the Moonbeam chain
93 |
94 | **Kind**: global function
95 |
96 |
97 | ## switchToCelo()
98 | Request switch to the Celo chain
99 |
100 | **Kind**: global function
101 |
102 |
103 | ## switchToPolygon()
104 | Request switch to the Polygon chain
105 |
106 | **Kind**: global function
107 |
108 |
109 | ## switchToBsc()
110 | Request switch to the Binance smart chain
111 |
112 | **Kind**: global function
113 |
114 |
115 | ## onChainChangedCallback : function
116 | Callback when networks changes
117 |
118 | **Kind**: global typedef
119 |
120 | | Param | Type | Description |
121 | | --- | --- | --- |
122 | | network | string | Network name |
123 |
124 |
--------------------------------------------------------------------------------
/src/utils/Numbers.js:
--------------------------------------------------------------------------------
1 | import moment from 'moment'
2 | import accounting from 'accounting'
3 | import dayjs from 'dayjs'
4 | import web3 from "web3";
5 | import { create, all } from 'mathjs';
6 |
7 | Number.prototype.noExponents = function () {
8 | var data = String(this).split(/[eE]/)
9 | if (data.length == 1) return data[0]
10 |
11 | var z = '',
12 | sign = this < 0 ? '-' : '',
13 | str = data[0].replace('.', ''),
14 | mag = Number(data[1]) + 1
15 |
16 | if (mag < 0) {
17 | z = sign + '0.'
18 | while (mag++) z += '0'
19 | return z + str.replace(/^\-/, '')
20 | }
21 | mag -= str.length
22 | while (mag--) z += '0'
23 | return str + z
24 | }
25 |
26 | /**
27 | * Numbers object
28 | * @constructor Numbers
29 | */
30 | class numbers {
31 | math = create(all, {
32 | number: 'BigNumber',
33 | precision: 64,
34 | });
35 |
36 | constructor() {}
37 |
38 | fromDayMonthYear(date) {
39 | let mom = moment().dayOfYear(date.day)
40 | mom.set('hour', date.hour)
41 | mom.set('year', date.year)
42 | return mom.format('ddd, hA')
43 | }
44 |
45 | fromSmartContractTimeToMinutes(time) {
46 | return dayjs.unix(time).toDate();
47 | }
48 |
49 | fromMinutesToSmartContracTime(time) {
50 | return time
51 | }
52 |
53 | fromHex(hex){
54 | return hex.toString();
55 | }
56 |
57 | toFloat(number) {
58 | return parseFloat(parseFloat(number).toFixed(2))
59 | }
60 |
61 | timeToSmartContractTime(time) {
62 | return parseInt(new Date(time).getTime() / 1000)
63 | }
64 |
65 | toDate(date) {
66 | let mom = moment().dayOfYear(date.day)
67 | mom.set('hour', date.hour)
68 | mom.set('year', date.year)
69 | return mom.unix()
70 | }
71 |
72 | toMoney(number) {
73 | var _0xbea8=["\x45\x55\x52","\x25\x76","\x66\x6F\x72\x6D\x61\x74\x4D\x6F\x6E\x65\x79"];return accounting[_0xbea8[2]](number,{symbol:_0xbea8[0],format:_0xbea8[1]})
74 | }
75 |
76 | formatNumber(number) {
77 | return accounting.formatNumber(number)
78 | }
79 |
80 | /**
81 | * @function toSmartContractDecimals
82 | * @description Converts a "human" number to the minimum unit.
83 | * @param {Float} value The number that you want to convert
84 | * @param {Integer} decimals Number of decimals
85 | * @returns {string}
86 | */
87 | toSmartContractDecimals(value, decimals) {
88 | return this.math.chain(this.math.bignumber(value)).multiply(this.math.bignumber(10 ** decimals)).done().toFixed(0);
89 | }
90 |
91 | /**
92 | * @function safeDivide
93 | * @description Performs a safe division
94 | * @param {Float} value The number that you want to divide
95 | * @param {Float} valueToDivideTo The number that you want to divide to
96 | * @returns {Float}
97 | */
98 | safeDivide(value, valueToDivideTo) {
99 | return parseFloat(this.math.chain(this.math.bignumber(value)).divide(this.math.bignumber(valueToDivideTo)).done());
100 | }
101 |
102 | /**
103 | * @function fromDecimals
104 | * @description Converts a number from his minimum unit to a human readable one.
105 | * @param {Float} value The number that you want to convert
106 | * @param {Integer} decimals Number of decimals
107 | * @returns {string}
108 | */
109 | fromDecimals(value, decimals) {
110 | if (value == null) {
111 | return 0;
112 | }
113 | return this.math.chain(
114 | this.math.bignumber(value.toString())).divide(this.math.bignumber(10 ** decimals)
115 | ).toString();
116 | }
117 |
118 | fromExponential(x) {
119 | var _0xe3ed=["\x61\x62\x73","\x65\x2D","\x73\x70\x6C\x69\x74","\x70\x6F\x77","\x30\x2E","\x30","\x6A\x6F\x69\x6E","\x73\x75\x62\x73\x74\x72\x69\x6E\x67","\x2B"];if(Math[_0xe3ed[0]](x)< 1.0){var e=parseInt(x.toString()[_0xe3ed[2]](_0xe3ed[1])[1]);if(e){x*= Math[_0xe3ed[3]](10,e- 1);x= _0xe3ed[4]+ new Array(e)[_0xe3ed[6]](_0xe3ed[5])+ x.toString()[_0xe3ed[7]](2)}}else {var e=parseInt(x.toString()[_0xe3ed[2]](_0xe3ed[8])[1]);if(e> 20){e-= 20;x/= Math[_0xe3ed[3]](10,e);x+= new Array(e+ 1)[_0xe3ed[6]](_0xe3ed[5])}};return x
120 | }
121 |
122 | }
123 |
124 | let Numbers = new numbers()
125 |
126 | export default Numbers
127 |
128 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "polkastarter-js",
3 | "version": "4.1.0",
4 | "description": "",
5 | "main": "index.js",
6 | "engines": {
7 | "node": ">=10.13.0 <=^14"
8 | },
9 | "directories": {
10 | "test": "test"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/polkastarter/polkastarter-js.git"
15 | },
16 | "dependencies": {
17 | "@walletconnect/web3-provider": "^1.5.2",
18 | "abi-decoder": "^1.2.0",
19 | "accounting": "^0.4.1",
20 | "axios": "^0.21.1",
21 | "babel-cli": "^6.26.0",
22 | "babel-plugin-transform-runtime": "^6.23.0",
23 | "babel-preset-env": "^1.6.1",
24 | "babel-preset-es2017": "^6.24.1",
25 | "babel-preset-stage-2": "^6.24.1",
26 | "big-number": "^2.0.0",
27 | "bignumber.js": "^9.0.1",
28 | "bn.js": "^5.1.3",
29 | "chai": "^4.2.0",
30 | "crypto-js": "^3.1.9-1",
31 | "dayjs": "^1.9.4",
32 | "decimal.js": "^10.2.1",
33 | "delay": "^4.4.0",
34 | "dotenv": "^8.2.0",
35 | "ethers": "^5.3.1",
36 | "execution-time": "^1.4.1",
37 | "express": "^4.17.1",
38 | "left-pad": "^1.3.0",
39 | "lodash": "^4.17.10",
40 | "mathjs": "^9.4.2",
41 | "mocha": "^5.1.1",
42 | "moment": "^2.21.0",
43 | "mongoose": "^5.9.5",
44 | "randomhex": "^0.1.5",
45 | "web3": "1.0.0-beta.55",
46 | "web3modal": "^1.9.4"
47 | },
48 | "scripts": {
49 | "test": "nyc ./node_modules/.bin/mocha ./tests/index.js --timeout 3000000 --require babel-core/register --require babel-polyfill",
50 | "test-pools": "nyc ./node_modules/.bin/mocha ./tests/test/multi-pool.js --timeout 3000000 --require babel-core/register --require babel-polyfill",
51 | "index": "babel-node ./index.js --presets es2015,stage-2",
52 | "docs:numbers": "jsdoc2md --configure tooling/docs/jsdoc.json --files src/utils/Numbers.js > docs/NUMBERS.md",
53 | "docs:app": "jsdoc2md --configure tooling/docs/jsdoc.json --files src/models/index.js > docs/APPLICATION.md",
54 | "docs:signer": "jsdoc2md --configure tooling/docs/jsdoc.json --files src/utils/Signer.js > docs/SIGNER.md",
55 | "docs:swap": "jsdoc2md --configure tooling/docs/jsdoc.json --files src/models/contracts/FixedSwapContract.js > docs/SWAP.md",
56 | "docs:nftswap": "jsdoc2md --configure tooling/docs/jsdoc.json --files src/models/contracts/FixedNFTSwapContract.js > docs/NFT_SWAP.md",
57 | "docs:baseswap": "jsdoc2md --configure tooling/docs/jsdoc.json --files src/models/contracts/base/BaseSwapContract.js > docs/BASE_SWAP.md",
58 | "docs:network": "jsdoc2md --configure tooling/docs/jsdoc.json --files src/utils/Network.js > docs/NETWORK.md",
59 | "docs:staking": "jsdoc2md --configure tooling/docs/jsdoc.json --files src/models/base/Staking.js > docs/STAKING.md",
60 | "docs:wallet": "jsdoc2md --configure tooling/docs/jsdoc.json --files src/utils/Wallet.js > docs/WALLET.md",
61 | "docs:idostaking": "jsdoc2md --configure tooling/docs/jsdoc.json --files src/models/contracts/IDOStaking.js > docs/IDOSTAKING.md",
62 | "docs": "npm run docs:numbers && npm run docs:signer && npm run docs:swap && npm run docs:network && npm run docs:app && npm run docs:staking && npm run docs:idostaking && npm run docs:wallet && npm run docs:nftswap && npm run docs:baseswap",
63 | "docs:prepare": "gitbook install",
64 | "docs:build": "npm run docs:prepare && npm run docs && gitbook build",
65 | "docs:serve": "npm run docs:prepare && npm run docs && gitbook serve",
66 | "docs:clean": "rimraf _book"
67 | },
68 | "devDependencies": {
69 | "babel-plugin-transform-runtime": "^6.23.0",
70 | "babel-preset-env": "^1.6.1",
71 | "babel-preset-es2015": "^6.24.1",
72 | "babel-register": "^6.26.0",
73 | "ganache-core": "^2.13.2",
74 | "gitbook-cli": "^2.3.2",
75 | "jsdoc-babel": "^0.5.0",
76 | "jsdoc-md": "^11.0.2",
77 | "jsdoc-to-markdown": "^7.0.0",
78 | "nyc": "^15.1.0",
79 | "should": "^7.1.0",
80 | "supertest": "^1.0.0"
81 | },
82 | "babel": {
83 | "presets": [
84 | "env",
85 | "es2015",
86 | "stage-2"
87 | ],
88 | "plugins": [
89 | "transform-runtime"
90 | ],
91 | "sourceMaps": true,
92 | "retainLines": true
93 | },
94 | "author": "",
95 | "license": "ISC"
96 | }
97 |
--------------------------------------------------------------------------------
/src/utils/Chains.js:
--------------------------------------------------------------------------------
1 | const networks = [
2 | { name: 'Ethereum Main', chain: 'ETH', currency: 'ETH', chainId: 1, testnet: false, rpc: "https://mainnet.infura.io/v3/40e2d4f67005468a83e2bcace6427bc8", explorer: "https://etherscan.io/" },
3 | { name: 'Ethereum Sepolia', chain: 'ETH', currency: 'ETH', chainId: 11155111, testnet: true, rpc: "https://ethereum-sepolia.publicnode.com", explorer: "https://sepolia.etherscan.io/" },
4 | { name: 'BSC Main', chain: 'BSC', currency: 'BSC', chainId: 56, testnet: false, rpc: "https://bsc-dataseed1.binance.org:443", explorer: "https://bscscan.com/" },
5 | { name: 'BSC Test', chain: 'BSC', currency: 'BSC', chainId: 97, testnet: true, rpc: "https://data-seed-prebsc-1-s1.binance.org:8545", explorer: "https://testnet.bscscan.com/" },
6 | { name: 'Polygon', chain: 'MATIC', currency: 'MATIC', chainId: 137, testnet: false, rpc: "https://polygon-rpc.com", explorer: "https://polygonscan.com/" },
7 | { name: 'Mumbai', chain: 'MATIC', currency: 'MATIC', chainId: 80001, testnet: true, rpc: "https://rpc-mumbai.maticvigil.com", explorer: "https://mumbai.polygonscan.com/" },
8 | { name: 'Celo', chain: 'CELO', currency: 'CELO', chainId: 42220, testnet: false, rpc: "https://forno.celo.org", explorer: "https://explorer.celo.org" },
9 | { name: 'Celo Testnet', chain: 'CELO', currency: 'CELO', chainId: 44787, testnet: true, rpc: "hhttps://alfajores-forno.celo-testnet.org", explorer: "https://alfajores-blockscout.celo-testnet.org" },
10 | { name: 'Avalanche', chain: 'AVAX', currency: 'AVAX', chainId: 43114, testnet: false, rpc: "https://api.avax.network/ext/bc/C/rpc", explorer: "https://snowtrace.io/" },
11 | { name: 'Avalanche Testnet', chain: 'AVAX', currency: 'AVAX', chainId: 43113, testnet: true, rpc: "https://api.avax-test.network/ext/bc/C/rpc", explorer: "https://testnet.snowtrace.io/" },
12 | { name: 'Arbitrum', chain: 'AETH', currency: 'ETH', chainId: 42161, testnet: false, rpc: "https://arb1.arbitrum.io/rpc", explorer: "https://arbiscan.io/" },
13 | { name: 'Arbitrum Sepolia', chain: 'AETH', currency: 'ETH', chainId: 421614, testnet: true, rpc: "https://sepolia-rollup.arbitrum.io/rpc", explorer: "https://sepolia.arbiscan.io/" },
14 | { name: 'Mode', chain: 'METH', currency: 'ETH', chainId: 34443, testnet: false, rpc: "https://mainnet.mode.network", explorer: "https://explorer.mode.network/" },
15 | { name: 'Mode Sepolia', chain: 'METH', currency: 'ETH', chainId: 919, testnet: true, rpc: "https://sepolia.mode.network", explorer: "https://sepolia.explorer.mode.network/" },
16 | { name: 'Base', chain: 'BETH', currency: 'ETH', chainId: 8453, testnet: false, rpc: "https://mainnet.base.org", explorer: "https://basescan.org/" },
17 | { name: 'Base Sepolia', chain: 'BETH', currency: 'ETH', chainId: 84532, testnet: true, rpc: "https://sepolia.base.org", explorer: "https://sepolia.basescan.org/" },
18 | { name: 'Sei', chain: 'SEI', currency: 'SEI', chainId: 1329, testnet: false, rpc: "https://evm-rpc.sei-apis.com", explorer: "https://seitrace.com/" },
19 | { name: 'Sei Testnet', chain: 'SEI', currency: 'SEI', chainId: 1328, testnet: true, rpc: "https://evm-rpc-testnet.sei-apis.com", explorer: "https://seitrace.com/" },
20 | ]
21 |
22 | /**
23 | * Chains object
24 | * @constructor Chains
25 | */
26 | class chains {
27 | constructor() {}
28 |
29 | checkIfNetworkIsSupported(network) {
30 | if(!this.isNetworkSupported(network)) {
31 | throw new Error("Network unsupported");
32 | }
33 | }
34 |
35 | isNetworkSupported(chain) {
36 | return networks.map((network) => network.chain).includes(chain)
37 | }
38 |
39 | getChainData(chain, mainnet = true) {
40 | return networks.find((network) => network.chain == chain && network.testnet !== mainnet)
41 | }
42 |
43 | getRpcUrl(chain, mainnet = true) {
44 | return networks.find((network) => network.chain == chain && network.testnet !== mainnet).rpc
45 | }
46 |
47 | getExplorercUrl(chain, mainnet = true) {
48 | return networks.find((network) => network.chain == chain && network.testnet !== mainnet).explorer
49 | }
50 |
51 | getNetworksEnum() {
52 | return networks.reduce((hash, network) => { hash[network.chainId] = network.name; return hash; }, {});
53 | }
54 | }
55 |
56 | let Chains = new chains()
57 |
58 | export default Chains
59 |
60 |
--------------------------------------------------------------------------------
/tests/utils/signer.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 |
3 | import chai from 'chai';
4 | import Application from '../../src/models';
5 | import { mochaAsync } from '../utils';
6 |
7 | const expect = chai.expect;
8 |
9 | context('Signer', async () => {
10 |
11 | const app = new Application({test : true, mainnet : false, network : 'ETH'});
12 | const signer = app.getSigner();
13 |
14 | const jsonAccount = {"address":"46d0e9eafe3a1eb66fc54cf40d949fd711e54355","crypto":{"cipher":"aes-128-ctr","ciphertext":"e3565812298ec27625e5a64e40beaf31233ac3fd392e08dc67928c1899f85722","cipherparams":{"iv":"7f35572de5630547d405177850f912c8"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"8c75a1deec757088496a0f24408a13683acc55f935a37b6a202380072eabe2e2"},"mac":"73026bbba3027046412d8c70132b1b5104a04ea7402b19526c6b2284395e0207"},"id":"fa401ff0-7e2e-4fbd-af65-115985a0f4f7","version":3};
15 | it('should generate valid accounts', mochaAsync(async () => {
16 | const account = await signer.generateSignerAccount({password: 'test1234'});
17 | expect(signer.getAddressFromAccount({accountJson: account, password: 'test1234'}).toLowerCase()).to.equal(('0x' + JSON.parse(account).address).toLowerCase());
18 | }));
19 |
20 | it('should sign addresses', mochaAsync(async () => {
21 | const signs = await signer.signAddresses({
22 | addresses: [
23 | '0xB9a83B0EB888bD041fE5704F75aAd88886A2bb0d',
24 | '0xA5E5fC6e75A19447544105995C0B6e8e405b63C2',
25 | '0x00'
26 | ],
27 | accountMaxAllocations: [
28 | 10,
29 | 20,
30 | 10
31 | ],
32 | decimals: 18,
33 | contractAddress: '0xb8f7166496996a7da21cf1f1b04d9b3e26a3d077',
34 | accountJson: JSON.stringify(jsonAccount),
35 | password: 'test1234'
36 | });
37 |
38 | expect(signs).to.have.deep.members([
39 | {
40 | address: '0xB9a83B0EB888bD041fE5704F75aAd88886A2bb0d',
41 | signature: '0x74f1e4aad1ed1aff418413052a519b856292bdf752558ad5eb56e05dcc52126b28fdabd9db2a72e09a205246f95984500fc7e8ad6e7043809f2d4bd53960e7831c',
42 | allocation: '10000000000000000000'
43 | },
44 | {
45 | address: '0xA5E5fC6e75A19447544105995C0B6e8e405b63C2',
46 | signature: '0x6f5f993225fdc5fc093f856ba658bc51bcd87bc4b1b3e91e526fd658982bfb5d4e1994d84eb39302af99d398d3a7cb890d06aedcdc429b48666795a433242e961c',
47 | allocation: '20000000000000000000'
48 | }
49 | ]);
50 | }));
51 |
52 | it('should verify signature', mochaAsync(async () => {
53 | const verified = await signer.verifySignature({
54 | signature: '0x74f1e4aad1ed1aff418413052a519b856292bdf752558ad5eb56e05dcc52126b28fdabd9db2a72e09a205246f95984500fc7e8ad6e7043809f2d4bd53960e7831c',
55 | address: '0xB9a83B0EB888bD041fE5704F75aAd88886A2bb0d',
56 | signerAddress: '0x46d0e9eafe3a1eb66fc54cf40d949fd711e54355',
57 | accountMaxAllocation: '10000000000000000000',
58 | contractAddress: '0xb8f7166496996a7da21cf1f1b04d9b3e26a3d077',
59 | });
60 | expect(verified).to.equal(true);
61 |
62 |
63 | const signedWithAnotherAccount = await signer.verifySignature({
64 | signature: '0x76d620690fbc5324ed1602e617cbb185c33e93b0e895587a9402a41faefc9dca2d2e40809da5a04707727665219574021517d827a83903e8c1dc220f7da876831c',
65 | address: '0xB9a83B0EB888bD041fE5704F75aAd88886A2bb0d',
66 | signerAddress: '0x46d0e9eafe3a1eb66fc54cf40d949fd711e54355',
67 | accountMaxAllocation: '10000000000000000000',
68 | contractAddress: '0xb8f7166496996a7da21cf1f1b04d9b3e26a3d077',
69 | });
70 | expect(signedWithAnotherAccount).to.equal(false);
71 |
72 | const signedWithAnotherAllocation = await signer.verifySignature({
73 | signature: '0x74f1e4aad1ed1aff418413052a519b856292bdf752558ad5eb56e05dcc52126b28fdabd9db2a72e09a205246f95984500fc7e8ad6e7043809f2d4bd53960e7831c',
74 | address: '0xB9a83B0EB888bD041fE5704F75aAd88886A2bb0d',
75 | signerAddress: '0x46d0e9eafe3a1eb66fc54cf40d949fd711e54355',
76 | accountMaxAllocation: '50000000000000000000',
77 | contractAddress: '0xb8f7166496996a7da21cf1f1b04d9b3e26a3d077',
78 | });
79 | expect(signedWithAnotherAllocation).to.equal(false);
80 |
81 | const invalidSig = await signer.verifySignature({
82 | signature: '0x76d620690fbc5324ed1602e617cbb185c33e93b0e895587a9402a41faefc9dca2d2e40809da5a04707727665219574021517d827a83903e8c1dc220f7ba876831c',
83 | address: '0xB9a83B0EB888bD041fE5704F75aAd88886A2bb0d',
84 | signerAddress: '0x46d0e9eafe3a1eb66fc54cf40d949fd711e54355',
85 | accountMaxAllocation: '10000000000000000000',
86 | contractAddress: '0xb8f7166496996a7da21cf1f1b04d9b3e26a3d077',
87 | });
88 | expect(invalidSig).to.equal(false);
89 | }));
90 |
91 | });
92 |
--------------------------------------------------------------------------------
/docs/APPLICATION.md:
--------------------------------------------------------------------------------
1 | ## Classes
2 |
3 | Starts an instance of web3 for read-only methods
13 |Starts an instance of web3
16 |Logins with metamask
19 |Returns the Signer instance.
22 |Returns the Network Utils instance.
25 |Returns the Wallet Utils instance.
28 |Returns the Staking Model instance.
31 |Returns Fixed Swap instance
34 |Returns Fixed NFT Swap instance
37 |Returns ERC20 instance
40 |Returns the current network
43 |Returns the connected user address
46 |Returns the native currency of the connected user wallet.
49 |ETH \| BSC \| MATIC \| DOT | Current network (Default = ETH) |
65 | | [mainnet] | Boolean | Specifies if we're on mainnet or tesnet (Default = true); |
66 | | [test] | Boolean | ? Specifies if we're on test env |
67 | | [web3] | Web3 | Custom Web3 instance. If not provided the Application will instance it for you. (Default: undefined) |
68 |
69 |
70 |
71 | ## startWithoutMetamask()
72 | Starts an instance of web3 for read-only methods
73 |
74 | **Kind**: global function
75 |
76 |
77 | ## start()
78 | Starts an instance of web3
79 |
80 | **Kind**: global function
81 |
82 |
83 | ## login()
84 | Logins with metamask
85 |
86 | **Kind**: global function
87 |
88 |
89 | ## getSigner()
90 | Returns the Signer instance.
91 |
92 | **Kind**: global function
93 |
94 |
95 | ## getNetworkUtils()
96 | Returns the Network Utils instance.
97 |
98 | **Kind**: global function
99 |
100 |
101 | ## getWalletUtils()
102 | Returns the Wallet Utils instance.
103 |
104 | **Kind**: global function
105 |
106 |
107 | ## getStaking([contractAddress], [tokenAddress])
108 | Returns the Staking Model instance.
109 |
110 | **Kind**: global function
111 |
112 | | Param | Type | Description |
113 | | --- | --- | --- |
114 | | [contractAddress] | string | The staking contract address. (Default: Predefined addresses depending on the network) |
115 | | [tokenAddress] | string | The staking token address. (Default: Predefined addresses depending on the network) |
116 |
117 |
118 |
119 | ## getFixedSwapContract(tokenAddress, [contractAddress])
120 | Returns Fixed Swap instance
121 |
122 | **Kind**: global function
123 |
124 | | Param | Type | Description |
125 | | --- | --- | --- |
126 | | tokenAddress | string | The token address we want to trade |
127 | | [contractAddress] | string | The swap contract address, in case t hat has already been instanced. (Default = null) |
128 |
129 |
130 |
131 | ## getFixedNFTSwapContract([contractAddress])
132 | Returns Fixed NFT Swap instance
133 |
134 | **Kind**: global function
135 |
136 | | Param | Type | Description |
137 | | --- | --- | --- |
138 | | [contractAddress] | string | The swap contract address, in case t hat has already been instanced. (Default = null) |
139 |
140 |
141 |
142 | ## getERC20TokenContract(tokenAddress)
143 | Returns ERC20 instance
144 |
145 | **Kind**: global function
146 |
147 | | Param | Type | Description |
148 | | --- | --- | --- |
149 | | tokenAddress | string | The token address |
150 |
151 |
152 |
153 | ## getETHNetwork()
154 | Returns the current network
155 |
156 | **Kind**: global function
157 |
158 |
159 | ## getAddress()
160 | Returns the connected user address
161 |
162 | **Kind**: global function
163 |
164 |
165 | ## getETHBalance()
166 | Returns the native currency of the connected user wallet.
167 |
168 | **Kind**: global function
169 |
--------------------------------------------------------------------------------
/docs/STAKING.md:
--------------------------------------------------------------------------------
1 | ## Classes
2 |
3 | Stakes tokens inside the stake contract
13 |Approve the stake to use approved tokens
16 |BooleanVerify if the address has approved the staking to deposit
19 |Withdraw tokens from the stake contract
22 |Withdraw all the tokens from the stake contract
25 |Claim rewards from the staking contract
28 |IntegerReturns the accumulated rewards
31 |IntegerReturns the stake time for a wallet
34 |IntegerReturns the lock time perdio
37 |IntegerReturns the stake time for a wallet
40 |IntegerReturns the stake amount for a wallet
43 |Web3 | |
59 | | [contractAddress] | string | The staking contract address. (Default: Predefined addresses depending on the network) |
60 | | acc | Account | |
61 | | [tokenAddress] | string | The staking token address. (Default: Predefined addresses depending on the network) |
62 | | [network] | ETH \| BSC \| MATIC \| DOT | The network where the staking contract is. (Default: ETH) |
63 | | [test] | Boolean | ? Specifies if we're on test env (Default: false) |
64 |
65 |
66 |
67 | ## stake(amount)
68 | Stakes tokens inside the stake contract
69 |
70 | **Kind**: global function
71 |
72 | | Param | Type | Description |
73 | | --- | --- | --- |
74 | | amount | Integer | Amount |
75 |
76 |
77 |
78 | ## approveStakeERC20(tokenAmount)
79 | Approve the stake to use approved tokens
80 |
81 | **Kind**: global function
82 |
83 | | Param | Type |
84 | | --- | --- |
85 | | tokenAmount | Integer |
86 |
87 |
88 |
89 | ## isApproved(tokenAmount, address) ⇒ Boolean
90 | Verify if the address has approved the staking to deposit
91 |
92 | **Kind**: global function
93 |
94 | | Param | Type |
95 | | --- | --- |
96 | | tokenAmount | Integer |
97 | | address | Address |
98 |
99 |
100 |
101 | ## withdraw(amount)
102 | Withdraw tokens from the stake contract
103 |
104 | **Kind**: global function
105 |
106 | | Param | Type |
107 | | --- | --- |
108 | | amount | Integer |
109 |
110 |
111 |
112 | ## withdrawAll()
113 | Withdraw all the tokens from the stake contract
114 |
115 | **Kind**: global function
116 |
117 |
118 | ## claim()
119 | Claim rewards from the staking contract
120 |
121 | **Kind**: global function
122 |
123 |
124 | ## userAccumulatedRewards(address) ⇒ Integer
125 | Returns the accumulated rewards
126 |
127 | **Kind**: global function
128 | **Returns**: Integer - userAccumulatedRewards
129 |
130 | | Param | Type |
131 | | --- | --- |
132 | | address | string |
133 |
134 |
135 |
136 | ## stakeTime(address) ⇒ Integer
137 | Returns the stake time for a wallet
138 |
139 | **Kind**: global function
140 | **Returns**: Integer - stakeTime
141 |
142 | | Param | Type |
143 | | --- | --- |
144 | | address | string |
145 |
146 |
147 |
148 | ## lockTimePeriod() ⇒ Integer
149 | Returns the lock time perdio
150 |
151 | **Kind**: global function
152 | **Returns**: Integer - lockTimePeriod
153 |
154 |
155 | ## getUnlockTime(address) ⇒ Integer
156 | Returns the stake time for a wallet
157 |
158 | **Kind**: global function
159 | **Returns**: Integer - unlockTime
160 |
161 | | Param | Type |
162 | | --- | --- |
163 | | address | string |
164 |
165 |
166 |
167 | ## stakeAmount(address) ⇒ Integer
168 | Returns the stake amount for a wallet
169 |
170 | **Kind**: global function
171 | **Returns**: Integer - stakeAmount
172 |
173 | | Param | Type |
174 | | --- | --- |
175 | | address | string |
176 |
177 |
--------------------------------------------------------------------------------
/tests/test/vesting/vestingSchedule100.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 |
3 | import chai from 'chai';
4 | import { mochaAsync, decimalAdjust } from '../../utils';
5 | import moment from 'moment';
6 | import Application from '../../../src/models';
7 | import delay from 'delay';
8 | const ERC20TokenAddress = '0x7a7748bd6f9bac76c2f3fcb29723227e3376cbb2';
9 | var contractAddress = '0x420751cdeb28679d8e336f2b4d1fc61df7439b5a';
10 | var userPrivateKey = process.env.TEST_PRIVATE_KEY || '0x7f76de05082c4d578219ca35a905f8debe922f1f00b99315ebf0706afc97f132';
11 |
12 | const expect = chai.expect;
13 | const tokenPurchaseAmount = 0.01;
14 | const tokenFundAmount = 0.03;
15 | const tradeValue = 0.01;
16 |
17 | context('Vesting Time = 1 And Vesting Schedule = 100', async () => {
18 | var swapContract, app, isSaleOpen;
19 |
20 | before( async () => {
21 | app = new Application({test : true, mainnet : false});
22 | });
23 |
24 | it('should deploy Fixed Swap Contract', mochaAsync(async () => {
25 |
26 | app = new Application({test : true, mainnet : false});
27 | /* Create Contract */
28 | swapContract = await app.getFixedSwapContract({tokenAddress : ERC20TokenAddress, decimals : 18});
29 | /* Deploy */
30 | let res = await swapContract.deploy({
31 | tradeValue : tradeValue,
32 | tokensForSale : tokenFundAmount,
33 | isTokenSwapAtomic : false,
34 | individualMaximumAmount : tokenFundAmount,
35 | startDate : moment().add(4, 'minutes'),
36 | endDate : moment().add(8, 'minutes'),
37 | hasWhitelisting : false,
38 | isETHTrade : true,
39 | vestingTime: 1,
40 | firstUnlock: 100
41 | });
42 | contractAddress = swapContract.getAddress();
43 | expect(res).to.not.equal(false);
44 | }));
45 |
46 | it('should get a Fixed Swap Contract From contractAddress', mochaAsync(async () => {
47 |
48 | /* Get Contract */
49 | swapContract = await app.getFixedSwapContract({contractAddress});
50 | swapContract.__init__();
51 | await swapContract.assertERC20Info();
52 | expect(swapContract).to.not.equal(false);
53 | }));
54 |
55 | it('should fund a Swap Contract and confirm balances', mochaAsync(async () => {
56 | /* Approve ERC20 Fund */
57 | let res = await swapContract.approveFundERC20({tokenAmount : tokenFundAmount});
58 | expect(res).to.not.equal(false);
59 | res = await swapContract.isApproved({address : app.account.getAddress(), tokenAmount : tokenFundAmount});
60 | expect(res).to.equal(true);
61 | /* Fund */
62 | res = await swapContract.hasStarted();
63 | expect(res).to.equal(false);
64 | res = await swapContract.fund({tokenAmount : tokenFundAmount});
65 | expect(res).to.not.equal(false);
66 | }));
67 |
68 | it('GET - isSaleOpen - before Start', mochaAsync(async () => {
69 | await delay(3*60*1000);
70 | let res = await swapContract.isOpen();
71 | isSaleOpen = res;
72 | expect(res).to.equal(true);
73 | }));
74 |
75 | it('should do a non atomic swap on the Contract', mochaAsync(async () => {
76 | let res = await swapContract.swap({tokenAmount : tokenPurchaseAmount});
77 | expect(res).to.not.equal(false);
78 | }));
79 |
80 | it('GET - Purchases', mochaAsync(async () => {
81 | let purchases = await swapContract.getPurchaseIds();
82 | expect(purchases.length).to.equal(1);
83 | }));
84 |
85 |
86 | it('GET - My Purchases', mochaAsync(async () => {
87 | let purchases = await swapContract.getAddressPurchaseIds({address : app.account.getAddress()});
88 | expect(purchases.length).to.equal(1);
89 | }));
90 |
91 | it('GET - Fixed Swap is Closed', mochaAsync(async () => {
92 | await delay(4*60*1000);
93 | let res = await swapContract.hasFinalized();
94 | expect(res).to.equal(true);
95 | res = await swapContract.isOpen();
96 | expect(res).to.equal(false);
97 | }));
98 |
99 | it('GET - Purchase ID', mochaAsync(async () => {
100 | let purchases = await swapContract.getAddressPurchaseIds({address : app.account.getAddress()});
101 | let purchase = await swapContract.getPurchase({purchase_id : purchases[0]});
102 | const amountPurchase = Number(purchase.amount).noExponents();
103 | expect(Number(amountPurchase).toFixed(2)).to.equal(Number(tokenPurchaseAmount).noExponents());
104 | expect(purchase.purchaser).to.equal(app.account.getAddress());
105 | expect(purchase.wasFinalized).to.equal(false);
106 | expect(purchase.reverted).to.equal(false);
107 | }));
108 |
109 | it('Should Redeem Tokens', mochaAsync(async () => {
110 | let purchases = await swapContract.getAddressPurchaseIds({address : app.account.getAddress()});
111 | let purchase = await swapContract.getPurchase({purchase_id : purchases[0]});
112 | let redeemTokens = await swapContract.redeemTokens({purchase_id : purchase._id});
113 | expect(redeemTokens.from).to.equal(app.account.getAddress());
114 | expect(redeemTokens.status).to.equal(true);
115 | }));
116 |
117 | it('GET - Distribution Info', mochaAsync(async () => {
118 | let info = await swapContract.getDistributionInformation();
119 | expect(Number(info.vestingTime).noExponents()).to.equal(Number(1).noExponents());
120 | expect(info.vestingSchedule).to.deep.equal([100]);
121 | }));
122 |
123 | it('GET - Purchase ID After Redeem', mochaAsync(async () => {
124 | let purchases = await swapContract.getAddressPurchaseIds({address : app.account.getAddress()});
125 | let purchase = await swapContract.getPurchase({purchase_id : purchases[0]});
126 | const amountPurchase = Number(purchase.amount).noExponents();
127 | expect(Number(amountPurchase).toFixed(2)).to.equal(Number(tokenPurchaseAmount).noExponents());
128 | expect(purchase.purchaser).to.equal(app.account.getAddress());
129 | expect(purchase.wasFinalized).to.equal(false);
130 | expect(purchase.reverted).to.equal(false);
131 | }));
132 | });
133 |
--------------------------------------------------------------------------------
/tests/test/stake.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 |
3 | import Web3 from "web3";
4 | import chai from 'chai';
5 | import { mochaAsync } from '../utils';
6 | import moment from 'moment';
7 | import Application from '../../src/models';
8 | import { ierc20, staking } from "../../src/interfaces";
9 | import * as ethers from 'ethers';
10 |
11 | var userPrivateKey = '0x7f76de05082c4d578219ca35a905f8debe922f1f00b99315ebf0706afc97f132';
12 |
13 | const expect = chai.expect;
14 |
15 |
16 | context('Staking Contract', async () => {
17 | var ERC20TokenAddress;
18 | var StakingAddress;
19 | var stakeContract;
20 | var app;
21 | var ethersProvider;
22 | var currentTime;
23 | var tenMinutes = 10 * 60;
24 | var lockTime = tenMinutes;
25 |
26 | const forwardTime = async (time) => {
27 | // "Roads? Where we’re going, we don’t need roads."
28 | const date = parseInt(new Date().getTime()/1000);
29 | currentTime = date + await ethersProvider.send('evm_increaseTime', [ time ]);
30 | return await ethersProvider.send('evm_mine');
31 | }
32 |
33 | before(mochaAsync(async () => {
34 | return new Promise(async (resolve) => {
35 | // Instance Application using ganache
36 | const ganacheProvider = require("ganache-core").provider({
37 | gasLimit: 10000000000,
38 |
39 | gasPrice: 1,
40 | debug: true,
41 | accounts: [
42 | {
43 | secretKey: userPrivateKey,
44 | balance: 10000000000000000000
45 | }
46 | ]
47 | });
48 | app = new Application({test : true, mainnet : false, network : 'BSC', web3:
49 | new Web3(ganacheProvider)
50 | });
51 | app.web3.eth.transactionConfirmationBlocks = 1;
52 | ethersProvider = new ethers.providers.Web3Provider(ganacheProvider);
53 |
54 | // Deploy the ERC20
55 | const contract = new app.web3.eth.Contract(ierc20.abi, null, {data: ierc20.bytecode});
56 | contract.deploy()
57 | .send({
58 | from: '0xe797860acFc4e06C1b2B96197a7dB1dFa518d5eB',
59 | gas: 4712388,
60 | })
61 | .on('confirmation', function(confirmationNumber, receipt){
62 | ERC20TokenAddress = receipt.contractAddress;
63 | // Deploy the stake contract
64 | const contractStake = new app.web3.eth.Contract(staking.abi, null, {data: staking.bytecode});
65 | contractStake.deploy({
66 | arguments: [ERC20TokenAddress, lockTime + '']
67 | })
68 | .send({
69 | from: '0xe797860acFc4e06C1b2B96197a7dB1dFa518d5eB',
70 | gas: 4712388,
71 | })
72 | .on('confirmation', function(confirmationNumber, receipt){
73 | StakingAddress = receipt.contractAddress;
74 | resolve();
75 | }).on('error', console.log);
76 |
77 | }).on('error', console.log);
78 | });
79 | }));
80 |
81 |
82 | it('should automatically get addresses', mochaAsync(async () => {
83 | let stakeContract = await app.getStaking({});
84 | expect(stakeContract).to.not.equal(false);
85 | expect(stakeContract.params.contractAddress).to.equal('0x1621AEC5D5B2e6eC6D9B58399E9D5253AF86DF5f');
86 | expect(stakeContract.params.erc20TokenContract.params.contractAddress).to.equal('0xcfd314B14cAB8c3e36852A249EdcAa1D3Dd05055');
87 | }));
88 |
89 | it('should get deployed contract', mochaAsync(async () => {
90 | stakeContract = await app.getStaking({contractAddress: StakingAddress, tokenAddress: ERC20TokenAddress});
91 | expect(stakeContract).to.not.equal(false);
92 | }));
93 |
94 | it('should return empty stake amount at start', mochaAsync(async () => {
95 | const res = await stakeContract.stakeAmount({address: app.account.getAddress()});
96 | expect(Number(res).noExponents()).to.equal(Number(0).noExponents());
97 | }));
98 |
99 | it('should stake after approve', mochaAsync(async () => {
100 | expect(await stakeContract.isApproved({address: app.account.getAddress(), tokenAmount: 1000})).to.equal(false);
101 | await stakeContract.approveStakeERC20({tokenAmount: 1000});
102 | expect(await stakeContract.isApproved({address: app.account.getAddress(), tokenAmount: '1000'})).to.equal(true);
103 | expect(await stakeContract.isApproved({address: app.account.getAddress(), tokenAmount: 1000})).to.equal(true);
104 | await stakeContract.stake({amount: 1000});
105 | const res = await stakeContract.stakeAmount({address: app.account.getAddress()});
106 | expect(Number(res).noExponents()).to.equal(Number(1000).noExponents());
107 |
108 | let unlockTime = parseInt(await stakeContract.stakeTime({address: app.account.getAddress()})) + parseInt(await stakeContract.getLockTimePeriod())
109 |
110 | expect(Number(await stakeContract.getUnlockTime({address: app.account.getAddress()})).noExponents()).to.equal(Number(unlockTime).noExponents())
111 | }));
112 |
113 |
114 | it('should fail withdraw if we didnt reach time', mochaAsync(async () => {
115 | let failed = false;
116 | try {
117 | res = await stakeContract.withdrawAll()
118 | expect(res).to.not.equal(false);
119 | } catch (e) {
120 | failed = true;
121 | }
122 | expect(failed).to.equal(true);
123 | }));
124 |
125 | it('should withdraw after stake', mochaAsync(async () => {
126 | await forwardTime(lockTime + 30);
127 | await stakeContract.withdraw({amount: 400});
128 | let res = await stakeContract.stakeAmount({address: app.account.getAddress()});
129 | expect(Number(res).noExponents()).to.equal(Number(600).noExponents());
130 | await stakeContract.withdrawAll();
131 | res = await stakeContract.stakeAmount({address: app.account.getAddress()});
132 | expect(Number(res).noExponents()).to.equal(Number(0).noExponents());
133 | }));
134 | });
--------------------------------------------------------------------------------
/tests/test/vesting/vestingSchedule20-80.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 |
3 | import chai from 'chai';
4 | import { mochaAsync } from '../../utils';
5 | import moment from 'moment';
6 | import Application from '../../../src/models';
7 | import delay from 'delay';
8 | const ERC20TokenAddress = '0x7a7748bd6f9bac76c2f3fcb29723227e3376cbb2';
9 | var contractAddress = '0x420751cdeb28679d8e336f2b4d1fc61df7439b5a';
10 | var userPrivateKey = process.env.TEST_PRIVATE_KEY || '0x7f76de05082c4d578219ca35a905f8debe922f1f00b99315ebf0706afc97f132';
11 |
12 | const expect = chai.expect;
13 | const tokenPurchaseAmount = 0.01;
14 | const tokenFundAmount = 0.03;
15 | const tradeValue = 0.01;
16 |
17 | context('Vesting Time = 2 And Vesting Schedule = 20% - 80%', async () => {
18 | var swapContract, app, isSaleOpen;
19 |
20 | before( async () => {
21 | app = new Application({test : true, mainnet : false});
22 | });
23 |
24 | it('should deploy Fixed Swap Contract', mochaAsync(async () => {
25 |
26 | app = new Application({test : true, mainnet : false});
27 | /* Create Contract */
28 | swapContract = await app.getFixedSwapContract({tokenAddress : ERC20TokenAddress, decimals : 18});
29 | /* Deploy */
30 | let res = await swapContract.deploy({
31 | tradeValue : tradeValue,
32 | tokensForSale : tokenFundAmount,
33 | isTokenSwapAtomic : false,
34 | individualMaximumAmount : tokenFundAmount,
35 | startDate : moment().add(5, 'minutes'),
36 | endDate : moment().add(10, 'minutes'),
37 | hasWhitelisting : false,
38 | isETHTrade : true,
39 | vestingTime: 2,
40 | firstUnlock: 20
41 | });
42 | contractAddress = swapContract.getAddress();
43 | expect(res).to.not.equal(false);
44 | }));
45 |
46 | it('should get a Fixed Swap Contract From contractAddress', mochaAsync(async () => {
47 |
48 | /* Get Contract */
49 | swapContract = await app.getFixedSwapContract({contractAddress});
50 | swapContract.__init__();
51 | await swapContract.assertERC20Info();
52 | expect(swapContract).to.not.equal(false);
53 | }));
54 |
55 | it('should fund a Swap Contract and confirm balances', mochaAsync(async () => {
56 | /* Approve ERC20 Fund */
57 | let res = await swapContract.approveFundERC20({tokenAmount : tokenFundAmount});
58 | expect(res).to.not.equal(false);
59 | res = await swapContract.isApproved({address : app.account.getAddress(), tokenAmount : tokenFundAmount});
60 | expect(res).to.equal(true);
61 | /* Fund */
62 | res = await swapContract.hasStarted();
63 | expect(res).to.equal(false);
64 | res = await swapContract.fund({tokenAmount : tokenFundAmount});
65 | expect(res).to.not.equal(false);
66 | }));
67 |
68 | it('should do a non atomic swap on the Contract', mochaAsync(async () => {
69 | await delay(5*60*1000);
70 | let res = await swapContract.swap({tokenAmount : tokenPurchaseAmount});
71 | expect(res).to.not.equal(false);
72 | }));
73 |
74 | it('GET - Purchases', mochaAsync(async () => {
75 | let purchases = await swapContract.getPurchaseIds();
76 | expect(purchases.length).to.equal(1);
77 | }));
78 |
79 |
80 | it('GET - My Purchases', mochaAsync(async () => {
81 | let purchases = await swapContract.getAddressPurchaseIds({address : app.account.getAddress()});
82 | expect(purchases.length).to.equal(1);
83 | }));
84 |
85 | it('GET - Purchase ID', mochaAsync(async () => {
86 | let purchases = await swapContract.getAddressPurchaseIds({address : app.account.getAddress()});
87 | let purchase = await swapContract.getPurchase({purchase_id : purchases[0]});
88 | const amountPurchase = Number(purchase.amount).noExponents();
89 | expect(Number(amountPurchase).toFixed(2)).to.equal(Number(tokenPurchaseAmount).noExponents());
90 | expect(purchase.purchaser).to.equal(app.account.getAddress());
91 | expect(purchase.wasFinalized).to.equal(false);
92 | expect(purchase.reverted).to.equal(false);
93 | console.log(purchase)
94 | }));
95 |
96 | it('GET - Fixed Swap is Closed', mochaAsync(async () => {
97 | await delay(5*60*1000);
98 | let res = await swapContract.hasFinalized();
99 | expect(res).to.equal(true);
100 | res = await swapContract.isOpen();
101 | expect(res).to.equal(false);
102 | }));
103 |
104 | it('Should Redeem Tokens - First time', mochaAsync(async () => {
105 | let purchases = await swapContract.getAddressPurchaseIds({address : app.account.getAddress()});
106 | let purchase = await swapContract.getPurchase({purchase_id : purchases[0]});
107 | let redeemTokens = await swapContract.redeemTokens({purchase_id : purchase._id});
108 | expect(redeemTokens.from).to.equal(app.account.getAddress());
109 | expect(redeemTokens.status).to.equal(true);
110 | }));
111 |
112 | it('GET - Distribution Info', mochaAsync(async () => {
113 | let info = await swapContract.getDistributionInformation();
114 | expect(Number(info.vestingTime).noExponents()).to.equal(Number(2).noExponents());
115 | expect(info.vestingSchedule).to.deep.equal([20,80]);
116 | }));
117 |
118 | it('Shouldnt Redeem Tokens - Second time', mochaAsync(async () => {
119 | let purchases = await swapContract.getAddressPurchaseIds({address : app.account.getAddress()});
120 | let purchase = await swapContract.getPurchase({purchase_id : purchases[0]});
121 | let redeemTokens = await swapContract.redeemTokens({purchase_id : purchase._id});
122 | expect(redeemTokens).toThrow();
123 | expect(redeemTokens.from).to.equal(app.account.getAddress());
124 | expect(redeemTokens.status).to.equal(false);
125 | }));
126 |
127 | it('GET - Purchase ID After Redeem', mochaAsync(async () => {
128 | let purchases = await swapContract.getAddressPurchaseIds({address : app.account.getAddress()});
129 | let purchase = await swapContract.getPurchase({purchase_id : purchases[0]});
130 | const amountPurchase = Number(purchase.amount).noExponents();
131 | expect(Number(amountPurchase).toFixed(2)).to.equal(Number(tokenPurchaseAmount).noExponents());
132 | expect(purchase.purchaser).to.equal(app.account.getAddress());
133 | expect(purchase.wasFinalized).to.equal(false);
134 | expect(purchase.reverted).to.equal(false);
135 | }));
136 | });
137 |
--------------------------------------------------------------------------------
/src/utils/Signer.js:
--------------------------------------------------------------------------------
1 | import * as ethers from 'ethers';
2 | import Numbers from "./Numbers";
3 |
4 | /**
5 | * @typedef Signer
6 | * @type {object}
7 | * @property {Function} signMessage - Signs a message
8 | */
9 |
10 | /**
11 | * @typedef SignedAddress
12 | * @type {object}
13 | * @property {string} address - Address.
14 | * @property {string} allocation - Max Allocation.
15 | * @property {string} signature - Signed Address
16 | */
17 |
18 |
19 | /**
20 | * Signer object
21 | * @constructor Signer
22 | */
23 | class Signer {
24 |
25 | /**
26 | * @function generateSignerAccount
27 | * @description Generates a new private key for signing the whitelist addresses
28 | * @param {string} password Password for encryption
29 | * @param {string=} entropy Add more entropy
30 | * @returns {string} JSON Account
31 | */
32 | async generateSignerAccount({password, entropy}) {
33 | const wallet = ethers.Wallet.createRandom(entropy)
34 |
35 | return await wallet.encrypt(password);
36 | }
37 |
38 | /**
39 | * @function getAddressFromAccount
40 | * @description Recovers an account given a json file
41 | * @param {string} accountJson Account in a json format
42 | * @param {string} password Password to unlock the account
43 | * @returns {string} Address
44 | */
45 | getAddressFromAccount({accountJson, password}) {
46 | const signer = ethers.Wallet.fromEncryptedJsonSync(
47 | accountJson,
48 | password
49 | );
50 | return signer.address;
51 | }
52 |
53 | /**
54 | * @function signAddresses
55 | * @description Signs an array of addresses. Will ignore malformed addresses.
56 | * @param {string[]} addresses List of addresses to sign
57 | * @param {string} accountJson Account in a json format
58 | * @param {number[]} accountMaxAllocations List of mac allocations in wei
59 | * @param {number} decimals Decimals for the max allocation
60 | * @param {string} contractAddress Pool
61 | * @param {string} password Password to unlock the account
62 | * @returns {SignedAddress[]} signedAddresses
63 | */
64 | async signAddresses({addresses, accountJson, password, accountMaxAllocations, contractAddress, decimals}) {
65 | const signer = ethers.Wallet.fromEncryptedJsonSync(
66 | accountJson,
67 | password
68 | );
69 | return await this.signAddressesWithSigner({addresses, accountMaxAllocations, contractAddress, decimals, signer});
70 | }
71 |
72 | /**
73 | * @function signAddressesWithSigner
74 | * @description Signs an array of addresses. Will ignore malformed addresses.
75 | * @param {string[]} addresses List of addresses to sign
76 | * @param {number[]} accountMaxAllocations List of mac allocations in wei
77 | * @param {number} decimals Decimals for the max allocation
78 | * @param {string} contractAddress Pool
79 | * @param {Signer} signer Signer object
80 | * @returns {SignedAddress[]} signedAddresses
81 | */
82 | async signAddressesWithSigner({addresses, accountMaxAllocations, contractAddress, decimals, signer}) {
83 | const signedAddresses = [];
84 | let n = 0;
85 | let r = 0;
86 | let index = 0;
87 | for (const addr of addresses) {
88 | const allocation = Numbers.toSmartContractDecimals(
89 | accountMaxAllocations[index],
90 | decimals
91 | );
92 | const result = await this._trySignAddress(signer, addr, allocation, contractAddress);
93 | if (result) {
94 | signedAddresses.push({
95 | address: addr,
96 | signature: result,
97 | allocation: allocation,
98 | });
99 | n++;
100 | } else {
101 | r++;
102 | }
103 | index++;
104 | }
105 | console.info(n, "lines successfully processed");
106 | console.info(r, "lines rejected");
107 | return signedAddresses;
108 | }
109 |
110 | /**
111 | * @function signMessage
112 | * @description Signs a message given an account
113 | * @param {Signer} signer Signer
114 | * @param {string} message String to sign
115 | * @returns {string} signedString
116 | */
117 | async signMessage({signer, message}) {
118 | return await signer.signMessage(message);
119 | }
120 |
121 | /**
122 | * @function verifySignature
123 | * @description Verifies if an address has been signed with the signer address
124 | * @param {string} signature Signature
125 | * @param {string} address Address signed
126 | * @param {string} contractAddress Pool contract address
127 | * @param {string} accountMaxAllocation Max allocation
128 | * @param {string} signerAddress Address who signed the message
129 | * @returns {boolean} verified
130 | */
131 | async verifySignature({signature, address, accountMaxAllocation, contractAddress, signerAddress}) {
132 | try {
133 | const actualAddress = ethers.utils.verifyMessage(this._addressToBytes32(address, accountMaxAllocation, contractAddress), signature);
134 | return signerAddress.toLowerCase() === actualAddress.toLowerCase();
135 | } catch (e) {
136 | return false;
137 | }
138 | }
139 |
140 | /**
141 | * @function signAddress
142 | * @description Signs a address given an account
143 | * @param {Signer} signer Signer object
144 | * @param {string} address Address to sign
145 | * @param {string} contractAddress Pool contract address
146 | * @param {string} accountMaxAllocation Max allocation
147 | * @returns {string} signedString
148 | */
149 | async signAddress({signer, address, accountMaxAllocation, contractAddress}) {
150 | return await this.signMessage({signer, message: this._addressToBytes32(address, accountMaxAllocation, contractAddress)});
151 | }
152 |
153 | async _trySignAddress(signer, address, accountMaxAllocation, contractAddress) {
154 | if (ethers.utils.isAddress(address) && ethers.BigNumber.from(address) != 0) {
155 | return await this.signAddress({signer, address, accountMaxAllocation, contractAddress});
156 | } else {
157 | console.error("address not valid - ignored :", address);
158 | return "";
159 | }
160 | }
161 |
162 |
163 | _addressToBytes32(address, accountMaxAllocation, contractAddress) {
164 | const messageHash = ethers.utils.solidityKeccak256(
165 | ["address", "uint256", "address"],
166 | [address, accountMaxAllocation, contractAddress],
167 | );
168 |
169 | return ethers.utils.arrayify(messageHash);
170 | }
171 | }
172 |
173 | export default Signer;
--------------------------------------------------------------------------------
/docs/SIGNER.md:
--------------------------------------------------------------------------------
1 | ## Classes
2 |
3 | stringGenerates a new private key for signing the whitelist addresses
13 |stringRecovers an account given a json file
16 |Array.<SignedAddress>Signs an array of addresses. Will ignore malformed addresses.
19 |Array.<SignedAddress>Signs an array of addresses. Will ignore malformed addresses.
22 |stringSigns a message given an account
25 |booleanVerifies if an address has been signed with the signer address
28 |stringSigns a address given an account
31 |objectobjectstring
55 | Generates a new private key for signing the whitelist addresses
56 |
57 | **Kind**: global function
58 | **Returns**: string - JSON Account
59 |
60 | | Param | Type | Description |
61 | | --- | --- | --- |
62 | | password | string | Password for encryption |
63 | | [entropy] | string | Add more entropy |
64 |
65 |
66 |
67 | ## getAddressFromAccount(accountJson, password) ⇒ string
68 | Recovers an account given a json file
69 |
70 | **Kind**: global function
71 | **Returns**: string - Address
72 |
73 | | Param | Type | Description |
74 | | --- | --- | --- |
75 | | accountJson | string | Account in a json format |
76 | | password | string | Password to unlock the account |
77 |
78 |
79 |
80 | ## signAddresses(addresses, accountJson, accountMaxAllocations, decimals, contractAddress, password) ⇒ [Array.<SignedAddress>](#SignedAddress)
81 | Signs an array of addresses. Will ignore malformed addresses.
82 |
83 | **Kind**: global function
84 | **Returns**: [Array.<SignedAddress>](#SignedAddress) - signedAddresses
85 |
86 | | Param | Type | Description |
87 | | --- | --- | --- |
88 | | addresses | Array.<string> | List of addresses to sign |
89 | | accountJson | string | Account in a json format |
90 | | accountMaxAllocations | Array.<number> | List of mac allocations in wei |
91 | | decimals | number | Decimals for the max allocation |
92 | | contractAddress | string | Pool |
93 | | password | string | Password to unlock the account |
94 |
95 |
96 |
97 | ## signAddressesWithSigner(addresses, accountMaxAllocations, decimals, contractAddress, signer) ⇒ [Array.<SignedAddress>](#SignedAddress)
98 | Signs an array of addresses. Will ignore malformed addresses.
99 |
100 | **Kind**: global function
101 | **Returns**: [Array.<SignedAddress>](#SignedAddress) - signedAddresses
102 |
103 | | Param | Type | Description |
104 | | --- | --- | --- |
105 | | addresses | Array.<string> | List of addresses to sign |
106 | | accountMaxAllocations | Array.<number> | List of mac allocations in wei |
107 | | decimals | number | Decimals for the max allocation |
108 | | contractAddress | string | Pool |
109 | | signer | [Signer](#Signer) | Signer object |
110 |
111 |
112 |
113 | ## signMessage(signer, message) ⇒ string
114 | Signs a message given an account
115 |
116 | **Kind**: global function
117 | **Returns**: string - signedString
118 |
119 | | Param | Type | Description |
120 | | --- | --- | --- |
121 | | signer | [Signer](#Signer) | Signer |
122 | | message | string | String to sign |
123 |
124 |
125 |
126 | ## verifySignature(signature, address, contractAddress, accountMaxAllocation, signerAddress) ⇒ boolean
127 | Verifies if an address has been signed with the signer address
128 |
129 | **Kind**: global function
130 | **Returns**: boolean - verified
131 |
132 | | Param | Type | Description |
133 | | --- | --- | --- |
134 | | signature | string | Signature |
135 | | address | string | Address signed |
136 | | contractAddress | string | Pool contract address |
137 | | accountMaxAllocation | string | Max allocation |
138 | | signerAddress | string | Address who signed the message |
139 |
140 |
141 |
142 | ## signAddress(signer, address, contractAddress, accountMaxAllocation) ⇒ string
143 | Signs a address given an account
144 |
145 | **Kind**: global function
146 | **Returns**: string - signedString
147 |
148 | | Param | Type | Description |
149 | | --- | --- | --- |
150 | | signer | [Signer](#Signer) | Signer object |
151 | | address | string | Address to sign |
152 | | contractAddress | string | Pool contract address |
153 | | accountMaxAllocation | string | Max allocation |
154 |
155 |
156 |
157 | ## Signer : object
158 | **Kind**: global typedef
159 | **Properties**
160 |
161 | | Name | Type | Description |
162 | | --- | --- | --- |
163 | | signMessage | function | Signs a message |
164 |
165 |
166 |
167 | ### new Signer()
168 | Signer object
169 |
170 |
171 |
172 | ## SignedAddress : object
173 | **Kind**: global typedef
174 | **Properties**
175 |
176 | | Name | Type | Description |
177 | | --- | --- | --- |
178 | | address | string | Address. |
179 | | allocation | string | Max Allocation. |
180 | | signature | string | Signed Address |
181 |
182 |
--------------------------------------------------------------------------------
/src/models/base/Staking.js:
--------------------------------------------------------------------------------
1 | import Contract from "./Contract";
2 | import { staking } from "../../interfaces";
3 | import Numbers from "../../utils/Numbers";
4 | import ERC20TokenContract from "./ERC20TokenContract";
5 | import Client from "../../utils/Client";
6 | import Addresses from "./Addresses";
7 | import Chains from "../../utils/Chains";
8 |
9 | /**
10 | * Staking Object
11 | * @constructor Staking
12 | * @param {Web3} web3
13 | * @param {string=} contractAddress The staking contract address. (Default: Predefined addresses depending on the network)
14 | * @param {Account} acc
15 | * @param {string=} tokenAddress The staking token address. (Default: Predefined addresses depending on the network)
16 | * @param {(ETH|BSC|MATIC|DOT)=} network The network where the staking contract is. (Default: ETH)
17 | * @param {Boolean=} test ? Specifies if we're on test env (Default: false)
18 | */
19 | class Staking {
20 |
21 | stakingAddresses = {
22 | 'BSC': '0xD558675a8c8E1fd45002010BaC970B115163dE3a',
23 | 'ETH': '0xc24A365A870821EB83Fd216c9596eDD89479d8d7'
24 | };
25 | stakingTestAddresses = {
26 | 'BSC': '0x1621AEC5D5B2e6eC6D9B58399E9D5253AF86DF5f',
27 | 'ETH': '0xa297c295aFcac59c749e25A02811a02B2f7D3Ab5'
28 | };
29 |
30 | constructor({
31 | web3,
32 | contractAddress,
33 | acc,
34 | tokenAddress,
35 | network = 'ETH',
36 | test = false
37 | }) {
38 | if (!web3) {
39 | throw new Error("Please provide a valid web3 provider");
40 | }
41 |
42 | Chains.checkIfNetworkIsSupported(network);
43 | this.web3 = web3;
44 | this.version = "2.0";
45 | if (acc) {
46 | this.acc = acc;
47 | }
48 |
49 | if (!contractAddress) {
50 | let stakingAddresses = this.stakingAddresses;
51 | if (test) {
52 | stakingAddresses = this.stakingTestAddresses;
53 | }
54 | contractAddress = stakingAddresses[network];
55 | if (!contractAddress) {
56 | throw new Error('Staking not available on the network ' + network);
57 | }
58 | }
59 |
60 | this.params = {
61 | web3: web3,
62 | contractAddress: contractAddress,
63 | contract: new Contract(web3, staking, contractAddress),
64 | };
65 |
66 | if (!tokenAddress) {
67 | let tokenAddresses = Addresses.tokenAddresses;
68 | if (test) {
69 | tokenAddresses = Addresses.tokenTestAddresses;
70 | }
71 | tokenAddress = tokenAddresses[network];
72 | if (!tokenAddress) {
73 | throw new Error('Token not available on the network ' + network);
74 | }
75 | }
76 |
77 | this.params.erc20TokenContract = new ERC20TokenContract({
78 | web3: web3,
79 | contractAddress: tokenAddress,
80 | acc
81 | });
82 | this.client = new Client();
83 | }
84 |
85 | /**
86 | * @function stake
87 | * @description Stakes tokens inside the stake contract
88 | * @param {Integer} amount Amount
89 | */
90 | stake = async ({ amount }) => {
91 | amount = Numbers.toSmartContractDecimals(
92 | amount,
93 | await this.getDecimals()
94 | )
95 | try {
96 | return await this.client.sendTx(
97 | this.params.web3,
98 | this.acc,
99 | this.params.contract,
100 | this.params.contract
101 | .getContract()
102 | .methods.stake(amount)
103 | );
104 | } catch (err) {
105 | throw err;
106 | }
107 | };
108 |
109 | /**
110 | * @function approveStakeERC20
111 | * @param {Integer} tokenAmount
112 | * @description Approve the stake to use approved tokens
113 | */
114 | approveStakeERC20 = async ({ tokenAmount, callback }) => {
115 | return await this.getTokenContract().approve({
116 | address: this.params.contractAddress,
117 | amount: tokenAmount,
118 | callback
119 | });
120 | };
121 |
122 | /**
123 | * @function isApproved
124 | * @description Verify if the address has approved the staking to deposit
125 | * @param {Integer} tokenAmount
126 | * @param {Address} address
127 | * @returns {Boolean}
128 | */
129 | isApproved = async ({ tokenAmount, address }) => {
130 | return await this.getTokenContract().isApproved({
131 | address: address,
132 | amount: tokenAmount,
133 | spenderAddress: this.params.contractAddress
134 | });
135 | };
136 |
137 | /**
138 | * @function withdraw
139 | * @param {Integer} amount
140 | * @description Withdraw tokens from the stake contract
141 | */
142 | withdraw = async ({amount}) => {
143 |
144 | amount = Numbers.toSmartContractDecimals(
145 | amount,
146 | await this.getDecimals()
147 | )
148 | try {
149 | return await this.client.sendTx(
150 | this.params.web3,
151 | this.acc,
152 | this.params.contract,
153 | this.params.contract
154 | .getContract()
155 | .methods.withdraw(amount)
156 | );
157 | } catch (err) {
158 | throw err;
159 | }
160 | };
161 |
162 | /**
163 | * @function withdrawAll
164 | * @description Withdraw all the tokens from the stake contract
165 | */
166 | withdrawAll = async () => {
167 | try {
168 | return await this.client.sendTx(
169 | this.params.web3,
170 | this.acc,
171 | this.params.contract,
172 | this.params.contract
173 | .getContract()
174 | .methods.withdrawAll()
175 | );
176 | } catch (err) {
177 | throw err;
178 | }
179 | };
180 |
181 | /**
182 | * @function claim
183 | * @description Claim rewards from the staking contract
184 | */
185 | claim = async () => {
186 | try {
187 | return await this.client.sendTx(
188 | this.params.web3,
189 | this.acc,
190 | this.params.contract,
191 | this.params.contract
192 | .getContract()
193 | .methods.claim()
194 | );
195 | } catch (err) {
196 | throw err;
197 | }
198 | };
199 |
200 | /**
201 | * @function userAccumulatedRewards
202 | * @description Returns the accumulated rewards
203 | * @param {string} address
204 | * @returns {Integer} userAccumulatedRewards
205 | */
206 | userAccumulatedRewards = async ({address}) => {
207 | return await this.params.contract.getContract().methods.userAccumulatedRewards(address).call();
208 | }
209 |
210 | /**
211 | * @function stakeTime
212 | * @description Returns the stake time for a wallet
213 | * @param {string} address
214 | * @returns {Integer} stakeTime
215 | */
216 | stakeTime = async ({address}) => {
217 | return await this.params.contract.getContract().methods.stakeTime(address).call();
218 | }
219 |
220 | /**
221 | * @function lockTimePeriod
222 | * @description Returns the lock time perdio
223 | * @returns {Integer} lockTimePeriod
224 | */
225 | getLockTimePeriod = async () => {
226 | return await this.params.contract.getContract().methods.lockTimePeriod().call();
227 | }
228 |
229 | /**
230 | * @function getUnlockTime
231 | * @description Returns the stake time for a wallet
232 | * @param {string} address
233 | * @returns {Integer} unlockTime
234 | */
235 | getUnlockTime = async ({address}) => {
236 | return await this.params.contract.getContract().methods.getUnlockTime(address).call();
237 | }
238 |
239 | /**
240 | * @function stakeAmount
241 | * @description Returns the stake amount for a wallet
242 | * @param {string} address
243 | * @returns {Integer} stakeAmount
244 | */
245 | stakeAmount = async ({address}) => {
246 | return Numbers.fromDecimals(
247 | await this.params.contract.getContract().methods.stakeAmount(address).call(),
248 | await this.getDecimals()
249 | );
250 | }
251 |
252 | getDecimals = async () => {
253 | return 18;
254 | }
255 |
256 | getTokenContract() {
257 | return this.params.erc20TokenContract;
258 | }
259 | }
260 |
261 | export default Staking;
262 |
--------------------------------------------------------------------------------
/src/models/index.js:
--------------------------------------------------------------------------------
1 | import Web3 from "web3";
2 | import FixedSwapContract from "./contracts/FixedSwapContract";
3 | import Signer from "../utils/Signer";
4 | import Network from "../utils/Network";
5 | import Wallet from "../utils/Wallet";
6 | import Account from './base/Account';
7 | import ERC20TokenContract from "./base/ERC20TokenContract";
8 | import FixedNFTSwapContract from "./contracts/FixedNFTSwapContract";
9 | import Staking from "./base/Staking";
10 | import FixedSwapContractLegacy from "./contracts/legacy/FixedSwapContractLegacy";
11 | import Chains from "../utils/Chains";
12 |
13 | const TEST_PRIVATE_KEY =
14 | "0x7f76de05082c4d578219ca35a905f8debe922f1f00b99315ebf0706afc97f132";
15 |
16 | /**
17 | * Polkastarter Application Object
18 | * @constructor Application
19 | * @param {(ETH|BSC|MATIC|DOT)=} network Current network (Default = ETH)
20 | * @param {Boolean=} mainnet Specifies if we're on mainnet or tesnet (Default = true);
21 | * @param {Boolean=} test ? Specifies if we're on test env
22 | * @param {Web3=} web3 Custom Web3 instance. If not provided the Application will instance it for you. (Default: undefined)
23 | */
24 | class Application {
25 | constructor({test=false, mainnet=true, network='ETH', web3=undefined}) {
26 | this.test = test;
27 | global.IS_TEST = !mainnet;
28 | this.mainnet = mainnet;
29 | Chains.checkIfNetworkIsSupported(network);
30 | this.network = network;
31 |
32 | if(this.test){
33 | if (!web3) {
34 | this.start();
35 | } else {
36 | this.web3 = web3;
37 | }
38 | // this.login();
39 | this.account = new Account(this.web3, this.web3.eth.accounts.privateKeyToAccount(TEST_PRIVATE_KEY));
40 | }
41 | }
42 |
43 | /**
44 | * @function startWithoutMetamask
45 | * @description Starts an instance of web3 for read-only methods
46 | */
47 | startWithoutMetamask = () => {
48 | const rpc = Chains.getRpcUrl(this.network, this.mainnet);
49 | if (rpc) {
50 | this.web3 = new Web3(rpc);
51 | }
52 | }
53 |
54 | /**
55 | * @function start
56 | * @description Starts an instance of web3
57 | */
58 | start = () => {
59 | const rpc = Chains.getRpcUrl(this.network, this.mainnet);
60 | if (rpc) {
61 | this.web3 = new Web3(rpc);
62 | }
63 |
64 | if((typeof window !== "undefined") && window.ethereum) {
65 | window.web3 = new Web3(window.ethereum);
66 | this.web3 = window.web3;
67 | }
68 | }
69 |
70 |
71 | /**
72 | * @function login
73 | * @description Logins with metamask
74 | */
75 | login = async () => {
76 | try{
77 | console.log("Login being done")
78 | if (typeof window === "undefined") { return false; }
79 | if (window.ethereum) {
80 | window.web3 = new Web3(window.ethereum);
81 | this.web3 = window.web3;
82 | await window.ethereum.enable();
83 | return true;
84 | }
85 | return false;
86 | }catch(err){
87 | throw err;
88 | }
89 | };
90 |
91 |
92 | __getUserAccount = ({privateKey}) => {
93 | return new Account(this.web3, this.web3.eth.accounts.privateKeyToAccount(privateKey));
94 | }
95 |
96 | /**
97 | * @function getSigner
98 | * @description Returns the Signer instance.
99 | */
100 | getSigner = () => {
101 | return new Signer();
102 | }
103 |
104 | /**
105 | * @function getNetworkUtils
106 | * @description Returns the Network Utils instance.
107 | */
108 | getNetworkUtils = () => {
109 | return new Network(this.network, !this.mainnet, this.getETHNetwork);
110 | }
111 |
112 | /**
113 | * @function getWalletUtils
114 | * @description Returns the Wallet Utils instance.
115 | */
116 | getWalletUtils = () => {
117 | return new Wallet(this.network, !this.mainnet);
118 | }
119 |
120 | /**
121 | * @function getStaking
122 | * @param {string=} contractAddress The staking contract address. (Default: Predefined addresses depending on the network)
123 | * @param {string=} tokenAddress The staking token address. (Default: Predefined addresses depending on the network)
124 | * @description Returns the Staking Model instance.
125 | */
126 | getStaking = ({contractAddress=null, tokenAddress=null}) => {
127 | return new Staking({
128 | web3: this.web3,
129 | acc : this.test ? this.account : null,
130 | contractAddress: contractAddress,
131 | tokenAddress: tokenAddress,
132 | network: this.network,
133 | test: !this.mainnet
134 | });
135 | }
136 |
137 | /**
138 | * @function getFixedSwapContract
139 | * @param {string} tokenAddress The token address we want to trade
140 | * @param {string=} contractAddress The swap contract address, in case t hat has already been instanced. (Default = null)
141 | * @description Returns Fixed Swap instance
142 | */
143 | getFixedSwapContract = async ({tokenAddress, contractAddress=null}) => {
144 | let contract;
145 | if(!contractAddress){
146 | // Not deployed
147 | return new FixedSwapContract({
148 | web3: this.web3,
149 | tokenAddress: tokenAddress,
150 | contractAddress: contractAddress,
151 | acc : this.test ? this.account : null
152 | });
153 | }else{
154 | // Deployed
155 | try{
156 | contract = new FixedSwapContract({
157 | web3: this.web3,
158 | tokenAddress: tokenAddress,
159 | contractAddress: contractAddress,
160 | acc : this.test ? this.account : null
161 | });
162 | await contract.isETHTrade();
163 | }catch(err){
164 | try{
165 | contract = new FixedSwapContractLegacy({
166 | web3: this.web3,
167 | tokenAddress: tokenAddress,
168 | contractAddress: contractAddress,
169 | acc : this.test ? this.account : null
170 | });
171 | }catch(err){
172 | throw err;
173 |
174 | }
175 | }
176 |
177 | return contract;
178 | }
179 | };
180 |
181 | /**
182 | * @function getFixedNFTSwapContract
183 | * @param {string=} contractAddress The swap contract address, in case t hat has already been instanced. (Default = null)
184 | * @description Returns Fixed NFT Swap instance
185 | */
186 | getFixedNFTSwapContract = async ({contractAddress=null}) => {
187 | let contract;
188 | if(!contractAddress){
189 | // Not deployed
190 | return new FixedNFTSwapContract({
191 | web3: this.web3,
192 | contractAddress: contractAddress,
193 | acc : this.test ? this.account : null
194 | });
195 | }else{
196 | // Deployed
197 | try{
198 | contract = new FixedNFTSwapContract({
199 | web3: this.web3,
200 | contractAddress: contractAddress,
201 | acc : this.test ? this.account : null
202 | });
203 | await contract.isETHTrade();
204 | }catch(err){
205 | throw err;
206 | }
207 |
208 | return contract;
209 | }
210 | };
211 |
212 | /**
213 | * @function getERC20TokenContract
214 | * @param {string} tokenAddress The token address
215 | * @description Returns ERC20 instance
216 | */
217 | getERC20TokenContract = ({tokenAddress}) => {
218 | try{
219 | return new ERC20TokenContract({
220 | web3: this.web3,
221 | contractAddress: tokenAddress,
222 | acc : this.test ? this.account : null
223 | });
224 | }catch(err){
225 | throw err;
226 | }
227 | };
228 |
229 | /**
230 | * @function getETHNetwork
231 | * @description Returns the current network
232 | */
233 | getETHNetwork = async () => {
234 | const netId = await this.web3.eth.net.getId();
235 | const networksEnum = Chains.getNetworksEnum();
236 | const networkName = networksEnum.hasOwnProperty(netId)
237 | ? networksEnum[netId]
238 | : "Unknown";
239 | return networkName;
240 | };
241 |
242 | /**
243 | * @function getAddress
244 | * @description Returns the connected user address
245 | */
246 | getAddress = async () => {
247 | const accounts = await this.web3.eth.getAccounts();
248 | return accounts[0];
249 | };
250 |
251 |
252 | /**
253 | * @function getETHBalance
254 | * @description Returns the native currency of the connected user wallet.
255 | */
256 | getETHBalance = async () => {
257 | let wei = await this.web3.eth.getBalance(await this.getAddress());
258 | return this.web3.utils.fromWei(wei, "ether");
259 | };
260 | }
261 |
262 | export default Application;
263 |
--------------------------------------------------------------------------------
/docs/IDOSTAKING.md:
--------------------------------------------------------------------------------
1 | ## Classes
2 |
3 | stringDeploys the IDO Staking contracts
13 |Stakes tokens inside the stake contract
16 |Approve the stake to use approved tokens
19 |BooleanVerify if the address has approved the staking to deposit
22 |IntegerReturns the APY that this pool is giving
25 |Withdraw tokens from the stake contract
28 |Withdraw all the tokens from the stake contract
31 |Claims all the rewards and withdraws all the staked tokens
34 |Claim rewards from the staking contract
37 |add (more) rewards token to current/future period
40 |Transfer and add (more) rewards token to current/future period
43 |IntegerReturns the accumulated rewards
46 |Emergency withdrawal of tokens
49 |DateGet the last time rewards are applicable
52 |IntegerReturns the total stake
55 |Integersubstract staked amount if staked token is the same as rewards token
58 |IntegerReturns the stake amount for a wallet
61 |Sets the token sale address
64 |Web3 | |
80 | | contractAddress | string | The staking contract address. |
81 | | acc | Account | |
82 |
83 |
84 |
85 | ## deploy(owner, rewardsDistribution, rewardsToken, stakingToken, rewardsDuration, tokenSaleAddress) ⇒ string
86 | Deploys the IDO Staking contracts
87 |
88 | **Kind**: global function
89 | **Returns**: string - address The deployed contract address
90 |
91 | | Param | Type | Description |
92 | | --- | --- | --- |
93 | | owner | string | Address of the owner |
94 | | rewardsDistribution | string | Address of the distributor |
95 | | rewardsToken | string | Address of the token we want to reward |
96 | | stakingToken | string | Address of the token to be staked |
97 | | rewardsDuration | Integer | Duration of the rewards |
98 | | tokenSaleAddress | string | Address of the pool |
99 |
100 |
101 |
102 | ## stake(amount)
103 | Stakes tokens inside the stake contract
104 |
105 | **Kind**: global function
106 |
107 | | Param | Type | Description |
108 | | --- | --- | --- |
109 | | amount | Integer | Amount |
110 |
111 |
112 |
113 | ## approveStakeERC20(tokenAmount)
114 | Approve the stake to use approved tokens
115 |
116 | **Kind**: global function
117 |
118 | | Param | Type |
119 | | --- | --- |
120 | | tokenAmount | Integer |
121 |
122 |
123 |
124 | ## isApproved(tokenAmount, address) ⇒ Boolean
125 | Verify if the address has approved the staking to deposit
126 |
127 | **Kind**: global function
128 |
129 | | Param | Type |
130 | | --- | --- |
131 | | tokenAmount | Integer |
132 | | address | Address |
133 |
134 |
135 |
136 | ## getAPY() ⇒ Integer
137 | Returns the APY that this pool is giving
138 |
139 | **Kind**: global function
140 |
141 |
142 | ## withdraw(amount)
143 | Withdraw tokens from the stake contract
144 |
145 | **Kind**: global function
146 |
147 | | Param | Type |
148 | | --- | --- |
149 | | amount | Integer |
150 |
151 |
152 |
153 | ## withdrawAll()
154 | Withdraw all the tokens from the stake contract
155 |
156 | **Kind**: global function
157 |
158 |
159 | ## exit()
160 | Claims all the rewards and withdraws all the staked tokens
161 |
162 | **Kind**: global function
163 |
164 |
165 | ## claim()
166 | Claim rewards from the staking contract
167 |
168 | **Kind**: global function
169 |
170 |
171 | ## notifyRewardAmountSamePeriod(amount)
172 | add (more) rewards token to current/future period
173 |
174 | **Kind**: global function
175 |
176 | | Param | Type |
177 | | --- | --- |
178 | | amount | Integer |
179 |
180 |
181 |
182 | ## transferRewardTokenSamePeriod(amount)
183 | Transfer and add (more) rewards token to current/future period
184 |
185 | **Kind**: global function
186 |
187 | | Param | Type |
188 | | --- | --- |
189 | | amount | Integer |
190 |
191 |
192 |
193 | ## userAccumulatedRewards(address) ⇒ Integer
194 | Returns the accumulated rewards
195 |
196 | **Kind**: global function
197 | **Returns**: Integer - userAccumulatedRewards
198 |
199 | | Param | Type |
200 | | --- | --- |
201 | | address | string |
202 |
203 |
204 |
205 | ## recoverERC20(address)
206 | Emergency withdrawal of tokens
207 |
208 | **Kind**: global function
209 |
210 | | Param | Type | Description |
211 | | --- | --- | --- |
212 | | address | string | Token address |
213 |
214 |
215 |
216 | ## lastTimeRewardApplicable() ⇒ Date
217 | Get the last time rewards are applicable
218 |
219 | **Kind**: global function
220 |
221 |
222 | ## totalStaked() ⇒ Integer
223 | Returns the total stake
224 |
225 | **Kind**: global function
226 | **Returns**: Integer - totalStakeAmount
227 |
228 |
229 | ## balanceRewardsToken() ⇒ Integer
230 | substract staked amount if staked token is the same as rewards token
231 |
232 | **Kind**: global function
233 | **Returns**: Integer - totalRewardsAmount
234 |
235 |
236 | ## stakeAmount(address) ⇒ Integer
237 | Returns the stake amount for a wallet
238 |
239 | **Kind**: global function
240 | **Returns**: Integer - stakeAmount
241 |
242 | | Param | Type |
243 | | --- | --- |
244 | | address | string |
245 |
246 |
247 |
248 | ## setTokenSaleAddress(address)
249 | Sets the token sale address
250 |
251 | **Kind**: global function
252 |
253 | | Param | Type |
254 | | --- | --- |
255 | | address | string |
256 |
257 |
--------------------------------------------------------------------------------
/tests/test/erc20.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 |
3 | import chai from 'chai';
4 | import { mochaAsync } from '../utils';
5 | import moment, { isDate } from 'moment';
6 | import Application from '../../src/models';
7 | import delay from 'delay';
8 | const ERC20TokenAddress = '0x7a7748bd6f9bac76c2f3fcb29723227e3376cbb2';
9 | var contractAddress = '0x420751cdeb28679d8e336f2b4d1fc61df7439b5a';
10 | var userPrivateKey = process.env.TEST_PRIVATE_KEY || '0x7f76de05082c4d578219ca35a905f8debe922f1f00b99315ebf0706afc97f132';
11 |
12 | const expect = chai.expect;
13 | const tokenPurchaseAmount = 0.01;
14 | const tokenFundAmount = 0.03;
15 | const tradeValue = 0.01;
16 |
17 | context('ERC-20 Contract', async () => {
18 | var swapContract;
19 | var app;
20 | var isFunded, isSaleOpen, hasWhitelist, tokensLeft, indiviMinAmount, indivMaxAmount, cost, tokensAvailable
21 |
22 | before( async () => {
23 | app = new Application({test : true, mainnet : false});
24 | });
25 |
26 | it('should deploy Fixed Swap Contract', mochaAsync(async () => {
27 |
28 | app = new Application({test : true, mainnet : false});
29 | /* Create Contract */
30 | swapContract = await app.getFixedSwapContract({tokenAddress : ERC20TokenAddress, decimals : 18});
31 | /* Deploy */
32 | let res = await swapContract.deploy({
33 | tradeValue : tradeValue,
34 | tokensForSale : tokenFundAmount,
35 | isTokenSwapAtomic : true,
36 | individualMaximumAmount : tokenFundAmount,
37 | startDate : moment().add(4, 'minutes'),
38 | endDate : moment().add(8, 'minutes'),
39 | hasWhitelisting : false,
40 | isETHTrade : false,
41 | ERC20TradingAddress: "0x59dd38615070ac185583a9a43059aa833685d49d",
42 | isPOLSWhitelist: false,
43 | tradingDecimals: 18,
44 | vestingTime: 1,
45 | vestingSchedule: [100]
46 | });
47 | contractAddress = swapContract.getAddress();
48 | expect(res).to.not.equal(false);
49 | }));
50 |
51 | it('should get a Fixed Swap Contract From contractAddress', mochaAsync(async () => {
52 |
53 | /* Get Contract */
54 | swapContract = await app.getFixedSwapContract({contractAddress});
55 | swapContract.__init__();
56 | await swapContract.assertERC20Info();
57 | expect(swapContract).to.not.equal(false);
58 | }));
59 |
60 | it('GET - isPreFunded', mochaAsync(async () => {
61 | let res = await swapContract.isPreStart();
62 | expect(res).to.equal(true);
63 | }));
64 |
65 | it('GET - tokensAllocated', mochaAsync(async () => {
66 | let tokens = await swapContract.tokensAllocated();
67 | expect(tokens).to.equal(Number(0).noExponents());
68 | }));
69 |
70 | it('GET - tradeValue', mochaAsync(async () => {
71 | let td = await swapContract.tradeValue();
72 | expect(td).to.equal(Number(tradeValue).noExponents());
73 | }));
74 |
75 | it('GET - tokensAvailable', mochaAsync(async () => {
76 | let tokens = await swapContract.tokensAvailable();
77 | expect(tokens).to.equal(Number(0).noExponents());
78 | }));
79 |
80 | it('GET - owner', mochaAsync(async () => {
81 | let res = await swapContract.owner();
82 | expect(res).to.equal('0xe797860acFc4e06C1b2B96197a7dB1dFa518d5eB');
83 | }));
84 |
85 | it('GET - tokensForSale', mochaAsync(async () => {
86 | let tokens = await swapContract.tokensForSale();
87 | expect(Number(tokens).noExponents()).to.equal(Number(tokenFundAmount).noExponents());
88 | }));
89 |
90 | it('GET - tokensLeft', mochaAsync(async () => {
91 | let tokens = await swapContract.tokensLeft();
92 | tokensLeft = tokens;
93 | expect(Number(tokens).noExponents()).to.equal(Number(tokenFundAmount).noExponents());
94 | }));
95 |
96 | it('should fund a Swap Contract and confirm balances', mochaAsync(async () => {
97 | /* Approve ERC20 Fund */
98 | let res = await swapContract.approveFundERC20({tokenAmount : tokenFundAmount});
99 | expect(res).to.not.equal(false);
100 | res = await swapContract.isApproved({address : app.account.getAddress(), tokenAmount : tokenFundAmount});
101 | expect(res).to.equal(true);
102 | /* Fund */
103 | res = await swapContract.hasStarted();
104 | expect(res).to.equal(false);
105 | res = await swapContract.fund({tokenAmount : tokenFundAmount});
106 | expect(res).to.not.equal(false);
107 | }));
108 |
109 |
110 | it('GET - tokensAvailable', mochaAsync(async () => {
111 | let tokens = await swapContract.tokensAvailable();
112 | expect(tokens).to.equal(Number(tokenFundAmount).noExponents());
113 | }));
114 |
115 | it('GET - isFunded', mochaAsync(async () => {
116 | let res = await swapContract.isFunded();
117 | isFunded = res;
118 | expect(res).to.equal(true);
119 | }));
120 |
121 | it('GET - isSaleOpen - before Start', mochaAsync(async () => {
122 | await delay(2*60*1000);
123 | let res = await swapContract.isOpen();
124 | isSaleOpen = res;
125 | expect(res).to.equal(true);
126 | }));
127 |
128 | it('GET - tokensAvailable after fund', mochaAsync(async () => {
129 | let tokens = await swapContract.tokensAvailable();
130 | expect(tokens).to.equal(Number(tokens).noExponents());
131 | }));
132 |
133 | it('should approve ERC20 swap', mochaAsync(async () => {
134 | await delay(15*1000);
135 | let res = await swapContract.approveSwapERC20({tokenAmount : tokenPurchaseAmount});
136 | expect(res).to.not.equal(false);
137 | }));
138 |
139 | it('should do a non atomic swap on the Contract', mochaAsync(async () => {
140 | await delay(15*1000);
141 | let res = await swapContract.swap({tokenAmount : tokenPurchaseAmount});
142 | expect(res).to.not.equal(false);
143 | }));
144 |
145 | it('GET - Purchases', mochaAsync(async () => {
146 | let purchases = await swapContract.getPurchaseIds();
147 | expect(purchases.length).to.equal(1);
148 | }));
149 |
150 | it('GET - My Purchases', mochaAsync(async () => {
151 | let purchases = await swapContract.getAddressPurchaseIds({address : app.account.getAddress()});
152 | expect(purchases.length).to.equal(1);
153 | }));
154 |
155 | it('GET - Purchase ID', mochaAsync(async () => {
156 | let purchases = await swapContract.getAddressPurchaseIds({address : app.account.getAddress()});
157 | let purchase = await swapContract.getPurchase({purchase_id : purchases[0]});
158 | const amountPurchase = Number(purchase.amount).noExponents();
159 | expect(Number(amountPurchase).toFixed(2)).to.equal(Number(tokenPurchaseAmount).noExponents());
160 | expect(purchase.purchaser).to.equal(app.account.getAddress());
161 | expect(purchase.wasFinalized).to.equal(true);
162 | expect(purchase.reverted).to.equal(false);
163 | }));
164 |
165 | it('GET - tokensAvailable after Swap', mochaAsync(async () => {
166 | let tokens = await swapContract.tokensAvailable();
167 | tokens = Number(tokens).noExponents();
168 | tokensAvailable = Number(tokenFundAmount-tokenPurchaseAmount).noExponents();
169 | expect(Number(tokens).toFixed(2)).to.equal(Number(tokensAvailable).toFixed(2));
170 | }));
171 |
172 | it('GET - Buyers', mochaAsync(async () => {
173 | let buyers = await swapContract.getBuyers();
174 | expect(buyers.length).to.equal(1);
175 | }));
176 |
177 | it('GET - Fixed Swap is Closed', mochaAsync(async () => {
178 | await delay(4*60*1000);
179 | let res = await swapContract.hasFinalized();
180 | expect(res).to.equal(true);
181 | res = await swapContract.isOpen();
182 | expect(res).to.equal(false);
183 | }));
184 |
185 | it('GET - tokensAvailable after closed', mochaAsync(async () => {
186 | let res = await swapContract.tokensAvailable();
187 | res = Number(res).noExponents()
188 | expect(Number(res).toFixed(2)).to.equal(Number(tokensAvailable).toFixed(2));
189 | }));
190 |
191 | it('Remove Tokens From Purchases - Admin', mochaAsync(async () => {
192 | let res = await swapContract.withdrawFunds();
193 | expect(res).to.not.equal(false);
194 | }));
195 |
196 | it('Remove Unsold Tokens - Admin', mochaAsync(async () => {
197 | let res = await swapContract.withdrawUnsoldTokens();
198 | expect(res).to.not.equal(false);
199 | }));
200 |
201 | it('should deploy Fixed Swap Contract - isPOLSWhitelisted', mochaAsync(async () => {
202 | /*
203 | It is necessary to create in the future, as it is necessary to simulate a "uniswap"
204 | with the entire structure of the kovan network.
205 | */
206 | }));
207 | });
208 |
--------------------------------------------------------------------------------
/docs/NFT_SWAP.md:
--------------------------------------------------------------------------------
1 | ## Classes
2 |
3 | BaseSwapContractDeploy the NFT swap contract
13 |Swap tokens by Ethereum or ERC20
16 |adminModifies the distribution date for the pool
19 |DateGet Distribution Date of NFT
22 |BooleanVerify if the NFTs are up for distribution, if the current date is after distributionDate
25 |IntegerGet Total tokens for sale by category
28 |IntegerGet Total tokens for sold by category
31 |IntegerGet Total tokens owned by category
34 |IntegerGet Total cost for buying all the nfts
37 |IntegerGet Cost for category and amount
40 |Safe Pull all trading tokens
43 |Array.<Object>Integer | Integer | Integer | Integer | Address | Date | BooleanGet Purchase based on ID
48 |Array | IntegerGet Buyers
51 |Array | IntegerGet All Purchase Ids
54 |Array | IntegerGet All Purchase Ids filter by Address/Purchaser
57 |booleanadminSets user claimed category
62 |Array.<Number>adminModifies the categories oon the contract
67 |BaseSwapContract
73 | **Kind**: global class
74 | **Extends**: BaseSwapContract
75 |
76 |
77 | ### new FixedNFTSwapContract(web3, contractAddress)
78 | Fixed NFT Swap Object
79 |
80 |
81 | | Param | Type | Description |
82 | | --- | --- | --- |
83 | | web3 | Web3 | |
84 | | contractAddress | Address | ? (opt) |
85 |
86 |
87 |
88 | ## deploy(startDate, endDate, distributionDate, [individualMaximumAmount], [minimumRaise], [feePercentage], [hasWhitelisting], [ERC20TradingAddress], categoryIds, categoriesSupply, categoriesPrice, [tradingDecimals])
89 | Deploy the NFT swap contract
90 |
91 | **Kind**: global function
92 |
93 | | Param | Type | Description |
94 | | --- | --- | --- |
95 | | startDate | String | Start date |
96 | | endDate | String | End date |
97 | | distributionDate | String | Distribution date |
98 | | [individualMaximumAmount] | Float | Max cap per wallet. 0 to disable it. (Default: 0) |
99 | | [minimumRaise] | Float | Soft cap (Default: 0) |
100 | | [feePercentage] | Float | Fee percentage (Default: 1) |
101 | | [hasWhitelisting] | Boolean | Has White Listing. (Default: false) |
102 | | [ERC20TradingAddress] | String | Token to use in the swap (Default: 0x0000000000000000000000000000000000000000) |
103 | | categoryIds | Array.<Number> | Ids of the NFT categories |
104 | | categoriesSupply | Array.<Number> | Supply of every category of NFT in same order than Ids |
105 | | categoriesPrice | Array.<Float> | Price per unit of a category item, in same order than Ids |
106 | | [tradingDecimals] | Number | To be the decimals of the currency in case (ex : USDT -> 9; ETH -> 18) (Default: 0) |
107 |
108 |
109 |
110 | ## swap(tokenAmount, categoryId, maxAllocation, [signature])
111 | Swap tokens by Ethereum or ERC20
112 |
113 | **Kind**: global function
114 |
115 | | Param | Type | Description |
116 | | --- | --- | --- |
117 | | tokenAmount | Integer | |
118 | | categoryId | Integer | |
119 | | maxAllocation | Integer | |
120 | | [signature] | string | Signature for the offchain whitelist |
121 |
122 |
123 |
124 | ## setDistributionDate(distributionDate) ⇒ admin
125 | Modifies the distribution date for the pool
126 |
127 | **Kind**: global function
128 |
129 | | Param | Type |
130 | | --- | --- |
131 | | distributionDate | Date |
132 |
133 |
134 |
135 | ## distributionDate() ⇒ Date
136 | Get Distribution Date of NFT
137 |
138 | **Kind**: global function
139 |
140 |
141 | ## hasDistributed() ⇒ Boolean
142 | Verify if the NFTs are up for distribution, if the current date is after distributionDate
143 |
144 | **Kind**: global function
145 |
146 |
147 | ## tokensForSale(categoryId) ⇒ Integer
148 | Get Total tokens for sale by category
149 |
150 | **Kind**: global function
151 | **Returns**: Integer - Amount in Tokens
152 |
153 | | Param | Type |
154 | | --- | --- |
155 | | categoryId | Integer |
156 |
157 |
158 |
159 | ## soldByCategoryId(categoryId) ⇒ Integer
160 | Get Total tokens for sold by category
161 |
162 | **Kind**: global function
163 | **Returns**: Integer - Amount in Tokens
164 |
165 | | Param | Type |
166 | | --- | --- |
167 | | categoryId | Integer |
168 |
169 |
170 |
171 | ## tokensLeft(categoryId) ⇒ Integer
172 | Get Total tokens owned by category
173 |
174 | **Kind**: global function
175 | **Returns**: Integer - Amount in Tokens
176 |
177 | | Param | Type |
178 | | --- | --- |
179 | | categoryId | Integer |
180 |
181 |
182 |
183 | ## totalCost() ⇒ Integer
184 | Get Total cost for buying all the nfts
185 |
186 | **Kind**: global function
187 | **Returns**: Integer - Amount in Tokens
188 |
189 |
190 | ## getCost(amount, categoryId) ⇒ Integer
191 | Get Cost for category and amount
192 |
193 | **Kind**: global function
194 | **Returns**: Integer - costAmount
195 |
196 | | Param | Type |
197 | | --- | --- |
198 | | amount | Integer |
199 | | categoryId | Integer |
200 |
201 |
202 |
203 | ## safePullTradeToken()
204 | Safe Pull all trading tokens
205 |
206 | **Kind**: global function
207 |
208 |
209 | ## getUserPurchases(address) ⇒ Array.<Object>
210 | **Kind**: global function
211 | **Returns**: Array.<Object> - purchases
212 |
213 | | Param | Type |
214 | | --- | --- |
215 | | address | Address |
216 |
217 |
218 |
219 | ## getPurchase(purchaseId) ⇒ Integer \| Integer \| Integer \| Integer \| Address \| Date \| Boolean
220 | Get Purchase based on ID
221 |
222 | **Kind**: global function
223 | **Returns**: Integer - _idInteger - categoryIdInteger - amountInteger - amountContributedAddress - purchaserDate - timestampBoolean - reverted
224 |
225 | | Param | Type |
226 | | --- | --- |
227 | | purchaseId | Integer |
228 |
229 |
230 |
231 | ## getBuyers() ⇒ Array \| Integer
232 | Get Buyers
233 |
234 | **Kind**: global function
235 | **Returns**: Array \| Integer - _ids
236 |
237 |
238 | ## getPurchaseIds() ⇒ Array \| Integer
239 | Get All Purchase Ids
240 |
241 | **Kind**: global function
242 | **Returns**: Array \| Integer - _ids
243 |
244 |
245 | ## getPurchaseIds(address) ⇒ Array \| Integer
246 | Get All Purchase Ids filter by Address/Purchaser
247 |
248 | **Kind**: global function
249 | **Returns**: Array \| Integer - _ids
250 |
251 | | Param | Type |
252 | | --- | --- |
253 | | address | Address |
254 |
255 |
256 |
257 | ## getIsClaimedCategoryForUser(address, categoryId) ⇒ boolean
258 | **Kind**: global function
259 | **Returns**: boolean - claimed
260 |
261 | | Param | Type |
262 | | --- | --- |
263 | | address | Address |
264 | | categoryId | Number |
265 |
266 |
267 |
268 | ## setUserClaimedCategory(address, categoryId) ⇒ admin
269 | Sets user claimed category
270 |
271 | **Kind**: global function
272 |
273 | | Param | Type |
274 | | --- | --- |
275 | | address | Address |
276 | | categoryId | Number |
277 |
278 |
279 |
280 | ## categoryIds() ⇒ Array.<Number>
281 | **Kind**: global function
282 | **Returns**: Array.<Number> - an array containig all category ids
283 |
284 |
285 | ## setCategories(categoryIds, categoriesSupply, categoriesPrice, tradingDecimals) ⇒ admin
286 | Modifies the categories oon the contract
287 |
288 | **Kind**: global function
289 |
290 | | Param | Type | Description |
291 | | --- | --- | --- |
292 | | categoryIds | Array.<Number> | Ids of the NFT categories |
293 | | categoriesSupply | Array.<Number> | Supply of every category of NFT in same order than Ids |
294 | | categoriesPrice | Array.<Float> | Price per unit of a category item, in same order than Ids |
295 | | tradingDecimals | Number | To be the decimals of the currency in case (ex : USDT -> 9; ETH -> 18) |
296 |
297 |
--------------------------------------------------------------------------------
/src/models/contracts/IDOStaking.js:
--------------------------------------------------------------------------------
1 | import Contract from "../base/Contract";
2 | import { idostaking } from "../../interfaces";
3 | import Numbers from "../../utils/Numbers";
4 | import ERC20TokenContract from "../base/ERC20TokenContract";
5 | import Client from "../../utils/Client";
6 |
7 | /**
8 | * IDO Staking Object
9 | * @constructor IDOStaking
10 | * @param {Web3} web3
11 | * @param {string} contractAddress The staking contract address.
12 | * @param {Account} acc
13 | */
14 | class IDOStaking {
15 |
16 | constructor({
17 | web3,
18 | contractAddress,
19 | acc,
20 | }) {
21 | if (!web3) {
22 | throw new Error("Please provide a valid web3 provider");
23 | }
24 | this.web3 = web3;
25 | this.version = "2.0";
26 | if (acc) {
27 | this.acc = acc;
28 | }
29 |
30 | this.params = {
31 | web3: web3,
32 | contractAddress: contractAddress,
33 | contract: new Contract(web3, idostaking, contractAddress),
34 | };
35 | this.client = new Client();
36 | }
37 |
38 | /**
39 | * @function deploy
40 | * @description Deploys the IDO Staking contracts
41 | * @param {string} owner Address of the owner
42 | * @param {string} rewardsDistribution Address of the distributor
43 | * @param {string} rewardsToken Address of the token we want to reward
44 | * @param {string} stakingToken Address of the token to be staked
45 | * @param {Integer} rewardsDuration Duration of the rewards
46 | * @param {string} tokenSaleAddress Address of the pool
47 | * @returns {string} address The deployed contract address
48 | */
49 | deploy = async ({
50 | owner,
51 | rewardsDistribution,
52 | rewardsToken,
53 | stakingToken,
54 | rewardsDuration,
55 | tokenSaleAddress = '0x0000000000000000000000000000000000000000',
56 | callback
57 | }) => {
58 | const params = [
59 | owner,
60 | rewardsDistribution,
61 | rewardsToken,
62 | stakingToken,
63 | rewardsDuration,
64 | tokenSaleAddress
65 | ];
66 | const res = await this.__deploy(params, callback);
67 | this.params.contractAddress = res.contractAddress;
68 | return res.contractAddress;
69 | }
70 |
71 | __deploy = async (params, callback) => {
72 | return await this.params.contract.deploy(
73 | this.acc,
74 | this.params.contract.getABI(),
75 | this.params.contract.getJSON().bytecode,
76 | params,
77 | callback
78 | );
79 | };
80 |
81 | /**
82 | * @function stake
83 | * @description Stakes tokens inside the stake contract
84 | * @param {Integer} amount Amount
85 | */
86 | stake = async ({ amount }) => {
87 | amount = Numbers.toSmartContractDecimals(
88 | amount,
89 | await this.getDecimals()
90 | )
91 | try {
92 | return await this.client.sendTx(
93 | this.params.web3,
94 | this.acc,
95 | this.params.contract,
96 | this.params.contract
97 | .getContract()
98 | .methods.stake(amount)
99 | );
100 | } catch (err) {
101 | throw err;
102 | }
103 | };
104 |
105 | /**
106 | * @function approveStakeERC20
107 | * @param {Integer} tokenAmount
108 | * @description Approve the stake to use approved tokens
109 | */
110 | approveStakeERC20 = async ({ tokenAmount, callback }) => {
111 | return await (await this.getTokenContract()).approve({
112 | address: this.params.contractAddress,
113 | amount: tokenAmount,
114 | callback
115 | });
116 | };
117 |
118 | /**
119 | * @function isApproved
120 | * @description Verify if the address has approved the staking to deposit
121 | * @param {Integer} tokenAmount
122 | * @param {Address} address
123 | * @returns {Boolean}
124 | */
125 | isApproved = async ({ tokenAmount, address }) => {
126 | return await (await this.getTokenContract()).isApproved({
127 | address: address,
128 | amount: tokenAmount,
129 | spenderAddress: this.params.contractAddress
130 | });
131 | };
132 |
133 | /**
134 | * @function getAPY
135 | * @description Returns the APY that this pool is giving
136 | * @returns {Integer}
137 | */
138 | getAPY = async () => {
139 | const oneYear = 31556952;
140 | const duration = await this.params.contract
141 | .getContract()
142 | .methods.rewardsDuration()
143 | .call();
144 | const rewardPerToken = await this.params.contract
145 | .getContract()
146 | .methods.rewardPerToken()
147 | .call();
148 |
149 | return parseInt((parseInt(rewardPerToken) * 100) / (parseInt(duration) / oneYear));
150 | }
151 |
152 | /**
153 | * @function withdraw
154 | * @param {Integer} amount
155 | * @description Withdraw tokens from the stake contract
156 | */
157 | withdraw = async ({amount}) => {
158 | try {
159 | return await this.client.sendTx(
160 | this.params.web3,
161 | this.acc,
162 | this.params.contract,
163 | this.params.contract
164 | .getContract()
165 | .methods.withdraw(Numbers.toSmartContractDecimals(
166 | amount,
167 | await this.getDecimals()
168 | ))
169 | );
170 | } catch (err) {
171 | throw err;
172 | }
173 | };
174 |
175 | /**
176 | * @function withdrawAll
177 | * @description Withdraw all the tokens from the stake contract
178 | */
179 | withdrawAll = async () => {
180 | try {
181 | return await this.client.sendTx(
182 | this.params.web3,
183 | this.acc,
184 | this.params.contract,
185 | this.params.contract
186 | .getContract()
187 | .methods.withdrawAll()
188 | );
189 | } catch (err) {
190 | throw err;
191 | }
192 | };
193 |
194 | /**
195 | * @function exit
196 | * @description Claims all the rewards and withdraws all the staked tokens
197 | */
198 | exit = async () => {
199 | try {
200 | return await this.client.sendTx(
201 | this.params.web3,
202 | this.acc,
203 | this.params.contract,
204 | this.params.contract
205 | .getContract()
206 | .methods.exit()
207 | );
208 | } catch (err) {
209 | throw err;
210 | }
211 | };
212 |
213 | /**
214 | * @function claim
215 | * @description Claim rewards from the staking contract
216 | */
217 | claim = async () => {
218 | try {
219 | return await this.client.sendTx(
220 | this.params.web3,
221 | this.acc,
222 | this.params.contract,
223 | this.params.contract
224 | .getContract()
225 | .methods.getReward()
226 | );
227 | } catch (err) {
228 | throw err;
229 | }
230 | };
231 |
232 | /**
233 | * @function notifyRewardAmountSamePeriod
234 | * @description add (more) rewards token to current/future period
235 | * @param {Integer} amount
236 | */
237 | notifyRewardAmountSamePeriod = async ({reward}) => {
238 | try {
239 | const amount = Numbers.toSmartContractDecimals(
240 | reward,
241 | await this.getRewardsDecimals()
242 | );
243 | return await this.client.sendTx(
244 | this.params.web3,
245 | this.acc,
246 | this.params.contract,
247 | this.params.contract
248 | .getContract()
249 | .methods.notifyRewardAmountSamePeriod(amount)
250 | );
251 | } catch (err) {
252 | throw err;
253 | }
254 | };
255 |
256 | /**
257 | * @function transferRewardTokenSamePeriod
258 | * @description Transfer and add (more) rewards token to current/future period
259 | * @param {Integer} amount
260 | */
261 | transferRewardTokenSamePeriod = async ({reward}) => {
262 | try {
263 | const amount = Numbers.toSmartContractDecimals(
264 | reward,
265 | await this.getRewardsDecimals()
266 | );
267 | return await this.client.sendTx(
268 | this.params.web3,
269 | this.acc,
270 | this.params.contract,
271 | this.params.contract
272 | .getContract()
273 | .methods.transferRewardTokenSamePeriod(amount)
274 | );
275 | } catch (err) {
276 | throw err;
277 | }
278 | };
279 |
280 | /**
281 | * @function userAccumulatedRewards
282 | * @description Returns the accumulated rewards
283 | * @param {string} address
284 | * @returns {Integer} userAccumulatedRewards
285 | */
286 | userAccumulatedRewards = async ({address}) => {
287 | return Numbers.fromDecimals(
288 | await this.params.contract.getContract().methods.earned(address).call(),
289 | await this.getRewardsDecimals(),
290 | );
291 | }
292 |
293 | /**
294 | * @function recoverERC20
295 | * @description Emergency withdrawal of tokens
296 | * @param {string} address Token address
297 | */
298 | recoverERC20 = async ({address}) => {
299 | await this.client.sendTx(
300 | this.params.web3,
301 | this.acc,
302 | this.params.contract,
303 | this.params.contract
304 | .getContract()
305 | .methods.recoverERC20(address)
306 | );
307 | }
308 |
309 | /**
310 | * @function lastTimeRewardApplicable
311 | * @description Get the last time rewards are applicable
312 | * @returns {Date}
313 | */
314 | async lastTimeRewardApplicable() {
315 | return Numbers.fromSmartContractTimeToMinutes(
316 | await this.params.contract.getContract().methods.lastTimeRewardApplicable().call()
317 | );
318 | }
319 |
320 |
321 | /**
322 | * @function totalStaked
323 | * @description Returns the total stake
324 | * @returns {Integer} totalStakeAmount
325 | */
326 | totalStaked = async () => {
327 | return Numbers.fromDecimals(
328 | await this.params.contract.getContract().methods.totalSupply().call(),
329 | await this.getDecimals()
330 | );
331 | }
332 |
333 | /**
334 | * @function balanceRewardsToken
335 | * @description substract staked amount if staked token is the same as rewards token
336 | * @returns {Integer} totalRewardsAmount
337 | */
338 | balanceRewardsToken = async () => {
339 | return Numbers.fromDecimals(
340 | await this.params.contract.getContract().methods.balanceRewardsToken().call(),
341 | await this.getDecimals()
342 | );
343 | }
344 |
345 | /**
346 | * @function stakeAmount
347 | * @description Returns the stake amount for a wallet
348 | * @param {string} address
349 | * @returns {Integer} stakeAmount
350 | */
351 | stakeAmount = async ({address}) => {
352 | return Numbers.fromDecimals(
353 | await this.params.contract.getContract().methods.balanceOf(address).call(),
354 | await this.getDecimals()
355 | );
356 | }
357 |
358 | /**
359 | * @function setTokenSaleAddress
360 | * @description Sets the token sale address
361 | * @param {string} address
362 | */
363 | setTokenSaleAddress = async ({address}) => {
364 | try {
365 | await this.client.sendTx(
366 | this.params.web3,
367 | this.acc,
368 | this.params.contract,
369 | this.params.contract
370 | .getContract()
371 | .methods.setTokenSaleAddress(address)
372 | );
373 | return true;
374 | } catch (err) {
375 | throw err;
376 | }
377 | };
378 |
379 | getDecimals = async () => {
380 | return await (await this.getTokenContract()).getDecimals();
381 | }
382 |
383 | getTokenContract = async () => {
384 | if (!this.params.erc20TokenContract) {
385 | this.params.erc20TokenContract = new ERC20TokenContract({
386 | web3: this.params.web3,
387 | contractAddress: await this.params.contract.getContract().methods.stakingToken().call(),
388 | acc: this.acc
389 | });
390 | }
391 | return this.params.erc20TokenContract;
392 | }
393 |
394 | getRewardsDecimals = async () => {
395 | return await (await this.getRewardsTokenContract()).getDecimals();
396 | }
397 |
398 | getRewardsTokenContract = async () => {
399 | if (!this.params.erc20TokenRewardsContract) {
400 | this.params.erc20TokenRewardsContract = new ERC20TokenContract({
401 | web3: this.params.web3,
402 | contractAddress: await this.params.contract.getContract().methods.rewardsToken().call(),
403 | acc: this.acc
404 | });
405 | }
406 | return this.params.erc20TokenRewardsContract;
407 | }
408 |
409 | }
410 |
411 | export default IDOStaking;
412 |
--------------------------------------------------------------------------------
/src/models/contracts/FixedNFTSwapContract.js:
--------------------------------------------------------------------------------
1 | import { fixednftswap } from "../../interfaces";
2 | import Numbers from "../../utils/Numbers";
3 | import _ from "lodash";
4 | import moment from 'moment';
5 | import BaseSwapContract from './base/BaseSwapContract';
6 | import DeploymentService from "../../services/DeploymentService";
7 | import ERC20TokenContract from "../base/ERC20TokenContract";
8 |
9 | /**
10 | * Fixed NFT Swap Object
11 | * @constructor FixedNFTSwapContract
12 | * @param {Web3} web3
13 | * @param {Address} contractAddress ? (opt)
14 | * @extends BaseSwapContract
15 | */
16 | class FixedNFTSwapContract extends BaseSwapContract {
17 | constructor({
18 | web3,
19 | contractAddress = null /* If not deployed */,
20 | acc,
21 | }) {
22 | super({ web3, contractAddress, acc, contractInterface: fixednftswap });
23 | }
24 |
25 | /**
26 | *
27 | * @function deploy
28 | * @description Deploy the NFT swap contract
29 | * @param {String} startDate Start date
30 | * @param {String} endDate End date
31 | * @param {String} distributionDate Distribution date
32 | * @param {Float=} individualMaximumAmount Max cap per wallet. 0 to disable it. (Default: 0)
33 | * @param {Float=} minimumRaise Soft cap (Default: 0)
34 | * @param {Float=} feePercentage Fee percentage (Default: 1)
35 | * @param {Boolean=} hasWhitelisting Has White Listing. (Default: false)
36 | * @param {String=} ERC20TradingAddress Token to use in the swap (Default: 0x0000000000000000000000000000000000000000)
37 | * @param {Number[]} categoryIds Ids of the NFT categories
38 | * @param {Number[]} categoriesSupply Supply of every category of NFT in same order than Ids
39 | * @param {Float[]} categoriesPrice Price per unit of a category item, in same order than Ids
40 | * @param {Number=} tradingDecimals To be the decimals of the currency in case (ex : USDT -> 9; ETH -> 18) (Default: 0)
41 |
42 | */
43 |
44 | deploy = async ({
45 | startDate,
46 | endDate,
47 | distributionDate,
48 | individualMaximumAmount = 0,
49 | minimumRaise = 0,
50 | feePercentage = 1,
51 | hasWhitelisting = false,
52 | ERC20TradingAddress = '0x0000000000000000000000000000000000000000',
53 | categoryIds,
54 | categoriesSupply,
55 | categoriesPrice,
56 | tradingDecimals = 0, /* To be the decimals of the currency in case (ex : USDT -> 9; ETH -> 18) */
57 | callback
58 | }) => {
59 | if (feePercentage < 1) {
60 | throw new Error("Fee Amount has to be >= 1");
61 | }
62 |
63 | if (ERC20TradingAddress != '0x0000000000000000000000000000000000000000' && (tradingDecimals == 0)) {
64 | throw new Error("If an ERC20 Trading Address please add the 'tradingDecimals' field to the trading address (Ex : USDT -> 6)");
65 | } else {
66 | /* is ETH Trade */
67 | tradingDecimals = 18;
68 | }
69 |
70 | if (ERC20TradingAddress) {
71 | this.params.erc20TokenContract = new ERC20TokenContract({
72 | web3: this.web3,
73 | contractAddress: ERC20TradingAddress,
74 | acc: this.acc
75 | });
76 | }
77 |
78 | let totalRaise = 0;
79 | let finalcategoriesPrice = [];
80 | for (let i = 0; i < categoriesSupply.length; i++) {
81 | totalRaise += categoriesSupply[i] * categoriesPrice[i];
82 | finalcategoriesPrice[i] = Numbers.toSmartContractDecimals(
83 | categoriesPrice[i],
84 | tradingDecimals
85 | )
86 | };
87 | if (minimumRaise != 0 && (minimumRaise > totalRaise)) {
88 | throw new Error("Minimum Raise has to be smaller than total Raise")
89 | }
90 | if (Date.parse(startDate) >= Date.parse(endDate)) {
91 | throw new Error("Start Date has to be smaller than End Date")
92 | }
93 | if (Date.parse(endDate) >= Date.parse(distributionDate)) {
94 | throw new Error("End Date has to be smaller than Distribution Date")
95 | }
96 | if (Date.parse(startDate) <= Date.parse(moment(Date.now()).add(2, 'm').toDate())) {
97 | throw new Error("Start Date has to be higher (at least 2 minutes) than now")
98 | }
99 | if (individualMaximumAmount < 0) {
100 | throw new Error("Individual Maximum Amount should be bigger than 0")
101 | }
102 |
103 | if (individualMaximumAmount > 0) {
104 | /* If exists individualMaximumAmount */
105 | if (individualMaximumAmount > totalRaise) {
106 | throw new Error("Individual Maximum Amount should be smaller than total Tokens For Sale")
107 | }
108 | }
109 |
110 | if (individualMaximumAmount == 0) {
111 | individualMaximumAmount = totalRaise; /* Set Max Amount to Unlimited if 0 */
112 | }
113 |
114 | let params = [
115 | Numbers.timeToSmartContractTime(startDate),
116 | Numbers.timeToSmartContractTime(endDate),
117 | Numbers.timeToSmartContractTime(distributionDate),
118 | Numbers.toSmartContractDecimals(
119 | individualMaximumAmount,
120 | await this.getTradingDecimals()
121 | ),
122 | Numbers.toSmartContractDecimals(minimumRaise, await this.getTradingDecimals()),
123 | parseInt(feePercentage),
124 | hasWhitelisting,
125 | ERC20TradingAddress,
126 | categoryIds,
127 | categoriesSupply,
128 | finalcategoriesPrice
129 | ];
130 | let res = await new DeploymentService().deploy(
131 | this.acc,
132 | this.params.contract,
133 | params,
134 | callback
135 | );
136 | this.params.contractAddress = res.contractAddress;
137 | /* Call to Backend API */
138 |
139 | this.__assert();
140 | return res;
141 | };
142 |
143 | /**
144 | * @function swap
145 | * @description Swap tokens by Ethereum or ERC20
146 | * @param {Integer} tokenAmount
147 | * @param {Integer} categoryId
148 | * @param {Integer} maxAllocation
149 | * @param {string=} signature Signature for the offchain whitelist
150 | */
151 |
152 | swap = async ({ tokenAmount, categoryId, maxAllocation, callback, signature }) => {
153 |
154 | let cost = await this.getCost({
155 | amount: tokenAmount,
156 | categoryId
157 | });
158 |
159 | let costToDecimals = Numbers.toSmartContractDecimals(cost, await this.getTradingDecimals());
160 |
161 | if (!signature) {
162 | signature = '0x00';
163 | }
164 |
165 | return await this.executeContractMethod(
166 | this.getContractMethods().swapWithSig(tokenAmount, categoryId, maxAllocation, signature),
167 | false,
168 | await this.isETHTrade() ? costToDecimals : 0,
169 | callback
170 | );
171 | };
172 |
173 | /**************************************
174 | * DATE METHODS
175 | **************************************/
176 |
177 | /**
178 | * @function setDistributionDate
179 | * @type admin
180 | * @param {Date} distributionDate
181 | * @description Modifies the distribution date for the pool
182 | */
183 | setDistributionDate = async ({ distributionDate }) => {
184 | return await this.executeContractMethod(
185 | this.getContractMethods().setDistributionDate(Numbers.timeToSmartContractTime(distributionDate))
186 | );
187 | }
188 |
189 | /**
190 | * @function distributionDate
191 | * @description Get Distribution Date of NFT
192 | * @returns {Date}
193 | */
194 | async distributionDate() {
195 | return Numbers.fromSmartContractTimeToMinutes(
196 | await this.getContractMethods().distributionDate().call()
197 | );
198 | }
199 |
200 | /**
201 | * @function hasDistributed
202 | * @description Verify if the NFTs are up for distribution, if the current date is after distributionDate
203 | * @returns {Boolean}
204 | */
205 | async hasDistributed() {
206 | return await this.params.contract
207 | .getContract()
208 | .methods.hasDistributed()
209 | .call();
210 | }
211 |
212 | /**************************************
213 | * TOKEN METHODS
214 | **************************************/
215 |
216 | /**
217 | * @function tokensForSale
218 | * @description Get Total tokens for sale by category
219 | * @param {Integer} categoryId
220 | * @returns {Integer} Amount in Tokens
221 | */
222 | async tokensForSale({ categoryId }) {
223 | return (await this.params.contract
224 | .getContract()
225 | .methods.categories(categoryId)
226 | .call()).supply;
227 | }
228 |
229 | /**
230 | * @function soldByCategoryId
231 | * @description Get Total tokens for sold by category
232 | * @param {Integer} categoryId
233 | * @returns {Integer} Amount in Tokens
234 | */
235 | async soldByCategoryId({ categoryId }) {
236 | return await this.params.contract
237 | .getContract()
238 | .methods.soldByCategoryId(categoryId)
239 | .call();
240 | }
241 |
242 | /**
243 | * @function tokensAllocated
244 | * @description Get Total tokens spent in the contract, therefore the tokens bought until now
245 | * @returns {Integer} Amount in Tokens
246 | */
247 | async tokensAllocated() {
248 | return Numbers.fromDecimals(
249 | (await this.params.contract
250 | .getContract()
251 | .methods.tokensAllocated()
252 | .call()),
253 | await this.getTradingDecimals()
254 | );
255 | }
256 |
257 | /**
258 | * @function tokensLeft
259 | * @description Get Total tokens owned by category
260 | * @param {Integer} categoryId
261 | * @returns {Integer} Amount in Tokens
262 | */
263 | async tokensLeft({ categoryId }) {
264 | return await this.params.contract
265 | .getContract()
266 | .methods.tokensLeft(categoryId)
267 | .call();
268 | }
269 |
270 | /**
271 | * @function totalCost
272 | * @description Get Total cost for buying all the nfts
273 | * @returns {Integer} Amount in Tokens
274 | */
275 | async totalCost() {
276 | return await this.params.contract
277 | .getContract()
278 | .methods.maximumRaise()
279 | .call();
280 | }
281 |
282 | /**
283 | * @function getCost
284 | * @description Get Cost for category and amount
285 | * @param {Integer} amount
286 | * @param {Integer} categoryId
287 | * @returns {Integer} costAmount
288 | */
289 | getCost = async ({ amount, categoryId }) => {
290 |
291 | return Numbers.fromDecimals(
292 | await this.params.contract
293 | .getContract()
294 | .methods.cost(amount, categoryId)
295 | .call(),
296 | await this.getTradingDecimals()
297 | );
298 | };
299 |
300 | /**
301 | * @function safePullTradeToken
302 | * @description Safe Pull all trading tokens
303 | */
304 | safePullTradeToken = async () => {
305 | return await this.executeContractMethod(
306 | this.getContractMethods().safePullTradeToken(),
307 | null,
308 | 0
309 | );
310 | };
311 |
312 | /* Legacy Call */
313 | getETHCostFromTokens = () => { throw new Error("Please use 'getCost' instead") };
314 |
315 | /**************************************
316 | * PURCHASE METHODS
317 | **************************************/
318 |
319 | /**
320 | * @function getUserPurchases
321 | * @param {Address} address
322 | * @returns {Object[]} purchases
323 | */
324 | getUserPurchases = async ({ address }) => {
325 | let purchaseIds = await this.params.contract
326 | .getContract()
327 | .methods
328 | .getMyPurchases(address)
329 | .call();
330 | let purchases = [];
331 |
332 | for (let id of purchaseIds) {
333 | if (id != undefined) {
334 | purchases.push(
335 | await this.getPurchase({ purchaseId: Number(id) })
336 | );
337 | }
338 | };
339 | return purchases;
340 | };
341 |
342 | /**
343 | * @function getPurchase
344 | * @description Get Purchase based on ID
345 | * @param {Integer} purchaseId
346 | * @returns {Integer} _id
347 | * @returns {Integer} categoryId
348 | * @returns {Integer} amount
349 | * @returns {Integer} amountContributed
350 | * @returns {Address} purchaser
351 | * @returns {Date} timestamp
352 | * @returns {Boolean} reverted
353 | */
354 | getPurchase = async ({ purchaseId }) => {
355 | let res = await this.params.contract
356 | .getContract()
357 | .methods.getPurchase(purchaseId)
358 | .call();
359 |
360 | let amountContributed = Numbers.fromDecimals(res.amountContributed, await this.getTradingDecimals());
361 |
362 | return {
363 | _id: purchaseId,
364 | categoryId: Number(res.categoryId),
365 | amount: Number(res.amountPurchased),
366 | amountContributed,
367 | purchaser: res.purchaser,
368 | timestamp: Numbers.fromSmartContractTimeToMinutes(res.timestamp),
369 | reverted: res.reverted,
370 | };
371 | };
372 |
373 | /**
374 | * @function getBuyers
375 | * @description Get Buyers
376 | * @returns {Array | Integer} _ids
377 | */
378 |
379 | getBuyers = async () =>
380 | await this.getContractMethods().getBuyers().call();
381 |
382 | /**
383 | * @function getPurchaseIds
384 | * @description Get All Purchase Ids
385 | * @returns {(Array | Integer)} _ids
386 | */
387 | getPurchaseIds = async () => {
388 | let res = await this.params.contract
389 | .getContract()
390 | .methods.getPurchasesCount()
391 | .call();
392 | let ids = [];
393 | for (let i = 0; i < res; i++) {
394 | ids.push(i);
395 | }
396 | return ids;
397 | };
398 |
399 | /**
400 | * @function getPurchaseIds
401 | * @description Get All Purchase Ids filter by Address/Purchaser
402 | * @param {Address} address
403 | * @returns {Array | Integer} _ids
404 | */
405 | getAddressPurchaseIds = async ({ address }) => {
406 | let res = await this.executeContractMethod(
407 | this.getContractMethods().getMyPurchases(address),
408 | true
409 | );
410 | return res.map((id) => Numbers.fromHex(id));
411 | };
412 |
413 |
414 | /**************************************
415 | * CATEGORIES METHODS
416 | **************************************/
417 |
418 | /**
419 | * @function getIsClaimedCategoryForUser
420 | * @param {Address} address
421 | * @param {Number} categoryId
422 | * @returns {boolean} claimed
423 | */
424 | getIsClaimedCategoryForUser = async ({ address, categoryId }) => {
425 | return await this.executeContractMethod(
426 | this.getContractMethods().getIsClaimedCategoryForUser(address, categoryId),
427 | true
428 | );
429 | }
430 |
431 | /**
432 | * @function setUserClaimedCategory
433 | * @type admin
434 | * @param {Address} address
435 | * @param {Number} categoryId
436 | * @description Sets user claimed category
437 | */
438 | setUserClaimedCategory = async ({ address, categoryId }) => {
439 | await this.executeContractMethod(
440 | this.getContractMethods().setUserClaimedCategory(address, categoryId)
441 | );
442 | };
443 |
444 | /**
445 | * @function categoryIds
446 | * @returns {Number[]} an array containig all category ids
447 | */
448 | async categoryIds() {
449 | return await this.params.contract
450 | .getContract()
451 | .methods
452 | .getCategoryIds()
453 | .call();
454 | }
455 |
456 | /**
457 | * @function setCategories
458 | * @type admin
459 | * @param {Number[]} categoryIds Ids of the NFT categories
460 | * @param {Number[]} categoriesSupply Supply of every category of NFT in same order than Ids
461 | * @param {Float[]} categoriesPrice Price per unit of a category item, in same order than Ids
462 | * @param {Number} tradingDecimals To be the decimals of the currency in case (ex : USDT -> 9; ETH -> 18)
463 | * @description Modifies the categories oon the contract
464 | */
465 | setCategories = async ({ categoryIds, categoriesSupply, categoriesPrice }) => {
466 | let finalcategoriesPrice = [];
467 | for (let i = 0; i < categoriesPrice.length; i++) {
468 | finalcategoriesPrice[i] = Numbers.toSmartContractDecimals(
469 | categoriesPrice[i],
470 | await this.getTradingDecimals()
471 | )
472 | };
473 | return await this.executeContractMethod(
474 | this.getContractMethods().setCategories(
475 | categoryIds,
476 | categoriesSupply,
477 | categoriesPrice
478 | )
479 | );
480 | }
481 |
482 | }
483 |
484 | export default FixedNFTSwapContract;
485 |
--------------------------------------------------------------------------------
/tests/test/nft-whitelist.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 |
3 | import Web3 from "web3";
4 | import chai from 'chai';
5 | import { mochaAsync } from '../utils';
6 | import moment, { isDate } from 'moment';
7 | import Application from '../../src/models';
8 | import { ierc20 } from "../../src/interfaces";
9 | import Numbers from "../../src/utils/Numbers";
10 | import Contract from "../../src/models/base/Contract";
11 | import * as ethers from 'ethers';
12 |
13 | var contractAddress = '0x420751cdeb28679d8e336f2b4d1fc61df7439b5a';
14 | var userPrivateKey = '0x7f76de05082c4d578219ca35a905f8debe922f1f00b99315ebf0706afc97f132';
15 | const expect = chai.expect;
16 | let tokenPurchaseAmount = 0.01;
17 | const tokenFundAmount = 5;
18 | const tradeValue = 0.01;
19 | let signs = [];
20 | context('NFT Contract With Whitelisting', async () => {
21 | var swapContract;
22 | var app;
23 | var ethersProvider;
24 | var isSaleOpen, tokensLeft, indivMaxAmount;
25 | var currentTime;
26 |
27 | var isRealChain = process.env.CHAIN_NAME;
28 |
29 | const getWeb3 = () => {
30 | // Instance Application using ganache
31 | const provider = require("ganache-core").provider({
32 | gasLimit: 10000000000,
33 |
34 | gasPrice: 1,
35 | debug: true,
36 | accounts: [
37 | {
38 | secretKey: userPrivateKey,
39 | balance: 1000000000000000000000
40 | }
41 | ]
42 | });
43 | ethersProvider = new ethers.providers.Web3Provider(provider);
44 | return new Web3(provider);
45 | }
46 |
47 | const sleep = async (time) => {
48 | return new Promise((resolve) => {
49 | setTimeout(resolve, time * 1000)
50 | });
51 | }
52 |
53 | const forwardTime = async (time) => {
54 | if (isRealChain) {
55 | await sleep(time);
56 | currentTime = parseInt(new Date().getTime()/1000);
57 | return;
58 | }
59 | // "Roads? Where we’re going, we don’t need roads."
60 | const date = parseInt(new Date().getTime()/1000);
61 | currentTime = date + await ethersProvider.send('evm_increaseTime', [ time ]);
62 | return await ethersProvider.send('evm_mine');
63 | }
64 |
65 | before(mochaAsync(async () => {
66 | return new Promise(async (resolve) => {
67 | // Instance Application
68 | app = new Application({test : true, mainnet : false, network : isRealChain ? process.env.CHAIN_NAME : 'ETH', web3:
69 | isRealChain ? undefined : getWeb3()
70 | });
71 | app.web3.eth.transactionConfirmationBlocks = 1;
72 |
73 | // Deploy the ERC20
74 | const contract = new Contract(app.web3, ierc20.abi);
75 | const response = await contract.deploy(
76 | app.account,
77 | ierc20.abi,
78 | ierc20.bytecode,
79 | [],
80 | undefined
81 | );
82 | resolve();
83 | });
84 | }));
85 |
86 |
87 | it('should deploy Fixed NFT Swap Contract with whitelist', mochaAsync(async () => {
88 | /* Create Contract */
89 | swapContract = await app.getFixedNFTSwapContract({});
90 | /* Deploy */
91 | let res = await swapContract.deploy({
92 | individualMaximumAmount : 0.1,
93 | startDate : moment().add(4, 'minutes'),
94 | endDate : moment().add(8, 'minutes'),
95 | distributionDate: moment().add(9, 'minutes'),
96 | hasWhitelisting : true,
97 | categoryIds: [1, 2],
98 | categoriesSupply: [tokenFundAmount, 3],
99 | categoriesPrice: [tradeValue, 0.02]
100 | });
101 | contractAddress = swapContract.getAddress();
102 | expect(res).to.not.equal(false);
103 |
104 | const signer = app.getSigner();
105 | const account = await signer.generateSignerAccount({password: 'test1234'});
106 |
107 | signs = await signer.signAddresses({
108 | addresses: [
109 | '0xe797860acFc4e06C1b2B96197a7dB1dFa518d5eB'
110 | ],
111 | accountMaxAllocations: [
112 | 2
113 | ],
114 | decimals: 18,
115 | contractAddress: contractAddress,
116 | accountJson: account,
117 | password: 'test1234'
118 | });
119 |
120 | await swapContract.setSignerPublicAddress({
121 | address: ('0x' + JSON.parse(account).address).toLowerCase()
122 | });
123 | expect(await swapContract.getTradingDecimals()).to.equal(18);
124 | }));
125 |
126 | it('should get the correct smart contract version', mochaAsync(async () => {
127 | expect(await swapContract.getSmartContractVersion()).to.equal(3100000);
128 | }));
129 |
130 | it('should get a Fixed Swap Contract From contractAddress - 2.0', mochaAsync(async () => {
131 | /* Get Contract */
132 | swapContract = await app.getFixedNFTSwapContract({contractAddress});
133 | swapContract.__init__();
134 | await swapContract.assertERC20Info();
135 | expect(swapContract.version).to.equal("2.0");
136 | expect(swapContract).to.not.equal(false);
137 | }));
138 |
139 | it('GET - isPreFunded', mochaAsync(async () => {
140 | let res = await swapContract.isPreStart();
141 | expect(res).to.equal(true);
142 | }));
143 |
144 | it('GET - tokensLeft', mochaAsync(async () => {
145 | let tokens = await swapContract.tokensLeft({categoryId: 1});
146 | tokensLeft = tokens;
147 | expect(Number(tokens).noExponents()).to.equal(Number(tokenFundAmount).noExponents());
148 | }));
149 |
150 | it('should edit start Date', mochaAsync(async () => {
151 | let oldStartDate = await swapContract.startDate();
152 |
153 | const newStartDate = new Date(oldStartDate.getTime() + (1 * 1000));
154 | await swapContract.setStartDate({startDate: newStartDate});
155 | let res = await swapContract.startDate();
156 | expect(res.getTime()).to.equal(newStartDate.getTime());
157 |
158 | await swapContract.setStartDate({startDate: oldStartDate});
159 | res = await swapContract.startDate();
160 | expect(res.getTime()).to.equal(oldStartDate.getTime());
161 |
162 | }));
163 | it('should edit distribution date', mochaAsync(async () => {
164 | let oldDistributionDate = await swapContract.distributionDate();
165 | const newDistributionDate = new Date(oldDistributionDate.getTime() + (86400 * 1000));
166 |
167 | await swapContract.setDistributionDate({distributionDate: newDistributionDate});
168 | let res = await swapContract.distributionDate();
169 | expect(res.getTime()).to.equal(newDistributionDate.getTime());
170 |
171 | await swapContract.setDistributionDate({distributionDate: oldDistributionDate});
172 | res = await swapContract.distributionDate();
173 | expect(res.getTime()).to.equal(oldDistributionDate.getTime());
174 | }));
175 |
176 |
177 | it('GET - isSaleOpen - before Start', mochaAsync(async () => {
178 | await forwardTime(4*60);
179 | let res = await swapContract.isOpen();
180 | isSaleOpen = res;
181 | expect(res).to.equal(true);
182 | }));
183 |
184 | it('GET - hasWhitelisting ', mochaAsync(async () => {
185 | let res = await swapContract.hasWhitelisting();
186 | expect(res).to.equal(true);
187 | }));
188 |
189 | it('GET - startDate ', mochaAsync(async () => {
190 | let res = await swapContract.startDate();
191 | res = isDate(res);
192 | expect(res).to.equal(true);
193 | }));
194 |
195 | it('GET - endDate ', mochaAsync(async () => {
196 | let res = await swapContract.endDate();
197 | res = isDate(res);
198 | expect(res).to.equal(true);
199 | }));
200 |
201 | it('GET - category ids ', mochaAsync(async () => {
202 | let res = await swapContract.categoryIds();
203 | expect(Number(res[0])).to.equal(1);
204 | expect(Number(res[1])).to.equal(2);
205 | }));
206 |
207 | it('GET - individualMaximumAmount ', mochaAsync(async () => {
208 | let res = await swapContract.individualMaximumAmount();
209 | indivMaxAmount = res;
210 | expect(Number(res).noExponents()).to.equal(Number(0.1).noExponents());
211 | }));
212 |
213 | it('GET - getCostFromTokens ', mochaAsync(async () => {
214 | let res = await swapContract.getCost({amount : 2, categoryId: 2});
215 | expect(Number(res).noExponents()).to.equal(Number(0.04).noExponents());
216 | }));
217 |
218 | it('check conditions for swap ', mochaAsync(async () => {
219 | let amount = Number(tokenPurchaseAmount).noExponents() > 0 ? true : false;
220 | tokensLeft = Number(tokenPurchaseAmount).noExponents() <= Number(tokensLeft).noExponents() ? true : false;
221 | indivMaxAmount = Number(tokenPurchaseAmount).noExponents() <= Number(indivMaxAmount).noExponents() ? true : false;
222 | expect(isSaleOpen).to.equal(true);
223 | expect(amount).to.equal(true);
224 | expect(tokensLeft).to.equal(true);
225 | expect(indivMaxAmount).to.equal(true);
226 | }));
227 |
228 | it('GET - hasStarted', mochaAsync(async () => {
229 | await forwardTime(1*60);
230 | let res = await swapContract.hasStarted();
231 | expect(res).to.equal(true);
232 | }));
233 |
234 | it('GET - isSaleOpen', mochaAsync(async () => {
235 | let res = await swapContract.isOpen();
236 | expect(res).to.equal(true);
237 | }));
238 |
239 | it('Edit max allocation - Admin', mochaAsync(async () => {
240 | let newMax = 500;
241 | let res = await swapContract.setIndividualMaximumAmount({individualMaximumAmount: newMax});
242 | expect(res).to.not.equal(false);
243 | expect(await swapContract.individualMaximumAmount()).to.equal(newMax+'');
244 | }));
245 |
246 | it('should do a non atomic swap on the Contract with signature', mochaAsync(async () => {
247 | await forwardTime(5);
248 | let res = await swapContract.swap({tokenAmount : 1, categoryId: 1, maxAllocation: signs[0].allocation, signature: signs[0].signature});
249 | expect(res).to.not.equal(false);
250 | }));
251 |
252 | it('should do a non atomic swap on the Contract after adding address to whitelist', mochaAsync(async () => {
253 | await swapContract.addWhitelistedAddress({address: app.account.getAddress()});
254 | let res = await swapContract.swap({tokenAmount : 1, categoryId: 1, maxAllocation: signs[0].allocation});
255 | expect(res).to.not.equal(false);
256 | }));
257 |
258 |
259 | it('GET - Purchases', mochaAsync(async () => {
260 | let purchases = await swapContract.getPurchaseIds();
261 | expect(purchases.length).to.equal(2);
262 | }));
263 |
264 | it('GET - My Purchases', mochaAsync(async () => {
265 | let purchases = await swapContract.getAddressPurchaseIds({address : app.account.getAddress()});
266 | expect(purchases.length).to.equal(2);
267 | }));
268 |
269 | it('GET - Purchase ID', mochaAsync(async () => {
270 | let purchases = await swapContract.getAddressPurchaseIds({address : app.account.getAddress()});
271 | let purchase = await swapContract.getPurchase({purchaseId : purchases[0]});
272 |
273 | const amountPurchase = Number(purchase.amount).noExponents();
274 |
275 | expect(amountPurchase).to.equal(Number(1).noExponents());
276 | expect(Number(purchase.amountContributed).toFixed(2)).to.equal(Number(tradeValue).noExponents());
277 | expect(purchase.purchaser).to.equal(app.account.getAddress());
278 | expect(purchase.reverted).to.equal(false);
279 | }));
280 |
281 |
282 | it('GET - tokensLeft after Swaps', mochaAsync(async () => {
283 | let tokens = await swapContract.tokensLeft({categoryId: 1});
284 | tokens = Number(tokens).noExponents();
285 | tokensLeft = Number(tokenFundAmount-2).noExponents();
286 | expect(Number(tokens).toFixed(2)).to.equal(Number(tokensLeft).toFixed(2));
287 | }));
288 |
289 | it('GET - soldByCategoryId', mochaAsync(async () => {
290 | let soldByCategoryId = await swapContract.soldByCategoryId({categoryId: 1});
291 | expect(Number(soldByCategoryId)).to.equal(2);
292 | }));
293 |
294 | it('GET - Buyers', mochaAsync(async () => {
295 | let buyers = await swapContract.getBuyers();
296 | expect(buyers.length).to.equal(2);
297 | }));
298 |
299 | it('GET - Fixed Swap is Closed', mochaAsync(async () => {
300 | await forwardTime(4*60);
301 | let res = await swapContract.hasFinalized();
302 | expect(res).to.equal(true);
303 | res = await swapContract.isOpen();
304 | expect(res).to.equal(false);
305 | }));
306 |
307 | it('GET - Purchase ID 2', mochaAsync(async () => {
308 | let purchases = await swapContract.getAddressPurchaseIds({address : app.account.getAddress()});
309 | let purchase = await swapContract.getPurchase({purchaseId : purchases[0]});
310 | expect(purchase.purchaser).to.equal(app.account.getAddress());
311 | expect(purchase.reverted).to.equal(false);
312 |
313 | }));
314 |
315 | it("GET - HasMinimumRaise", mochaAsync(async () => {
316 | let hasMinimumRaise = await swapContract.hasMinimumRaise();
317 | expect(hasMinimumRaise).to.equal(false);
318 | }));
319 |
320 | it("GET - Minimum Raise Not having", mochaAsync(async () => {
321 | let minimumRaise = await swapContract.minimumRaise();
322 | expect(Number(minimumRaise)).to.equal(0);
323 | }));
324 |
325 | it("GET - MinimumReached with no minimum", mochaAsync(async () => {
326 | let minimumReached = await swapContract.minimumReached();
327 | expect(minimumReached).to.equal(true);
328 | }));
329 |
330 | it("GET - MinimumReached with minimum not satisfied", mochaAsync(async () => {
331 | let minimumReached = await swapContract.minimumReached();
332 | expect(minimumReached).to.equal(true);
333 | }));
334 |
335 | it("GET - Allocated tokens", mochaAsync(async () => {
336 | let tokensAllocated = await swapContract.tokensAllocated();
337 | expect(Number(tokensAllocated)).to.equal(2 * tradeValue);
338 | }));
339 |
340 | it("GET - Tokens for sale", mochaAsync(async() => {
341 | let tokensForSale = await swapContract.tokensForSale({categoryId: 1});
342 | expect(Number(tokensForSale)).to.equal(tokenFundAmount);
343 | }));
344 |
345 | it('Remove ETH From Purchases - Admin', mochaAsync(async () => {
346 | let res = await swapContract.withdrawFunds();
347 | expect(res).to.not.equal(false);
348 | }));
349 |
350 | it('Add to blacklist - Admin', mochaAsync(async () => {
351 | let res = await swapContract.addToBlacklist({address: '0xfAadFace3FbD81CE37B0e19c0B65fF4234148132'});
352 | expect(res).to.not.equal(false);
353 | expect(await swapContract.isBlacklisted({address: '0xfAadFace3FbD81CE37B0e19c0B65fF4234148132'})).to.equal(true);
354 | }));
355 |
356 | it('Remove from blacklist - Admin', mochaAsync(async () => {
357 | let res = await swapContract.removeFromBlacklist({address: '0xfAadFace3FbD81CE37B0e19c0B65fF4234148132'});
358 | expect(res).to.not.equal(false);
359 | expect(await swapContract.isBlacklisted({address: '0xfAadFace3FbD81CE37B0e19c0B65fF4234148132'})).to.equal(false);
360 | }));
361 |
362 | it("GET User purchases", mochaAsync( async () => {
363 | let purchases = await swapContract.getUserPurchases({address: app.account.getAddress()});
364 | expect(purchases.length).to.equal(2);
365 | expect(purchases[0].categoryId).to.equal(1);
366 | expect(purchases[0].amount).to.equal(1);
367 | }));
368 |
369 | it("GET User purchase", mochaAsync( async () => {
370 | let purchase = await swapContract.getPurchase({purchaseId: 0});
371 | expect(purchase.categoryId).to.equal(1);
372 | expect(purchase.amount).to.equal(1);
373 | }));
374 |
375 | it("GET Is Claimed category", mochaAsync( async () => {
376 | let claimed = await swapContract.getIsClaimedCategoryForUser({address: app.account.getAddress(), categoryId: 1});
377 | expect(claimed).to.equal(false);
378 | }));
379 | });
380 |
--------------------------------------------------------------------------------
/tests/test/nft-erc20.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 |
3 | import Web3 from "web3";
4 | import chai from 'chai';
5 | import { mochaAsync } from '../utils';
6 | import moment, { isDate } from 'moment';
7 | import Application from '../../src/models';
8 | import { ierc20 } from "../../src/interfaces";
9 | import Numbers from "../../src/utils/Numbers";
10 | import * as ethers from 'ethers';
11 | import Contract from "../../src/models/base/Contract";
12 | import BigNumber from "bignumber.js";
13 |
14 | // const ERC20TokenAddress = '0x7a7748bd6f9bac76c2f3fcb29723227e3376cbb2';
15 | var contractAddress = '0x420751cdeb28679d8e336f2b4d1fc61df7439b5a';
16 | var contractAddressWithMinimumRaise = '0x420751cdeb28679d8e336f2b4d1fc61df7439b5a';
17 | var userPrivateKey = '0x7f76de05082c4d578219ca35a905f8debe922f1f00b99315ebf0706afc97f132';
18 | const expect = chai.expect;
19 | let tokenPurchaseAmount = 0.01;
20 | const tokenFundAmount = 5;
21 | const tradeValue = 0.01;
22 |
23 | context('NFT ERC20 Contract', async () => {
24 | var ERC20TokenAddress;
25 | var swapContract;
26 | var app;
27 | var ethersProvider;
28 | var isFunded, isSaleOpen, tokensLeft, indiviMinAmount, indivMaxAmount, cost, tokensAvailable;
29 | var currentTime;
30 |
31 | var isRealChain = process.env.CHAIN_NAME;
32 |
33 | const getWeb3 = () => {
34 | // Instance Application using ganache
35 | const provider = require("ganache-core").provider({
36 | gasLimit: 10000000000,
37 |
38 | gasPrice: 1,
39 | debug: true,
40 | accounts: [
41 | {
42 | secretKey: userPrivateKey,
43 | balance: 1000000000000000000000
44 | }
45 | ]
46 | });
47 | ethersProvider = new ethers.providers.Web3Provider(provider);
48 | return new Web3(provider);
49 | }
50 |
51 | const sleep = async (time) => {
52 | return new Promise((resolve) => {
53 | setTimeout(resolve, time * 1000)
54 | });
55 | }
56 |
57 | const forwardTime = async (time) => {
58 | if (isRealChain) {
59 | await sleep(time);
60 | currentTime = parseInt(new Date().getTime()/1000);
61 | return;
62 | }
63 | // "Roads? Where we’re going, we don’t need roads."
64 | const date = parseInt(new Date().getTime()/1000);
65 | currentTime = date + await ethersProvider.send('evm_increaseTime', [ time ]);
66 | return await ethersProvider.send('evm_mine');
67 | }
68 |
69 | before(mochaAsync(async () => {
70 | return new Promise(async (resolve) => {
71 | // Instance Application
72 | app = new Application({test : true, mainnet : false, network : isRealChain ? process.env.CHAIN_NAME : 'ETH', web3:
73 | isRealChain ? undefined : getWeb3()
74 | });
75 | app.web3.eth.transactionConfirmationBlocks = 1;
76 |
77 | // Deploy the ERC20
78 | const contract = new Contract(app.web3, ierc20.abi);
79 | const response = await contract.deploy(
80 | app.account,
81 | ierc20.abi,
82 | ierc20.bytecode,
83 | [],
84 | undefined
85 | );
86 | ERC20TokenAddress = response.contractAddress;
87 | resolve();
88 | });
89 | }));
90 |
91 |
92 | it('should deploy Fixed NFT Swap Contract', mochaAsync(async () => {
93 | /* Create Contract */
94 | swapContract = await app.getFixedNFTSwapContract({});
95 | /* Deploy */
96 | let res = await swapContract.deploy({
97 | ERC20TradingAddress: ERC20TokenAddress,
98 | tradingDecimals: 18,
99 | individualMaximumAmount : 0.1,
100 | startDate : moment().add(4, 'minutes'),
101 | endDate : moment().add(8, 'minutes'),
102 | distributionDate: moment().add(9, 'minutes'),
103 | hasWhitelisting : false,
104 | categoryIds: [1, 2],
105 | categoriesSupply: [tokenFundAmount, 3],
106 | categoriesPrice: [tradeValue, 0.02]
107 | });
108 | contractAddress = swapContract.getAddress();
109 | await swapContract.approveSwapERC20({tokenAmount: 1, callback: () => {}});
110 | expect(res).to.not.equal(false);
111 |
112 | expect(await swapContract.getTradingDecimals()).to.equal(18);
113 | }));
114 |
115 | it('should get the correct smart contract version', mochaAsync(async () => {
116 | expect(await swapContract.getSmartContractVersion()).to.equal(3100000);
117 | }));
118 |
119 | it('should get a Fixed Swap Contract From contractAddress - 2.0', mochaAsync(async () => {
120 | /* Get Contract */
121 | swapContract = await app.getFixedNFTSwapContract({contractAddress});
122 | swapContract.__init__();
123 | await swapContract.assertERC20Info();
124 | expect(swapContract.version).to.equal("2.0");
125 | expect(swapContract).to.not.equal(false);
126 | }));
127 |
128 | it('GET - isPreFunded', mochaAsync(async () => {
129 | let res = await swapContract.isPreStart();
130 | expect(res).to.equal(true);
131 | }));
132 |
133 | it('GET - tokensLeft', mochaAsync(async () => {
134 | let tokens = await swapContract.tokensLeft({categoryId: 1});
135 | tokensLeft = tokens;
136 | expect(Number(tokens).noExponents()).to.equal(Number(tokenFundAmount).noExponents());
137 | }));
138 |
139 | it('should edit start Date', mochaAsync(async () => {
140 | let oldStartDate = await swapContract.startDate();
141 |
142 | const newStartDate = new Date(oldStartDate.getTime() + (1 * 1000));
143 | await swapContract.setStartDate({startDate: newStartDate});
144 | let res = await swapContract.startDate();
145 | expect(res.getTime()).to.equal(newStartDate.getTime());
146 |
147 | await swapContract.setStartDate({startDate: oldStartDate});
148 | res = await swapContract.startDate();
149 | expect(res.getTime()).to.equal(oldStartDate.getTime());
150 |
151 | }));
152 |
153 | it('should edit end Date', mochaAsync(async () => {
154 | let oldEndDate = await swapContract.endDate();
155 |
156 | const newEndDate = new Date(oldEndDate.getTime() + (30 * 1000));
157 | await swapContract.setEndDate({endDate: newEndDate});
158 | let res = await swapContract.endDate();
159 | expect(res.getTime()).to.equal(newEndDate.getTime());
160 |
161 | await swapContract.setEndDate({endDate: oldEndDate});
162 | res = await swapContract.endDate();
163 | expect(res.getTime()).to.equal(oldEndDate.getTime());
164 |
165 | }));
166 |
167 | it('should edit distribution date', mochaAsync(async () => {
168 | let oldDistributionDate = await swapContract.distributionDate();
169 | const newDistributionDate = new Date(oldDistributionDate.getTime() + (86400 * 1000));
170 |
171 | await swapContract.setDistributionDate({distributionDate: newDistributionDate});
172 | let res = await swapContract.distributionDate();
173 | expect(res.getTime()).to.equal(newDistributionDate.getTime());
174 |
175 | await swapContract.setDistributionDate({distributionDate: oldDistributionDate});
176 | res = await swapContract.distributionDate();
177 | expect(res.getTime()).to.equal(oldDistributionDate.getTime());
178 | }));
179 |
180 |
181 | it('GET - isSaleOpen - before Start', mochaAsync(async () => {
182 | await forwardTime(4*60);
183 | let res = await swapContract.isOpen();
184 | isSaleOpen = res;
185 | expect(res).to.equal(true);
186 | }));
187 |
188 | it('GET - hasWhitelisting ', mochaAsync(async () => {
189 | let res = await swapContract.hasWhitelisting();
190 | expect(res).to.equal(false);
191 | }));
192 |
193 | it('GET - startDate ', mochaAsync(async () => {
194 | let res = await swapContract.startDate();
195 | res = isDate(res);
196 | expect(res).to.equal(true);
197 | }));
198 |
199 | it('GET - endDate ', mochaAsync(async () => {
200 | let res = await swapContract.endDate();
201 | res = isDate(res);
202 | expect(res).to.equal(true);
203 | }));
204 |
205 | it('GET - category ids ', mochaAsync(async () => {
206 | let res = await swapContract.categoryIds();
207 | expect(Number(res[0])).to.equal(1);
208 | expect(Number(res[1])).to.equal(2);
209 | }));
210 |
211 | it('GET - individualMaximumAmount ', mochaAsync(async () => {
212 | let res = await swapContract.individualMaximumAmount();
213 | indivMaxAmount = res;
214 | expect(Number(res).noExponents()).to.equal(Number(0.1).noExponents());
215 | }));
216 |
217 | it('GET - getCostFromTokens ', mochaAsync(async () => {
218 | let res = await swapContract.getCost({amount : 2, categoryId: 2});
219 | expect(Number(res).noExponents()).to.equal(Number(0.04).noExponents());
220 | }));
221 |
222 | it('check conditions for swap ', mochaAsync(async () => {
223 | let amount = Number(tokenPurchaseAmount).noExponents() > 0 ? true : false;
224 | tokensLeft = Number(tokenPurchaseAmount).noExponents() <= Number(tokensLeft).noExponents() ? true : false;
225 | indivMaxAmount = Number(tokenPurchaseAmount).noExponents() <= Number(indivMaxAmount).noExponents() ? true : false;
226 | expect(isSaleOpen).to.equal(true);
227 | expect(amount).to.equal(true);
228 | expect(tokensLeft).to.equal(true);
229 | expect(indivMaxAmount).to.equal(true);
230 | }));
231 |
232 | it('GET - hasStarted', mochaAsync(async () => {
233 | await forwardTime(1*60);
234 | let res = await swapContract.hasStarted();
235 | expect(res).to.equal(true);
236 | }));
237 |
238 | it('GET - isSaleOpen', mochaAsync(async () => {
239 | let res = await swapContract.isOpen();
240 | expect(res).to.equal(true);
241 | }));
242 |
243 | it('Edit max allocation - Admin', mochaAsync(async () => {
244 | let newMax = 500;
245 | let res = await swapContract.setIndividualMaximumAmount({individualMaximumAmount: newMax});
246 | expect(res).to.not.equal(false);
247 | expect(await swapContract.individualMaximumAmount()).to.equal(newMax+'');
248 | }));
249 |
250 | it('should do a non atomic swap on the Contract', mochaAsync(async () => {
251 | await forwardTime(5);
252 | let res = await swapContract.swap({tokenAmount : 2, categoryId: 1, maxAllocation: 0});
253 | expect(res).to.not.equal(false);
254 | res = await swapContract.swap({tokenAmount : 1, categoryId: 1, maxAllocation: 0});
255 | expect(res).to.not.equal(false);
256 | }));
257 |
258 | it('GET - Purchases', mochaAsync(async () => {
259 | let purchases = await swapContract.getPurchaseIds();
260 | expect(purchases.length).to.equal(2);
261 | }));
262 |
263 | it('GET - My Purchases', mochaAsync(async () => {
264 | let purchases = await swapContract.getAddressPurchaseIds({address : app.account.getAddress()});
265 | expect(purchases.length).to.equal(2);
266 | }));
267 |
268 | it('GET - Purchase ID', mochaAsync(async () => {
269 | let purchases = await swapContract.getAddressPurchaseIds({address : app.account.getAddress()});
270 | let purchase = await swapContract.getPurchase({purchaseId : purchases[0]});
271 |
272 | const amountPurchase = Number(purchase.amount).noExponents();
273 |
274 | expect(amountPurchase).to.equal(Number(2).noExponents());
275 | expect(Number(purchase.amountContributed).toFixed(2)).to.equal(Number(tradeValue * 2).noExponents());
276 | expect(purchase.purchaser).to.equal(app.account.getAddress());
277 | expect(purchase.reverted).to.equal(false);
278 | }));
279 |
280 |
281 | it('GET - tokensLeft after Swap', mochaAsync(async () => {
282 | let tokens = await swapContract.tokensLeft({categoryId: 1});
283 | tokens = Number(tokens).noExponents();
284 | tokensLeft = Number(tokenFundAmount-3).noExponents();
285 | expect(Number(tokens).toFixed(2)).to.equal(Number(tokensLeft).toFixed(2));
286 | }));
287 |
288 | it('GET - soldByCategoryId', mochaAsync(async () => {
289 | let soldByCategoryId = await swapContract.soldByCategoryId({categoryId: 1});
290 | expect(Number(soldByCategoryId)).to.equal(3);
291 | }));
292 |
293 | it('GET - Buyers', mochaAsync(async () => {
294 | let buyers = await swapContract.getBuyers();
295 | expect(buyers.length).to.equal(2);
296 | }));
297 |
298 | it('GET - Fixed Swap is Closed', mochaAsync(async () => {
299 | await forwardTime(4*60);
300 | let res = await swapContract.hasFinalized();
301 | expect(res).to.equal(true);
302 | res = await swapContract.isOpen();
303 | expect(res).to.equal(false);
304 | }));
305 |
306 | it('GET - Purchase ID 2', mochaAsync(async () => {
307 | let purchases = await swapContract.getAddressPurchaseIds({address : app.account.getAddress()});
308 | let purchase = await swapContract.getPurchase({purchaseId : purchases[0]});
309 | expect(purchase.purchaser).to.equal(app.account.getAddress());
310 | expect(purchase.reverted).to.equal(false);
311 |
312 | }));
313 |
314 | it("GET - HasMinimumRaise", mochaAsync(async () => {
315 | let hasMinimumRaise = await swapContract.hasMinimumRaise();
316 | expect(hasMinimumRaise).to.equal(false);
317 | }));
318 |
319 |
320 | it("GET - Minimum Raise Not having", mochaAsync(async () => {
321 | let minimumRaise = await swapContract.minimumRaise();
322 | expect(Number(minimumRaise)).to.equal(0);
323 | }));
324 |
325 | it("GET - MinimumReached with no minimum", mochaAsync(async () => {
326 | let minimumReached = await swapContract.minimumReached();
327 | expect(minimumReached).to.equal(true);
328 | }));
329 |
330 | it("GET - MinimumReached with minimum not satisfied", mochaAsync(async () => {
331 | let minimumReached = await swapContract.minimumReached();
332 | expect(minimumReached).to.equal(true);
333 | }));
334 |
335 | it("GET - Allocated tokens", mochaAsync(async () => {
336 | let tokensAllocated = await swapContract.tokensAllocated();
337 | expect(Number(tokensAllocated)).to.equal(3 * tradeValue);
338 | }));
339 |
340 | it("GET - Tokens for sale", mochaAsync(async() => {
341 | let tokensForSale = await swapContract.tokensForSale({categoryId: 1});
342 | expect(Number(tokensForSale)).to.equal(tokenFundAmount);
343 | }));
344 |
345 | it('Remove ETH From Purchases - Admin', mochaAsync(async () => {
346 | let res = await swapContract.withdrawFunds();
347 | expect(res).to.not.equal(false);
348 | }));
349 |
350 | it('Add to blacklist - Admin', mochaAsync(async () => {
351 | let res = await swapContract.addToBlacklist({address: '0xfAadFace3FbD81CE37B0e19c0B65fF4234148132'});
352 | expect(res).to.not.equal(false);
353 | expect(await swapContract.isBlacklisted({address: '0xfAadFace3FbD81CE37B0e19c0B65fF4234148132'})).to.equal(true);
354 | }));
355 |
356 | it('Remove from blacklist - Admin', mochaAsync(async () => {
357 | let res = await swapContract.removeFromBlacklist({address: '0xfAadFace3FbD81CE37B0e19c0B65fF4234148132'});
358 | expect(res).to.not.equal(false);
359 | expect(await swapContract.isBlacklisted({address: '0xfAadFace3FbD81CE37B0e19c0B65fF4234148132'})).to.equal(false);
360 | }));
361 |
362 | it("GET User purchases", mochaAsync( async () => {
363 | let purchases = await swapContract.getUserPurchases({address: app.account.getAddress()});
364 | expect(purchases.length).to.equal(2);
365 | expect(purchases[0].categoryId).to.equal(1);
366 | expect(purchases[0].amount).to.equal(2);
367 | }));
368 |
369 | it("GET User purchase", mochaAsync( async () => {
370 | let purchase = await swapContract.getPurchase({purchaseId: 0});
371 | expect(purchase.categoryId).to.equal(1);
372 | expect(purchase.amount).to.equal(2);
373 | }));
374 |
375 | it("GET Is Claimed category", mochaAsync( async () => {
376 | let claimed = await swapContract.getIsClaimedCategoryForUser({address: app.account.getAddress(), categoryId: 1});
377 | expect(claimed).to.equal(false);
378 | }));
379 | });
380 |
--------------------------------------------------------------------------------
/docs/BASE_SWAP.md:
--------------------------------------------------------------------------------
1 | ## Classes
2 |
3 | BooleanVerify if swap has whitelisting
13 |BooleanVerify if address is whitelisted
16 |adminModifies if the pool has whitelisting or not
19 |add WhiteListed Address
22 |remove WhiteListed Address
25 |Set the public address of the signer
28 |stringGet the public address of the signer
31 |Array | AddressGet Whitelisted Addresses
34 |Get Balance of Contract
37 |Remove Tokens from other ERC20 Address (in case of accident)
40 |IntegerGet Minimum Raise amount for Token Sale
43 |BooleanSee if hasMinimumRaise
46 |BooleanSee if minimumRaise was Reached
49 |IntegerGet Total tokens spent in the contract, therefore the tokens bought until now
52 |Safe Pull all tokens & ETH
55 |Withdraw all funds from tokens sold
58 |IntegerGet Total funds raised to be withdrawn by the admin
61 |BooleanVerify if the admin already reemeded unsold tokens
64 |Reedem Ethereum from sale that did not achieve minimum goal
67 |adminModifies the max allocation
70 |IntegerGet Individual Maximum Amount for each address
73 |BooleanVerify if the Admin has approved the pool to use receive the tokens for sale
76 |Verify if it is approved to invest
79 |Approve the investor to use approved tokens for the sale
82 |AddressGet Trading Address if ERC20
85 |BooleanVerify if Token Sale is against Ethereum
88 |IntegerGet Trading Decimals (18 if isETHTrade, X if not)
91 |DateGet Start Date of Change
94 |DateGet End Date of Change
97 |adminModifies the end date for the pool
100 |adminModifies the start date for the pool
103 |BooleanTo see if contract was finalized
106 |BooleanVerify if the Token Sale is Open for Swap
109 |BooleanVerify if the Token Sale has started the Swap
112 |BooleanVerify if the Token Sale has finalized, if the current date is after endDate
115 |BooleanVerify if the Token Sale in not open yet
118 |Adds an address to the blacklist
121 |Removes an address from the blacklist
124 |booleanReturns true if the address is in the blacklist
127 |booleanReturns if the contract is paused or not
130 |adminPause Contract
133 |adminUnpause Contract
136 |Returns the version of the smart contract that is currently inside psjs
139 |Web3 | |
155 | | contractAddress | Address | ? (opt) |
156 |
157 |
158 |
159 | ## hasWhitelisting() ⇒ Boolean
160 | Verify if swap has whitelisting
161 |
162 | **Kind**: global function
163 |
164 |
165 | ## isWhitelisted(address) ⇒ Boolean
166 | Verify if address is whitelisted
167 |
168 | **Kind**: global function
169 |
170 | | Param | Type |
171 | | --- | --- |
172 | | address | string |
173 |
174 |
175 |
176 | ## setHasWhitelisting(hasWhitelist) ⇒ admin
177 | Modifies if the pool has whitelisting or not
178 |
179 | **Kind**: global function
180 |
181 | | Param | Type |
182 | | --- | --- |
183 | | hasWhitelist | boolean |
184 |
185 |
186 |
187 | ## addWhitelistedAddress(address)
188 | add WhiteListed Address
189 |
190 | **Kind**: global function
191 |
192 | | Param | Type |
193 | | --- | --- |
194 | | address | Address |
195 |
196 |
197 |
198 | ## removeWhitelistedAddress(addresses, index)
199 | remove WhiteListed Address
200 |
201 | **Kind**: global function
202 |
203 | | Param | Type |
204 | | --- | --- |
205 | | addresses | Array \| Addresses |
206 | | index | Integer |
207 |
208 |
209 |
210 | ## setSignerPublicAddress(address)
211 | Set the public address of the signer
212 |
213 | **Kind**: global function
214 |
215 | | Param | Type |
216 | | --- | --- |
217 | | address | string |
218 |
219 |
220 |
221 | ## signerPublicAddress() ⇒ string
222 | Get the public address of the signer
223 |
224 | **Kind**: global function
225 | **Returns**: string - address
226 |
227 |
228 | ## getWhiteListedAddresses() ⇒ Array \| Address
229 | Get Whitelisted Addresses
230 |
231 | **Kind**: global function
232 | **Returns**: Array \| Address - addresses
233 |
234 |
235 | ## getBalance(Balance)
236 | Get Balance of Contract
237 |
238 | **Kind**: global function
239 |
240 | | Param | Type |
241 | | --- | --- |
242 | | Balance | Integer |
243 |
244 |
245 |
246 | ## removeOtherERC20Tokens(tokenAddress, toAddress)
247 | Remove Tokens from other ERC20 Address (in case of accident)
248 |
249 | **Kind**: global function
250 |
251 | | Param | Type |
252 | | --- | --- |
253 | | tokenAddress | Address |
254 | | toAddress | Address |
255 |
256 |
257 |
258 | ## minimumRaise() ⇒ Integer
259 | Get Minimum Raise amount for Token Sale
260 |
261 | **Kind**: global function
262 | **Returns**: Integer - Amount in Tokens
263 |
264 |
265 | ## hasMinimumRaise() ⇒ Boolean
266 | See if hasMinimumRaise
267 |
268 | **Kind**: global function
269 |
270 |
271 | ## minimumReached() ⇒ Boolean
272 | See if minimumRaise was Reached
273 |
274 | **Kind**: global function
275 |
276 |
277 | ## tokensAllocated() ⇒ Integer
278 | Get Total tokens spent in the contract, therefore the tokens bought until now
279 |
280 | **Kind**: global function
281 | **Returns**: Integer - Amount in Tokens
282 |
283 |
284 | ## safePull()
285 | Safe Pull all tokens & ETH
286 |
287 | **Kind**: global function
288 |
289 |
290 | ## withdrawFunds()
291 | Withdraw all funds from tokens sold
292 |
293 | **Kind**: global function
294 |
295 |
296 | ## withdrawableFunds() ⇒ Integer
297 | Get Total funds raised to be withdrawn by the admin
298 |
299 | **Kind**: global function
300 | **Returns**: Integer - Amount in ETH
301 |
302 |
303 | ## wereUnsoldTokensReedemed() ⇒ Boolean
304 | Verify if the admin already reemeded unsold tokens
305 |
306 | **Kind**: global function
307 |
308 |
309 | ## redeemGivenMinimumGoalNotAchieved(purchaseId)
310 | Reedem Ethereum from sale that did not achieve minimum goal
311 |
312 | **Kind**: global function
313 |
314 | | Param | Type |
315 | | --- | --- |
316 | | purchaseId | Integer |
317 |
318 |
319 |
320 | ## setIndividualMaximumAmount(individualMaximumAmount) ⇒ admin
321 | Modifies the max allocation
322 |
323 | **Kind**: global function
324 |
325 | | Param | Type |
326 | | --- | --- |
327 | | individualMaximumAmount | Integer |
328 |
329 |
330 |
331 | ## individualMaximumAmount() ⇒ Integer
332 | Get Individual Maximum Amount for each address
333 |
334 | **Kind**: global function
335 |
336 |
337 | ## isApproved(tokenAmount, address) ⇒ Boolean
338 | Verify if the Admin has approved the pool to use receive the tokens for sale
339 |
340 | **Kind**: global function
341 |
342 | | Param | Type |
343 | | --- | --- |
344 | | tokenAmount | Integer |
345 | | address | Address |
346 |
347 |
348 |
349 | ## isApprovedSwapERC20(tokenAmount, address)
350 | Verify if it is approved to invest
351 |
352 | **Kind**: global function
353 |
354 | | Param | Type |
355 | | --- | --- |
356 | | tokenAmount | Integer |
357 | | address | Address |
358 |
359 |
360 |
361 | ## approveSwapERC20(tokenAmount)
362 | Approve the investor to use approved tokens for the sale
363 |
364 | **Kind**: global function
365 |
366 | | Param | Type |
367 | | --- | --- |
368 | | tokenAmount | Integer |
369 |
370 |
371 |
372 | ## getTradingERC20Address() ⇒ Address
373 | Get Trading Address if ERC20
374 |
375 | **Kind**: global function
376 |
377 |
378 | ## isETHTrade() ⇒ Boolean
379 | Verify if Token Sale is against Ethereum
380 |
381 | **Kind**: global function
382 |
383 |
384 | ## getTradingDecimals() ⇒ Integer
385 | Get Trading Decimals (18 if isETHTrade, X if not)
386 |
387 | **Kind**: global function
388 |
389 |
390 | ## startDate() ⇒ Date
391 | Get Start Date of Change
392 |
393 | **Kind**: global function
394 |
395 |
396 | ## endDate() ⇒ Date
397 | Get End Date of Change
398 |
399 | **Kind**: global function
400 |
401 |
402 | ## setEndDate(endDate) ⇒ admin
403 | Modifies the end date for the pool
404 |
405 | **Kind**: global function
406 |
407 | | Param | Type |
408 | | --- | --- |
409 | | endDate | Date |
410 |
411 |
412 |
413 | ## setStartDate(startDate) ⇒ admin
414 | Modifies the start date for the pool
415 |
416 | **Kind**: global function
417 |
418 | | Param | Type |
419 | | --- | --- |
420 | | startDate | Date |
421 |
422 |
423 |
424 | ## isFinalized() ⇒ Boolean
425 | To see if contract was finalized
426 |
427 | **Kind**: global function
428 |
429 |
430 | ## isOpen() ⇒ Boolean
431 | Verify if the Token Sale is Open for Swap
432 |
433 | **Kind**: global function
434 |
435 |
436 | ## hasStarted() ⇒ Boolean
437 | Verify if the Token Sale has started the Swap
438 |
439 | **Kind**: global function
440 |
441 |
442 | ## hasFinalized() ⇒ Boolean
443 | Verify if the Token Sale has finalized, if the current date is after endDate
444 |
445 | **Kind**: global function
446 |
447 |
448 | ## isPreStart() ⇒ Boolean
449 | Verify if the Token Sale in not open yet
450 |
451 | **Kind**: global function
452 |
453 |
454 | ## addToBlacklist(address)
455 | Adds an address to the blacklist
456 |
457 | **Kind**: global function
458 |
459 | | Param | Type |
460 | | --- | --- |
461 | | address | string |
462 |
463 |
464 |
465 | ## removeFromBlacklist(address)
466 | Removes an address from the blacklist
467 |
468 | **Kind**: global function
469 |
470 | | Param | Type |
471 | | --- | --- |
472 | | address | string |
473 |
474 |
475 |
476 | ## isBlackListed(address) ⇒ boolean
477 | Returns true if the address is in the blacklist
478 |
479 | **Kind**: global function
480 | **Returns**: boolean - isBlackListed
481 |
482 | | Param | Type |
483 | | --- | --- |
484 | | address | string |
485 |
486 |
487 |
488 | ## isPaused() ⇒ boolean
489 | Returns if the contract is paused or not
490 |
491 | **Kind**: global function
492 |
493 |
494 | ## pauseContract() ⇒ admin
495 | Pause Contract
496 |
497 | **Kind**: global function
498 |
499 |
500 | ## unpauseContract() ⇒ admin
501 | Unpause Contract
502 |
503 | **Kind**: global function
504 |
505 |
506 | ## getSmartContractVersion(Address)
507 | Returns the version of the smart contract that is currently inside psjs
508 |
509 | **Kind**: global function
510 |
511 | | Param | Type |
512 | | --- | --- |
513 | | Address | Address |
514 |
515 |
--------------------------------------------------------------------------------