├── test ├── .gitkeep └── facutoken.test.js ├── .eslintrc.json ├── public ├── favicon.ico └── vercel.svg ├── next.config.js ├── next-env.d.ts ├── pages ├── _app.tsx ├── api │ └── hello.ts └── index.tsx ├── contracts ├── FacuToken.sol ├── Migrations.sol └── FacuTokenSale.sol ├── styles ├── globals.css └── Home.module.css ├── migrations └── 1_initial_migration.js ├── .gitignore ├── tsconfig.json ├── package.json ├── README.md ├── src └── funcs.js └── truffle-config.js /test/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/facundocarballo/FacuTokenICO/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | } 5 | 6 | module.exports = nextConfig 7 | -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import type { AppProps } from 'next/app' 2 | import { ChakraProvider } from '@chakra-ui/react' 3 | 4 | function MyApp({ Component, pageProps }: AppProps) { 5 | return 6 | 7 | 8 | } 9 | 10 | export default MyApp 11 | -------------------------------------------------------------------------------- /contracts/FacuToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import '@openzeppelin/contracts/token/ERC20/ERC20.sol'; 6 | 7 | contract FacuToken is ERC20 { 8 | constructor() ERC20("FacuToken", "FT") { 9 | _mint(msg.sender, 1000000000 * 10**18); 10 | } 11 | } -------------------------------------------------------------------------------- /styles/globals.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | padding: 0; 4 | margin: 0; 5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 7 | } 8 | 9 | a { 10 | color: inherit; 11 | text-decoration: none; 12 | } 13 | 14 | * { 15 | box-sizing: border-box; 16 | } 17 | -------------------------------------------------------------------------------- /pages/api/hello.ts: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | import type { NextApiRequest, NextApiResponse } from 'next' 3 | 4 | type Data = { 5 | name: string 6 | } 7 | 8 | export default function handler( 9 | req: NextApiRequest, 10 | res: NextApiResponse 11 | ) { 12 | res.status(200).json({ name: 'John Doe' }) 13 | } 14 | -------------------------------------------------------------------------------- /test/facutoken.test.js: -------------------------------------------------------------------------------- 1 | const FacuToken = artifacts.require('FacuToken'); 2 | const FacuTokenSale = artifacts.require('FacuTokenSale'); 3 | 4 | contract('FacuToken', () => { 5 | const initAmount = BigInt(750000000 * 10**18); 6 | it('Se inicializó el contrato con los valores apropiados', () => { 7 | FacuToken.deployed().then((FT) => { 8 | FacuTokenSale.deployed().then((FTS) => { 9 | FT.transfer(FTS.address, initAmount) 10 | }); 11 | }) 12 | }); 13 | }); -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.4.22 <0.9.0; 3 | 4 | contract Migrations { 5 | address public owner = msg.sender; 6 | uint public last_completed_migration; 7 | 8 | modifier restricted() { 9 | require( 10 | msg.sender == owner, 11 | "This function is restricted to the contract's owner" 12 | ); 13 | _; 14 | } 15 | 16 | function setCompleted(uint completed) public restricted { 17 | last_completed_migration = completed; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const FacuToken = artifacts.require("./facuTokenICO/FacuToken"); 2 | const FacuTokenSale = artifacts.require("./facuTokenICO/FacuTokenSale"); 3 | 4 | module.exports = function (deployer) { 5 | deployer.deploy(FacuToken).then(() => { 6 | deployer.deploy(FacuTokenSale, FacuToken.address); 7 | }); 8 | // If this code doesn't work, to deploy the contract token sale 9 | // we have to copy the contract tokenn address and paste here 10 | // deployer.deploy(FacuTokenSale, "0xBC0484Ab69982738BcD5FA45947Fc9203551bB7c"); 11 | }; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | 4 | # dependencies 5 | /node_modules 6 | /.pnp 7 | .pnp.js 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env.local 30 | .env.development.local 31 | .env.test.local 32 | .env.production.local 33 | 34 | # vercel 35 | .vercel 36 | 37 | # typescript 38 | *.tsbuildinfo 39 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true 17 | }, 18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 19 | "exclude": ["node_modules"] 20 | } 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "facu-coin", 3 | "private": true, 4 | "scripts": { 5 | "dev": "next dev", 6 | "build": "next build", 7 | "start": "next start", 8 | "lint": "next lint" 9 | }, 10 | "dependencies": { 11 | "@chainlink/contracts": "^0.3.1", 12 | "@chakra-ui/icons": "^1.1.1", 13 | "@chakra-ui/react": "^1.7.4", 14 | "@emotion/react": "^11.7.1", 15 | "@emotion/styled": "^11.6.0", 16 | "@openzeppelin/contracts": "^4.4.2", 17 | "@truffle/contract": "^4.4.5", 18 | "@truffle/hdwallet-provider": "^2.0.1", 19 | "framer-motion": "^4.1.17", 20 | "next": "^10.0.1", 21 | "react": "17.0.2", 22 | "react-dom": "17.0.2" 23 | }, 24 | "devDependencies": { 25 | "@types/node": "17.0.10", 26 | "@types/react": "17.0.38", 27 | "eslint": "8.7.0", 28 | "eslint-config-next": "^0.2.4", 29 | "typescript": "4.5.5" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | ``` 12 | 13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 14 | 15 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. 16 | 17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. 18 | 19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy on Vercel 31 | 32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 33 | 34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 35 | -------------------------------------------------------------------------------- /styles/Home.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | padding: 0 2rem; 3 | } 4 | 5 | .main { 6 | min-height: 100vh; 7 | padding: 4rem 0; 8 | flex: 1; 9 | display: flex; 10 | flex-direction: column; 11 | justify-content: center; 12 | align-items: center; 13 | } 14 | 15 | .footer { 16 | display: flex; 17 | flex: 1; 18 | padding: 2rem 0; 19 | border-top: 1px solid #eaeaea; 20 | justify-content: center; 21 | align-items: center; 22 | } 23 | 24 | .footer a { 25 | display: flex; 26 | justify-content: center; 27 | align-items: center; 28 | flex-grow: 1; 29 | } 30 | 31 | .title a { 32 | color: #0070f3; 33 | text-decoration: none; 34 | } 35 | 36 | .title a:hover, 37 | .title a:focus, 38 | .title a:active { 39 | text-decoration: underline; 40 | } 41 | 42 | .title { 43 | margin: 0; 44 | line-height: 1.15; 45 | font-size: 4rem; 46 | } 47 | 48 | .title, 49 | .description { 50 | text-align: center; 51 | } 52 | 53 | .description { 54 | margin: 4rem 0; 55 | line-height: 1.5; 56 | font-size: 1.5rem; 57 | } 58 | 59 | .code { 60 | background: #fafafa; 61 | border-radius: 5px; 62 | padding: 0.75rem; 63 | font-size: 1.1rem; 64 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, 65 | Bitstream Vera Sans Mono, Courier New, monospace; 66 | } 67 | 68 | .grid { 69 | display: flex; 70 | align-items: center; 71 | justify-content: center; 72 | flex-wrap: wrap; 73 | max-width: 800px; 74 | } 75 | 76 | .card { 77 | margin: 1rem; 78 | padding: 1.5rem; 79 | text-align: left; 80 | color: inherit; 81 | text-decoration: none; 82 | border: 1px solid #eaeaea; 83 | border-radius: 10px; 84 | transition: color 0.15s ease, border-color 0.15s ease; 85 | max-width: 300px; 86 | } 87 | 88 | .card:hover, 89 | .card:focus, 90 | .card:active { 91 | color: #0070f3; 92 | border-color: #0070f3; 93 | } 94 | 95 | .card h2 { 96 | margin: 0 0 1rem 0; 97 | font-size: 1.5rem; 98 | } 99 | 100 | .card p { 101 | margin: 0; 102 | font-size: 1.25rem; 103 | line-height: 1.5; 104 | } 105 | 106 | .logo { 107 | height: 1em; 108 | margin-left: 0.5rem; 109 | } 110 | 111 | @media (max-width: 600px) { 112 | .grid { 113 | width: 100%; 114 | flex-direction: column; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /contracts/FacuTokenSale.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import './FacuToken.sol'; 6 | import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; 7 | 8 | contract FacuTokenSale { 9 | address payable public admin; 10 | address payable private ethFunds = payable(0xD35c657500a074A03E367d8EC2f939fada73f839); 11 | FacuToken public token; 12 | uint256 public tokensSold; 13 | int public tokenPriceUSD; 14 | AggregatorV3Interface internal priceFeed; 15 | 16 | uint256 public transactionCount; 17 | 18 | event Sell(address _buyer, uint256 _amount); 19 | 20 | struct Transaction { 21 | address buyer; 22 | uint256 amount; 23 | } 24 | 25 | mapping(uint256 => Transaction) public transaction; 26 | 27 | constructor(FacuToken _token) { 28 | priceFeed = AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331); 29 | tokenPriceUSD = 50; 30 | token = _token; 31 | admin = payable(msg.sender); 32 | } 33 | 34 | function getETHPrice() public view returns(int) { 35 | (, int price, , , ) = priceFeed.latestRoundData(); 36 | return (price / 10**8); 37 | } 38 | 39 | function facuTokenPriceInETH() public view returns(int) { 40 | int ethPrice = getETHPrice(); 41 | return tokenPriceUSD / ethPrice; 42 | } 43 | 44 | function buyToken(uint256 _amount) public payable { 45 | int facuTokenPriceETH = facuTokenPriceInETH(); 46 | // Check that the buyer sends the enough ETH 47 | require(int(msg.value) >= facuTokenPriceETH * int(_amount)); 48 | // Check that the sale contract provides the enough ETH to make this transaction. 49 | require(token.balanceOf(address(this)) >= _amount); 50 | // Make the transaction inside of the require 51 | // transfer returns a boolean value. 52 | require(token.transfer(msg.sender, _amount)); 53 | // Transfer the ETH of the buyer to us 54 | ethFunds.transfer(msg.value); 55 | // Increase the amount of tokens sold 56 | tokensSold += _amount; 57 | // Increase the amount of transactions 58 | transaction[transactionCount] = Transaction(msg.sender, _amount); 59 | transactionCount++; 60 | // Emit the Sell event 61 | emit Sell(msg.sender, _amount); 62 | } 63 | 64 | function endSale() public { 65 | require(msg.sender == admin); 66 | // Return the tokens that were left inside of the sale contract 67 | uint256 amount = token.balanceOf(address(this)); 68 | require(token.transfer(admin, amount)); 69 | selfdestruct(payable(admin)); 70 | } 71 | 72 | } -------------------------------------------------------------------------------- /src/funcs.js: -------------------------------------------------------------------------------- 1 | import Web3 from 'web3' 2 | import FacuToken from '../build/contracts/FacuToken.json'; 3 | import FacuTokenSale from '../build/contracts/FacuTokenSale.json'; 4 | const contract = require('@truffle/contract'); 5 | 6 | export const load = async() => { 7 | await loadWeb3(); 8 | const account = await loadAccount(); 9 | const { contractFT, contractFTS } = await loadContracts(); 10 | const { ethFunds, transactionCount, tokensSold, ethPriceN, transactions } = await loadVariables(contractFTS); 11 | const bal = await contractFT.balanceOf(account); 12 | const myFT = bal / 10**18; 13 | return { account, contractFTS, contractFT, ethFunds, transactionCount, tokensSold, ethPriceN, transactions, myFT }; 14 | }; 15 | 16 | 17 | const loadVariables = async (contractFTS) => { 18 | const admin = "0xf361eC759e85107Eca4C743e59E624cC4382745d"; 19 | const ethFunds = await window.web3.eth.getBalance(admin); 20 | 21 | const tCount = await contractFTS.transactionCount(); 22 | const transactionCount = tCount.toNumber(); 23 | 24 | const tSold = await contractFTS.tokensSold(); 25 | const tokensSold = window.web3.utils.fromWei(tSold, 'ether'); 26 | 27 | const ethPrice = await contractFTS.getETHPrice(); 28 | const ethPriceN = ethPrice.toNumber(); 29 | 30 | // Make this strange for loop to get the last 10 transactions. 31 | const transactions = []; 32 | var j = 0; 33 | for (var i = transactionCount - 1; i >= 0 && j < 10; i--) { 34 | const t = await contractFTS.transaction(i); 35 | j++; 36 | transactions.push(t); 37 | } 38 | 39 | return { ethFunds, transactionCount, tokensSold, ethPriceN, transactions }; 40 | }; 41 | 42 | const loadContracts = async () => { 43 | const FTContract = contract(FacuToken); 44 | FTContract.setProvider(window.web3.currentProvider); 45 | const FTSContract = contract(FacuTokenSale); 46 | FTSContract.setProvider(window.web3.currentProvider); 47 | 48 | const contractFT = await FTContract.deployed(); 49 | const contractFTS = await FTSContract.deployed(); 50 | 51 | return { contractFT, contractFTS }; 52 | }; 53 | 54 | const loadAccount = async () => { 55 | const account = window.web3.eth.getCoinbase(); 56 | return account; 57 | }; 58 | 59 | const loadWeb3 = async() => { 60 | if (window.ethereum) { 61 | window.web3 = new Web3(ethereum); 62 | try { 63 | // Request account access if needed 64 | await ethereum.enable(); 65 | // Acccounts now exposed 66 | web3.eth.sendTransaction({/* ... */}); 67 | } catch (error) { 68 | // User denied account access... 69 | } 70 | } 71 | // Legacy dapp browsers... 72 | else if (window.web3) { 73 | window.web3 = new Web3(web3.currentProvider); 74 | // Acccounts always exposed 75 | web3.eth.sendTransaction({/* ... */}); 76 | } 77 | // Non-dapp browsers... 78 | else { 79 | console.log('Non-Ethereum browser detected. You should consider trying MetaMask!'); 80 | } 81 | }; -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | const HDWalletProvider = require('@truffle/hdwallet-provider'); 2 | const privateKeys = [ 3 | 'af8b039bad5aba2faa98e898a66811a1cf6ef6821fbe91b655ce488f605de90c', 4 | '7a33b8a9f7e6021ce71b04fd5a46a9ac17d1d4a3af098919ac291633f078ec17' 5 | ]; 6 | /** 7 | * Use this file to configure your truffle project. It's seeded with some 8 | * common settings for different networks and features like migrations, 9 | * compilation and testing. Uncomment the ones you need or modify 10 | * them to suit your project as necessary. 11 | * 12 | * More information about configuration can be found at: 13 | * 14 | * trufflesuite.com/docs/advanced/configuration 15 | * 16 | * To deploy via Infura you'll need a wallet provider (like @truffle/hdwallet-provider) 17 | * to sign your transactions before they're sent to a remote public node. Infura accounts 18 | * are available for free at: infura.io/register. 19 | * 20 | * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate 21 | * public/private key pairs. If you're publishing your code to GitHub make sure you load this 22 | * phrase from a file you've .gitignored so it doesn't accidentally become public. 23 | * 24 | */ 25 | 26 | // const HDWalletProvider = require('@truffle/hdwallet-provider'); 27 | // 28 | // const fs = require('fs'); 29 | // const mnemonic = fs.readFileSync(".secret").toString().trim(); 30 | 31 | module.exports = { 32 | /** 33 | * Networks define how you connect to your ethereum client and let you set the 34 | * defaults web3 uses to send transactions. If you don't specify one truffle 35 | * will spin up a development blockchain for you on port 9545 when you 36 | * run `develop` or `test`. You can ask a truffle command to use a specific 37 | * network from the command line, e.g 38 | * 39 | * $ truffle test --network 40 | */ 41 | 42 | networks: { 43 | // Useful for testing. The `development` name is special - truffle uses it by default 44 | // if it's defined here and no other network is specified at the command line. 45 | // You should run a client (like ganache-cli, geth or parity) in a separate terminal 46 | // tab if you use this network and you must also set the `host`, `port` and `network_id` 47 | // options below to some value. 48 | // 49 | // development: { 50 | // host: "127.0.0.1", // Localhost (default: none) 51 | // port: 7545, // Standard Ethereum port (default: none) 52 | // network_id: "*", // Any network (default: none) 53 | // }, 54 | // Another network with more advanced options... 55 | // advanced: { 56 | // port: 8777, // Custom port 57 | // network_id: 1342, // Custom network 58 | // gas: 8500000, // Gas sent with each transaction (default: ~6700000) 59 | // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) 60 | // from:
, // Account to send txs from (default: accounts[0]) 61 | // websocket: true // Enable EventEmitter interface for web3 (default: false) 62 | // }, 63 | // Useful for deploying to a public network. 64 | // NB: It's important to wrap the provider as a function. 65 | kovan: { 66 | provider: () => new HDWalletProvider({ 67 | privateKeys: privateKeys, 68 | providerOrUrl: 'https://kovan.infura.io/v3/9bf23283254d41039174a045b1d0e743', 69 | numberOfAddresses: 2 70 | }), 71 | network_id: 42, // Kovan's id 72 | gas: 5500000, // Ropsten has a lower block limit than mainnet 73 | confirmations: 2, // # of confs to wait between deployments. (default: 0) 74 | timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) 75 | skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) 76 | }, 77 | // Useful for private networks 78 | // private: { 79 | // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), 80 | // network_id: 2111, // This network is yours, in the cloud. 81 | // production: true // Treats this network as if it was a public net. (default: false) 82 | // } 83 | }, 84 | 85 | // Set default mocha options here, use special reporters etc. 86 | mocha: { 87 | // timeout: 100000 88 | }, 89 | 90 | // Configure your compilers 91 | compilers: { 92 | solc: { 93 | version: "0.8.11", // Fetch exact version from solc-bin (default: truffle's version) 94 | // docker: true, // Use "0.5.1" you've installed locally with docker (default: false) 95 | settings: { // See the solidity docs for advice about optimization and evmVersion 96 | optimizer: { 97 | enabled: true, 98 | runs: 200 99 | }, 100 | // evmVersion: "byzantium" 101 | } 102 | } 103 | }, 104 | 105 | // Truffle DB is currently disabled by default; to enable it, change enabled: 106 | // false to enabled: true. The default storage location can also be 107 | // overridden by specifying the adapter settings, as shown in the commented code below. 108 | // 109 | // NOTE: It is not possible to migrate your contracts to truffle DB and you should 110 | // make a backup of your artifacts to a safe location before enabling this feature. 111 | // 112 | // After you backed up your artifacts you can utilize db by running migrate as follows: 113 | // $ truffle migrate --reset --compile-all 114 | // 115 | // db: { 116 | // enabled: false, 117 | // host: "127.0.0.1", 118 | // adapter: { 119 | // name: "sqlite", 120 | // settings: { 121 | // directory: ".db" 122 | // } 123 | // } 124 | // } 125 | }; 126 | -------------------------------------------------------------------------------- /pages/index.tsx: -------------------------------------------------------------------------------- 1 | import type { NextPage } from 'next' 2 | import Head from 'next/head' 3 | import { VStack, HStack, Box, Spacer, Text, Heading, Input, Button, Slider, SliderTrack, SliderFilledTrack, Table, Thead, Th, Tr, Tbody, Td, Image, Link, useColorModeValue, Center, Spinner, AlertDialog, Modal, ModalOverlay, ModalContent, ModalHeader, ModalCloseButton, ModalBody, ModalFooter } from '@chakra-ui/react' 4 | import React from 'react'; 5 | import Web3 from 'web3'; 6 | 7 | import { load } from '../src/funcs'; 8 | 9 | 10 | const Loading = () => { 11 | const bg = useColorModeValue('gray.200', 'gray.600'); 12 | return ( 13 | 14 | 15 |
16 | 17 |
18 | 19 |
20 | ); 21 | }; 22 | 23 | const Home: NextPage = () => { 24 | const bg = useColorModeValue('gray.200', 'gray.700'); 25 | const hBG = useColorModeValue('gray.300', 'gray.500'); 26 | const sliderBG = useColorModeValue('blue.300', 'blue.500'); 27 | const filled = useColorModeValue('gray.300', 'gray.600'); 28 | 29 | // React.useState 30 | const [refresh, setRefresh] = React.useState(true); 31 | const [account, setAccount] = React.useState(null); 32 | const [contractFT, setContractFT] = React.useState(null); 33 | const [contractFTS, setContractFTS] = React.useState(null); 34 | const [tokensSold, setTokensSold] = React.useState(null); 35 | const [transactionCount, setTransactionCount] = React.useState(null); 36 | const [ethFunds, setEthFunds] = React.useState(null); 37 | const [FTtoETH, setFTtoETH] = React.useState(null); 38 | const [myFT, setMyFT] = React.useState(0); 39 | const [transactions, setTransactions] = React.useState([]); 40 | 41 | // Modal 42 | const [isOpen, setIsOpen] = React.useState(false); 43 | const onClose = () => setIsOpen(false); 44 | const [inputValue, setInputValue] = React.useState(0); 45 | const handleInput = (e:any) => setInputValue(e.currentTarget.value); 46 | 47 | 48 | const handleUseEffect = async () => { 49 | if (!refresh) return; 50 | setRefresh(false); 51 | load().then((e) => { 52 | setAccount(e.account); 53 | setContractFT(e.contractFT); 54 | setContractFTS(e.contractFTS); 55 | setTokensSold(e.tokensSold); 56 | setTransactionCount(e.transactionCount); 57 | setEthFunds(e.ethFunds); 58 | const ftETH = (50 / e.ethPriceN).toFixed(2); 59 | setFTtoETH(ftETH); 60 | setTransactions(e.transactions) 61 | setMyFT(e.myFT); 62 | }); 63 | }; 64 | 65 | // React.useEffect 66 | React.useEffect(() => { handleUseEffect(); } ); 67 | 68 | 69 | // Functions 70 | const isLoading = () => account == null || contractFT == null || contractFTS == null || tokensSold == null || transactionCount == null || ethFunds == null || FTtoETH == null; 71 | const SliderValue = () => { 72 | const bigInt = 750000000 * 10**18; 73 | const r = ((tokensSold * 100) / bigInt); 74 | return r; 75 | }; 76 | const buyTokens = async () => { 77 | const big = BigInt(inputValue * 10**18); 78 | await contractFTS.buyToken(big, { 79 | from: account, 80 | value: inputValue * FTtoETH * 10**18, 81 | gas: 500000 // Gas limit 82 | }); 83 | setIsOpen(false); 84 | setRefresh(true); 85 | }; 86 | 87 | return ( 88 | isLoading() ? : 89 | 90 | 91 | {/* Desktop */} 92 | 93 | 1FT = 50 USD = {FTtoETH} ETH 94 | 95 | 96 | 97 | 98 | 99 | {/* Mobile */} 100 | 101 | 102 | 1FT = 50 USD = {FTtoETH} ETH 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | {/* Desktop */} 111 | 112 | 113 | 114 | 115 |
116 | {Number(tokensSold).toFixed()} / 750.000.000 FT 117 |
118 |
119 |
120 |
121 | {/* Mobile */} 122 | 123 | 124 | 125 | 126 | 127 |
128 | {Number(tokensSold).toFixed()} / 750.000.000 FT 129 |
130 |
131 |
132 | 133 |
134 | 135 | 136 | {/* Desktop */} 137 | 138 | 139 | transactions 144 | 145 | {transactionCount} Transactions 146 | 147 | {/* Mobile */} 148 | 149 | 150 | 151 | 152 | transactions 157 | 158 | {transactionCount} Transactions 159 | 160 | 161 | 162 | {/* Desktop */} 163 | 164 | eth 169 | {(ethFunds / 10**18).toFixed(2)} ETH Founded 170 | 171 | {/* Mobile */} 172 | 173 | 174 | 175 | eth 180 | {(ethFunds / 10**18).toFixed(2)} ETH Founded 181 | 182 | 183 | 184 | {/* Desktop */} 185 | 186 | 187 | My Address: {account} 188 | 189 | {/* Mobile */} 190 | 191 | 192 | 193 | 194 | My Address: {account} 195 | 196 | 197 | 198 | {/* Desktop */} 199 | 200 | FT Token 205 | {myFT} 206 | 207 | {/* Mobile */} 208 | 209 | 210 | 211 | FT Token 216 | {myFT} 217 | 218 | 219 | 220 | 221 | Last Transactions 222 | {/* Desktop */} 223 | 224 | { 225 | transactions.length == 0 ? null : 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | { 235 | transactions.map((tran, idx) => 236 | 237 | 238 | 239 | 240 | ) 241 | } 242 | 243 |
AddressAmount
{tran[0]}{(tran[1] / 10**18).toFixed()}
244 | } 245 |
246 | {/* Mobile */} 247 | 248 | { 249 | transactions.length == 0 ? null : 250 | 251 | 252 | 253 | Address 254 | 255 | Amount 256 | 257 | 258 | 259 | { 260 | transactions.map((tran, idx) => 261 | 262 | 263 | {tran[0]} 264 | 265 | {(tran[1] / 10**18).toFixed(2)} 266 | 267 | 268 | ) 269 | } 270 | 271 | } 272 | 273 | 274 | 275 | 276 | Buy FT 277 | 278 | 279 | 286 | 287 | 288 | 289 | 290 | 291 | 292 |
293 | ) 294 | } 295 | 296 | const HeaderFT = () => { 297 | return ( 298 | 299 | 300 | Facu Token ICO 301 | 302 | 303 | 304 | 305 | 306 | 307 | Facu Token ICO 308 | 309 | 310 | 311 | 312 | ); 313 | }; 314 | 315 | 316 | export default Home 317 | --------------------------------------------------------------------------------