├── .eslintrc ├── .gitignore ├── README.md ├── components └── wallet │ └── connectors.js ├── constants ├── index.js ├── spiral.json └── spiral.sol ├── next.config.js ├── package-lock.json ├── package.json ├── pages ├── _app.js ├── api │ └── hello.js └── index.js ├── postcss.config.js ├── public ├── favicon.ico └── vercel.svg ├── styles ├── Home.module.css └── globals.css ├── tailwind.config.js └── yarn.lock /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["next", "next/core-web-vitals"] 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | -------------------------------------------------------------------------------- /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.js`. 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.js`. 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 | -------------------------------------------------------------------------------- /components/wallet/connectors.js: -------------------------------------------------------------------------------- 1 | import { InjectedConnector } from "@web3-react/injected-connector"; 2 | 3 | export const injected = new InjectedConnector({ 4 | supportedChainIds: [1, 4, 5, 97, 56, 324], 5 | }); 6 | -------------------------------------------------------------------------------- /constants/index.js: -------------------------------------------------------------------------------- 1 | export const spiralAddress = "0x3cB6CeEF116aCda0d39654BD60768683d7D989e5"; 2 | -------------------------------------------------------------------------------- /constants/spiral.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "_SPIRAL", 7 | "type": "address" 8 | } 9 | ], 10 | "stateMutability": "nonpayable", 11 | "type": "constructor" 12 | }, 13 | { 14 | "anonymous": false, 15 | "inputs": [ 16 | { 17 | "indexed": true, 18 | "internalType": "address", 19 | "name": "previousOwner", 20 | "type": "address" 21 | }, 22 | { 23 | "indexed": true, 24 | "internalType": "address", 25 | "name": "newOwner", 26 | "type": "address" 27 | } 28 | ], 29 | "name": "OwnershipTransferred", 30 | "type": "event" 31 | }, 32 | { 33 | "anonymous": false, 34 | "inputs": [ 35 | { 36 | "indexed": false, 37 | "internalType": "address", 38 | "name": "user", 39 | "type": "address" 40 | }, 41 | { 42 | "indexed": false, 43 | "internalType": "uint256", 44 | "name": "tokens", 45 | "type": "uint256" 46 | } 47 | ], 48 | "name": "TokenBuy", 49 | "type": "event" 50 | }, 51 | { 52 | "anonymous": false, 53 | "inputs": [ 54 | { 55 | "indexed": false, 56 | "internalType": "address", 57 | "name": "user", 58 | "type": "address" 59 | }, 60 | { 61 | "indexed": false, 62 | "internalType": "uint256", 63 | "name": "tokens", 64 | "type": "uint256" 65 | } 66 | ], 67 | "name": "TokenClaim", 68 | "type": "event" 69 | }, 70 | { 71 | "inputs": [], 72 | "name": "HardCap", 73 | "outputs": [ 74 | { 75 | "internalType": "uint256", 76 | "name": "", 77 | "type": "uint256" 78 | } 79 | ], 80 | "stateMutability": "view", 81 | "type": "function" 82 | }, 83 | { 84 | "inputs": [], 85 | "name": "SPIRAL", 86 | "outputs": [ 87 | { 88 | "internalType": "contract IBEP20", 89 | "name": "", 90 | "type": "address" 91 | } 92 | ], 93 | "stateMutability": "view", 94 | "type": "function" 95 | }, 96 | { 97 | "inputs": [], 98 | "name": "SPIRALPerETH", 99 | "outputs": [ 100 | { 101 | "internalType": "uint256", 102 | "name": "", 103 | "type": "uint256" 104 | } 105 | ], 106 | "stateMutability": "view", 107 | "type": "function" 108 | }, 109 | { 110 | "inputs": [ 111 | { 112 | "internalType": "uint256", 113 | "name": "_amount", 114 | "type": "uint256" 115 | } 116 | ], 117 | "name": "buy", 118 | "outputs": [], 119 | "stateMutability": "payable", 120 | "type": "function" 121 | }, 122 | { 123 | "inputs": [], 124 | "name": "claimActive", 125 | "outputs": [ 126 | { 127 | "internalType": "bool", 128 | "name": "", 129 | "type": "bool" 130 | } 131 | ], 132 | "stateMutability": "view", 133 | "type": "function" 134 | }, 135 | { 136 | "inputs": [], 137 | "name": "claimTokens", 138 | "outputs": [], 139 | "stateMutability": "nonpayable", 140 | "type": "function" 141 | }, 142 | { 143 | "inputs": [], 144 | "name": "getHardCap", 145 | "outputs": [ 146 | { 147 | "internalType": "uint256", 148 | "name": "", 149 | "type": "uint256" 150 | } 151 | ], 152 | "stateMutability": "view", 153 | "type": "function" 154 | }, 155 | { 156 | "inputs": [], 157 | "name": "getSPIRALTokensLeft", 158 | "outputs": [ 159 | { 160 | "internalType": "uint256", 161 | "name": "", 162 | "type": "uint256" 163 | } 164 | ], 165 | "stateMutability": "view", 166 | "type": "function" 167 | }, 168 | { 169 | "inputs": [ 170 | { 171 | "internalType": "address", 172 | "name": "_user", 173 | "type": "address" 174 | } 175 | ], 176 | "name": "getTokensOwned", 177 | "outputs": [ 178 | { 179 | "internalType": "uint256", 180 | "name": "", 181 | "type": "uint256" 182 | } 183 | ], 184 | "stateMutability": "view", 185 | "type": "function" 186 | }, 187 | { 188 | "inputs": [ 189 | { 190 | "internalType": "address", 191 | "name": "_user", 192 | "type": "address" 193 | } 194 | ], 195 | "name": "getTokensUnclaimed", 196 | "outputs": [ 197 | { 198 | "internalType": "uint256", 199 | "name": "", 200 | "type": "uint256" 201 | } 202 | ], 203 | "stateMutability": "view", 204 | "type": "function" 205 | }, 206 | { 207 | "inputs": [], 208 | "name": "getTotalTokensSold", 209 | "outputs": [ 210 | { 211 | "internalType": "uint256", 212 | "name": "", 213 | "type": "uint256" 214 | } 215 | ], 216 | "stateMutability": "view", 217 | "type": "function" 218 | }, 219 | { 220 | "inputs": [], 221 | "name": "owner", 222 | "outputs": [ 223 | { 224 | "internalType": "address", 225 | "name": "", 226 | "type": "address" 227 | } 228 | ], 229 | "stateMutability": "view", 230 | "type": "function" 231 | }, 232 | { 233 | "inputs": [], 234 | "name": "renounceOwnership", 235 | "outputs": [], 236 | "stateMutability": "nonpayable", 237 | "type": "function" 238 | }, 239 | { 240 | "inputs": [], 241 | "name": "saleActive", 242 | "outputs": [ 243 | { 244 | "internalType": "bool", 245 | "name": "", 246 | "type": "bool" 247 | } 248 | ], 249 | "stateMutability": "view", 250 | "type": "function" 251 | }, 252 | { 253 | "inputs": [ 254 | { 255 | "internalType": "bool", 256 | "name": "_isClaimActive", 257 | "type": "bool" 258 | } 259 | ], 260 | "name": "setClaimActive", 261 | "outputs": [], 262 | "stateMutability": "nonpayable", 263 | "type": "function" 264 | }, 265 | { 266 | "inputs": [ 267 | { 268 | "internalType": "uint256", 269 | "name": "_hardcap", 270 | "type": "uint256" 271 | } 272 | ], 273 | "name": "setHardcap", 274 | "outputs": [], 275 | "stateMutability": "nonpayable", 276 | "type": "function" 277 | }, 278 | { 279 | "inputs": [ 280 | { 281 | "internalType": "uint256", 282 | "name": "_SPIRALPerETH", 283 | "type": "uint256" 284 | } 285 | ], 286 | "name": "setSPIRALPerETH", 287 | "outputs": [], 288 | "stateMutability": "nonpayable", 289 | "type": "function" 290 | }, 291 | { 292 | "inputs": [ 293 | { 294 | "internalType": "bool", 295 | "name": "_isSaleActive", 296 | "type": "bool" 297 | } 298 | ], 299 | "name": "setSaleActive", 300 | "outputs": [], 301 | "stateMutability": "nonpayable", 302 | "type": "function" 303 | }, 304 | { 305 | "inputs": [ 306 | { 307 | "internalType": "address", 308 | "name": "", 309 | "type": "address" 310 | } 311 | ], 312 | "name": "tokensOwned", 313 | "outputs": [ 314 | { 315 | "internalType": "uint256", 316 | "name": "", 317 | "type": "uint256" 318 | } 319 | ], 320 | "stateMutability": "view", 321 | "type": "function" 322 | }, 323 | { 324 | "inputs": [ 325 | { 326 | "internalType": "address", 327 | "name": "", 328 | "type": "address" 329 | } 330 | ], 331 | "name": "tokensUnclaimed", 332 | "outputs": [ 333 | { 334 | "internalType": "uint256", 335 | "name": "", 336 | "type": "uint256" 337 | } 338 | ], 339 | "stateMutability": "view", 340 | "type": "function" 341 | }, 342 | { 343 | "inputs": [ 344 | { 345 | "internalType": "address", 346 | "name": "newOwner", 347 | "type": "address" 348 | } 349 | ], 350 | "name": "transferOwnership", 351 | "outputs": [], 352 | "stateMutability": "nonpayable", 353 | "type": "function" 354 | }, 355 | { 356 | "inputs": [], 357 | "name": "withdrawAllSPIRAL", 358 | "outputs": [], 359 | "stateMutability": "nonpayable", 360 | "type": "function" 361 | }, 362 | { 363 | "inputs": [], 364 | "name": "withdrawFunds", 365 | "outputs": [], 366 | "stateMutability": "payable", 367 | "type": "function" 368 | }, 369 | { 370 | "inputs": [], 371 | "name": "withdrawUnsoldSPIRAL", 372 | "outputs": [], 373 | "stateMutability": "nonpayable", 374 | "type": "function" 375 | } 376 | ] -------------------------------------------------------------------------------- /constants/spiral.sol: -------------------------------------------------------------------------------- 1 | 2 | // SPDX-License-Identifier: MIT 3 | 4 | pragma solidity ^0.8.17; 5 | /** 6 | * @dev Provides information about the current execution context, including the 7 | * sender of the transaction and its data. While these are generally available 8 | * via msg.sender and msg.data, they should not be accessed in such a direct 9 | * manner, since when dealing with meta-transactions the account sending and 10 | * paying for execution may not be the actual sender (as far as an application 11 | * is concerned). 12 | * 13 | * This contract is only required for intermediate, library-like contracts. 14 | */ 15 | abstract contract Context { 16 | function _msgSender() internal view virtual returns (address) { 17 | return msg.sender; 18 | } 19 | 20 | function _msgData() internal view virtual returns (bytes calldata) { 21 | return msg.data; 22 | } 23 | } 24 | 25 | /** 26 | * @dev Contract module which provides a basic access control mechanism, where 27 | * there is an account (an owner) that can be granted exclusive access to 28 | * specific functions. 29 | * 30 | * By default, the owner account will be the one that deploys the contract. This 31 | * can later be changed with {transferOwnership}. 32 | * 33 | * This module is used through inheritance. It will make available the modifier 34 | * `onlyOwner`, which can be applied to your functions to restrict their use to 35 | * the owner. 36 | */ 37 | abstract contract Ownable is Context { 38 | address private _owner; 39 | 40 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 41 | 42 | /** 43 | * @dev Initializes the contract setting the deployer as the initial owner. 44 | */ 45 | constructor() { 46 | _transferOwnership(_msgSender()); 47 | } 48 | 49 | /** 50 | * @dev Throws if called by any account other than the owner. 51 | */ 52 | modifier onlyOwner() { 53 | _checkOwner(); 54 | _; 55 | } 56 | 57 | /** 58 | * @dev Returns the address of the current owner. 59 | */ 60 | function owner() public view virtual returns (address) { 61 | return _owner; 62 | } 63 | 64 | /** 65 | * @dev Throws if the sender is not the owner. 66 | */ 67 | function _checkOwner() internal view virtual { 68 | require(owner() == _msgSender(), "Ownable: caller is not the owner"); 69 | } 70 | 71 | /** 72 | * @dev Leaves the contract without owner. It will not be possible to call 73 | * `onlyOwner` functions anymore. Can only be called by the current owner. 74 | * 75 | * NOTE: Renouncing ownership will leave the contract without an owner, 76 | * thereby removing any functionality that is only available to the owner. 77 | */ 78 | function renounceOwnership() public virtual onlyOwner { 79 | _transferOwnership(address(0)); 80 | } 81 | 82 | /** 83 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 84 | * Can only be called by the current owner. 85 | */ 86 | function transferOwnership(address newOwner) public virtual onlyOwner { 87 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 88 | _transferOwnership(newOwner); 89 | } 90 | 91 | /** 92 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 93 | * Internal function without access restriction. 94 | */ 95 | function _transferOwnership(address newOwner) internal virtual { 96 | address oldOwner = _owner; 97 | _owner = newOwner; 98 | emit OwnershipTransferred(oldOwner, newOwner); 99 | } 100 | } 101 | 102 | // File: contracts\presale.sol 103 | 104 | /** 105 | *Submitted for verification at Arbiscan on 2023-03-08 106 | */ 107 | /** 108 | * @dev Contract module that helps prevent reentrant calls to a function. 109 | * 110 | * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier 111 | * available, which can be applied to functions to make sure there are no nested 112 | * (reentrant) calls to them. 113 | * 114 | * Note that because there is a single `nonReentrant` guard, functions marked as 115 | * `nonReentrant` may not call one another. This can be worked around by making 116 | * those functions `private`, and then adding `external` `nonReentrant` entry 117 | * points to them. 118 | * 119 | * TIP: If you would like to learn more about reentrancy and alternative ways 120 | * to protect against it, check out our blog post 121 | * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. 122 | */ 123 | abstract contract ReentrancyGuard is Ownable { 124 | // Booleans are more expensive than uint256 or any type that takes up a full 125 | // word because each write operation emits an extra SLOAD to first read the 126 | // slot's contents, replace the bits taken up by the boolean, and then write 127 | // back. This is the compiler's defense against contract upgrades and 128 | // pointer aliasing, and it cannot be disabled. 129 | 130 | // The values being non-zero value makes deployment a bit more expensive, 131 | // but in exchange the refund on every call to nonReentrant will be lower in 132 | // amount. Since refunds are capped to a percentage of the total 133 | // transaction's gas, it is best to keep them low in cases like this one, to 134 | // increase the likelihood of the full refund coming into effect. 135 | uint256 private constant _NOT_ENTERED = 1; 136 | uint256 private constant _ENTERED = 2; 137 | 138 | uint256 private _status; 139 | 140 | constructor () { 141 | _status = _NOT_ENTERED; 142 | } 143 | 144 | /** 145 | * @dev Prevents a contract from calling itself, directly or indirectly. 146 | * Calling a `nonReentrant` function from another `nonReentrant` 147 | * function is not supported. It is possible to prevent this from happening 148 | * by making the `nonReentrant` function external, and make it call a 149 | * `private` function that does the actual work. 150 | */ 151 | modifier nonReentrant() { 152 | // On the first call to nonReentrant, _notEntered will be true 153 | require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); 154 | 155 | // Any calls to nonReentrant after this point will fail 156 | _status = _ENTERED; 157 | 158 | _; 159 | 160 | // By storing the original value once again, a refund is triggered (see 161 | // https://eips.ethereum.org/EIPS/eip-2200) 162 | _status = _NOT_ENTERED; 163 | } 164 | } 165 | 166 | interface IBEP20 { 167 | /** 168 | * @dev Returns the amount of tokens in existence. 169 | */ 170 | function totalSupply() external view returns (uint256); 171 | 172 | /** 173 | * @dev Returns the token decimals. 174 | */ 175 | function decimals() external view returns (uint8); 176 | 177 | /** 178 | * @dev Returns the token symbol. 179 | */ 180 | function symbol() external view returns (string memory); 181 | 182 | /** 183 | * @dev Returns the token name. 184 | */ 185 | function name() external view returns (string memory); 186 | 187 | /** 188 | * @dev Returns the bep token owner. 189 | */ 190 | function getOwner() external view returns (address); 191 | 192 | /** 193 | * @dev Returns the amount of tokens owned by `account`. 194 | */ 195 | function balanceOf(address account) external view returns (uint256); 196 | 197 | /** 198 | * @dev Moves `amount` tokens from the caller's account to `recipient`. 199 | * 200 | * Returns a boolean value indicating whether the operation succeeded. 201 | * 202 | * Emits a {Transfer} event. 203 | */ 204 | function transfer(address recipient, uint256 amount) external returns (bool); 205 | 206 | /** 207 | * @dev Returns the remaining number of tokens that `spender` will be 208 | * allowed to spend on behalf of `owner` through {transferFrom}. This is 209 | * zero by default. 210 | * 211 | * This value changes when {approve} or {transferFrom} are called. 212 | */ 213 | function allowance(address _owner, address spender) external view returns (uint256); 214 | 215 | /** 216 | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. 217 | * 218 | * Returns a boolean value indicating whether the operation succeeded. 219 | * 220 | * IMPORTANT: Beware that changing an allowance with this method brings the risk 221 | * that someone may use both the old and the new allowance by unfortunate 222 | * transaction ordering. One possible solution to mitigate this race 223 | * condition is to first reduce the spender's allowance to 0 and set the 224 | * desired value afterwards: 225 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 226 | * 227 | * Emits an {Approval} event. 228 | */ 229 | function approve(address spender, uint256 amount) external returns (bool); 230 | 231 | /** 232 | * @dev Moves `amount` tokens from `sender` to `recipient` using the 233 | * allowance mechanism. `amount` is then deducted from the caller's 234 | * allowance. 235 | * 236 | * Returns a boolean value indicating whether the operation succeeded. 237 | * 238 | * Emits a {Transfer} event. 239 | */ 240 | function transferFrom( 241 | address sender, 242 | address recipient, 243 | uint256 amount 244 | ) external returns (bool); 245 | 246 | /** 247 | * @dev Emitted when `value` tokens are moved from one account (`from`) to 248 | * another (`to`). 249 | * 250 | * Note that `value` may be zero. 251 | */ 252 | event Transfer(address indexed from, address indexed to, uint256 value); 253 | 254 | /** 255 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by 256 | * a call to {approve}. `value` is the new allowance. 257 | */ 258 | event Approval(address indexed owner, address indexed spender, uint256 value); 259 | } 260 | 261 | /** 262 | * @dev Wrappers over Solidity's arithmetic operations with added overflow 263 | * checks. 264 | * 265 | * Arithmetic operations in Solidity wrap on overflow. This can easily result 266 | * in bugs, because programmers usually assume that an overflow raises an 267 | * error, which is the standard behavior in high level programming languages. 268 | * `SafeMath` restores this intuition by reverting the transaction when an 269 | * operation overflows. 270 | * 271 | * Using this library instead of the unchecked operations eliminates an entire 272 | * class of bugs, so it's recommended to use it always. 273 | */ 274 | library SafeMath { 275 | /** 276 | * @dev Returns the addition of two unsigned integers, with an overflow flag. 277 | * 278 | * _Available since v3.4._ 279 | */ 280 | function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { 281 | uint256 c = a + b; 282 | if (c < a) return (false, 0); 283 | return (true, c); 284 | } 285 | 286 | /** 287 | * @dev Returns the substraction of two unsigned integers, with an overflow flag. 288 | * 289 | * _Available since v3.4._ 290 | */ 291 | function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { 292 | if (b > a) return (false, 0); 293 | return (true, a - b); 294 | } 295 | 296 | /** 297 | * @dev Returns the multiplication of two unsigned integers, with an overflow flag. 298 | * 299 | * _Available since v3.4._ 300 | */ 301 | function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { 302 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 303 | // benefit is lost if 'b' is also tested. 304 | // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 305 | if (a == 0) return (true, 0); 306 | uint256 c = a * b; 307 | if (c / a != b) return (false, 0); 308 | return (true, c); 309 | } 310 | 311 | /** 312 | * @dev Returns the division of two unsigned integers, with a division by zero flag. 313 | * 314 | * _Available since v3.4._ 315 | */ 316 | function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { 317 | if (b == 0) return (false, 0); 318 | return (true, a / b); 319 | } 320 | 321 | /** 322 | * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. 323 | * 324 | * _Available since v3.4._ 325 | */ 326 | function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { 327 | if (b == 0) return (false, 0); 328 | return (true, a % b); 329 | } 330 | 331 | /** 332 | * @dev Returns the addition of two unsigned integers, reverting on 333 | * overflow. 334 | * 335 | * Counterpart to Solidity's `+` operator. 336 | * 337 | * Requirements: 338 | * 339 | * - Addition cannot overflow. 340 | */ 341 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 342 | uint256 c = a + b; 343 | require(c >= a, "SafeMath: addition overflow"); 344 | return c; 345 | } 346 | 347 | /** 348 | * @dev Returns the subtraction of two unsigned integers, reverting on 349 | * overflow (when the result is negative). 350 | * 351 | * Counterpart to Solidity's `-` operator. 352 | * 353 | * Requirements: 354 | * 355 | * - Subtraction cannot overflow. 356 | */ 357 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 358 | require(b <= a, "SafeMath: subtraction overflow"); 359 | return a - b; 360 | } 361 | 362 | /** 363 | * @dev Returns the multiplication of two unsigned integers, reverting on 364 | * overflow. 365 | * 366 | * Counterpart to Solidity's `*` operator. 367 | * 368 | * Requirements: 369 | * 370 | * - Multiplication cannot overflow. 371 | */ 372 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 373 | if (a == 0) return 0; 374 | uint256 c = a * b; 375 | require(c / a == b, "SafeMath: multiplication overflow"); 376 | return c; 377 | } 378 | 379 | /** 380 | * @dev Returns the integer division of two unsigned integers, reverting on 381 | * division by zero. The result is rounded towards zero. 382 | * 383 | * Counterpart to Solidity's `/` operator. Note: this function uses a 384 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 385 | * uses an invalid opcode to revert (consuming all remaining gas). 386 | * 387 | * Requirements: 388 | * 389 | * - The divisor cannot be zero. 390 | */ 391 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 392 | require(b > 0, "SafeMath: division by zero"); 393 | return a / b; 394 | } 395 | 396 | /** 397 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 398 | * reverting when dividing by zero. 399 | * 400 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 401 | * opcode (which leaves remaining gas untouched) while Solidity uses an 402 | * invalid opcode to revert (consuming all remaining gas). 403 | * 404 | * Requirements: 405 | * 406 | * - The divisor cannot be zero. 407 | */ 408 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 409 | require(b > 0, "SafeMath: modulo by zero"); 410 | return a % b; 411 | } 412 | 413 | /** 414 | * @dev Returns the subtraction of two unsigned integers, reverting with custom message on 415 | * overflow (when the result is negative). 416 | * 417 | * CAUTION: This function is deprecated because it requires allocating memory for the error 418 | * message unnecessarily. For custom revert reasons use {trySub}. 419 | * 420 | * Counterpart to Solidity's `-` operator. 421 | * 422 | * Requirements: 423 | * 424 | * - Subtraction cannot overflow. 425 | */ 426 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 427 | require(b <= a, errorMessage); 428 | return a - b; 429 | } 430 | 431 | /** 432 | * @dev Returns the integer division of two unsigned integers, reverting with custom message on 433 | * division by zero. The result is rounded towards zero. 434 | * 435 | * CAUTION: This function is deprecated because it requires allocating memory for the error 436 | * message unnecessarily. For custom revert reasons use {tryDiv}. 437 | * 438 | * Counterpart to Solidity's `/` operator. Note: this function uses a 439 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 440 | * uses an invalid opcode to revert (consuming all remaining gas). 441 | * 442 | * Requirements: 443 | * 444 | * - The divisor cannot be zero. 445 | */ 446 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 447 | require(b > 0, errorMessage); 448 | return a / b; 449 | } 450 | 451 | /** 452 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 453 | * reverting with custom message when dividing by zero. 454 | * 455 | * CAUTION: This function is deprecated because it requires allocating memory for the error 456 | * message unnecessarily. For custom revert reasons use {tryMod}. 457 | * 458 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 459 | * opcode (which leaves remaining gas untouched) while Solidity uses an 460 | * invalid opcode to revert (consuming all remaining gas). 461 | * 462 | * Requirements: 463 | * 464 | * - The divisor cannot be zero. 465 | */ 466 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 467 | require(b > 0, errorMessage); 468 | return a % b; 469 | } 470 | } 471 | /** 472 | * @dev Collection of functions related to the address type 473 | */ 474 | library Address { 475 | /** 476 | * @dev Returns true if `account` is a contract. 477 | * 478 | * [IMPORTANT] 479 | * ==== 480 | * It is unsafe to assume that an address for which this function returns 481 | * false is an externally-owned account (EOA) and not a contract. 482 | * 483 | * Among others, `isContract` will return false for the following 484 | * types of addresses: 485 | * 486 | * - an externally-owned account 487 | * - a contract in construction 488 | * - an address where a contract will be created 489 | * - an address where a contract lived, but was destroyed 490 | * ==== 491 | */ 492 | function isContract(address account) internal view returns (bool) { 493 | // This method relies on extcodesize, which returns 0 for contracts in 494 | // construction, since the code is only stored at the end of the 495 | // constructor execution. 496 | 497 | uint256 size; 498 | // solhint-disable-next-line no-inline-assembly 499 | assembly { size := extcodesize(account) } 500 | return size > 0; 501 | } 502 | 503 | /** 504 | * @dev Replacement for Solidity's `transfer`: sends `amount` wei to 505 | * `recipient`, forwarding all available gas and reverting on errors. 506 | * 507 | * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost 508 | * of certain opcodes, possibly making contracts go over the 2300 gas limit 509 | * imposed by `transfer`, making them unable to receive funds via 510 | * `transfer`. {sendValue} removes this limitation. 511 | * 512 | * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. 513 | * 514 | * IMPORTANT: because control is transferred to `recipient`, care must be 515 | * taken to not create reentrancy vulnerabilities. Consider using 516 | * {ReentrancyGuard} or the 517 | * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. 518 | */ 519 | function sendValue(address payable recipient, uint256 amount) internal { 520 | require(address(this).balance >= amount, "Address: insufficient balance"); 521 | 522 | // solhint-disable-next-line avoid-low-level-calls, avoid-call-value 523 | (bool success, ) = recipient.call{ value: amount }(""); 524 | require(success, "Address: unable to send value, recipient may have reverted"); 525 | } 526 | 527 | /** 528 | * @dev Performs a Solidity function call using a low level `call`. A 529 | * plain`call` is an unsafe replacement for a function call: use this 530 | * function instead. 531 | * 532 | * If `target` reverts with a revert reason, it is bubbled up by this 533 | * function (like regular Solidity function calls). 534 | * 535 | * Returns the raw returned data. To convert to the expected return value, 536 | * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. 537 | * 538 | * Requirements: 539 | * 540 | * - `target` must be a contract. 541 | * - calling `target` with `data` must not revert. 542 | * 543 | * _Available since v3.1._ 544 | */ 545 | function functionCall(address target, bytes memory data) internal returns (bytes memory) { 546 | return functionCall(target, data, "Address: low-level call failed"); 547 | } 548 | 549 | /** 550 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with 551 | * `errorMessage` as a fallback revert reason when `target` reverts. 552 | * 553 | * _Available since v3.1._ 554 | */ 555 | function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { 556 | return functionCallWithValue(target, data, 0, errorMessage); 557 | } 558 | 559 | /** 560 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 561 | * but also transferring `value` wei to `target`. 562 | * 563 | * Requirements: 564 | * 565 | * - the calling contract must have an ETH balance of at least `value`. 566 | * - the called Solidity function must be `payable`. 567 | * 568 | * _Available since v3.1._ 569 | */ 570 | function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { 571 | return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); 572 | } 573 | 574 | /** 575 | * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but 576 | * with `errorMessage` as a fallback revert reason when `target` reverts. 577 | * 578 | * _Available since v3.1._ 579 | */ 580 | function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { 581 | require(address(this).balance >= value, "Address: insufficient balance for call"); 582 | require(isContract(target), "Address: call to non-contract"); 583 | 584 | // solhint-disable-next-line avoid-low-level-calls 585 | (bool success, bytes memory returndata) = target.call{ value: value }(data); 586 | return _verifyCallResult(success, returndata, errorMessage); 587 | } 588 | 589 | /** 590 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 591 | * but performing a static call. 592 | * 593 | * _Available since v3.3._ 594 | */ 595 | function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { 596 | return functionStaticCall(target, data, "Address: low-level static call failed"); 597 | } 598 | 599 | /** 600 | * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], 601 | * but performing a static call. 602 | * 603 | * _Available since v3.3._ 604 | */ 605 | function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { 606 | require(isContract(target), "Address: static call to non-contract"); 607 | 608 | // solhint-disable-next-line avoid-low-level-calls 609 | (bool success, bytes memory returndata) = target.staticcall(data); 610 | return _verifyCallResult(success, returndata, errorMessage); 611 | } 612 | 613 | /** 614 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 615 | * but performing a delegate call. 616 | * 617 | * _Available since v3.4._ 618 | */ 619 | function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { 620 | return functionDelegateCall(target, data, "Address: low-level delegate call failed"); 621 | } 622 | 623 | /** 624 | * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], 625 | * but performing a delegate call. 626 | * 627 | * _Available since v3.4._ 628 | */ 629 | function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { 630 | require(isContract(target), "Address: delegate call to non-contract"); 631 | 632 | // solhint-disable-next-line avoid-low-level-calls 633 | (bool success, bytes memory returndata) = target.delegatecall(data); 634 | return _verifyCallResult(success, returndata, errorMessage); 635 | } 636 | 637 | function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { 638 | if (success) { 639 | return returndata; 640 | } else { 641 | // Look for revert reason and bubble it up if present 642 | if (returndata.length > 0) { 643 | // The easiest way to bubble the revert reason is using memory via assembly 644 | 645 | // solhint-disable-next-line no-inline-assembly 646 | assembly { 647 | let returndata_size := mload(returndata) 648 | revert(add(32, returndata), returndata_size) 649 | } 650 | } else { 651 | revert(errorMessage); 652 | } 653 | } 654 | } 655 | } 656 | 657 | /** 658 | * @title SafeBEP20 659 | * @dev Wrappers around BEP20 operations that throw on failure (when the token 660 | * contract returns false). Tokens that return no value (and instead revert or 661 | * throw on failure) are also supported, non-reverting calls are assumed to be 662 | * successful. 663 | * To use this library you can add a `using SafeBEP20 for IBEP20;` statement to your contract, 664 | * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. 665 | */ 666 | library SafeBEP20 { 667 | using SafeMath for uint256; 668 | using Address for address; 669 | 670 | function safeTransfer( 671 | IBEP20 token, 672 | address to, 673 | uint256 value 674 | ) internal { 675 | _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 676 | } 677 | 678 | function safeTransferFrom( 679 | IBEP20 token, 680 | address from, 681 | address to, 682 | uint256 value 683 | ) internal { 684 | _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 685 | } 686 | 687 | /** 688 | * @dev Deprecated. This function has issues similar to the ones found in 689 | * {IBEP20-approve}, and its usage is discouraged. 690 | * 691 | * Whenever possible, use {safeIncreaseAllowance} and 692 | * {safeDecreaseAllowance} instead. 693 | */ 694 | function safeApprove( 695 | IBEP20 token, 696 | address spender, 697 | uint256 value 698 | ) internal { 699 | // safeApprove should only be called when setting an initial allowance, 700 | // or when resetting it to zero. To increase and decrease it, use 701 | // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' 702 | // solhint-disable-next-line max-line-length 703 | require( 704 | (value == 0) || (token.allowance(address(this), spender) == 0), 705 | "SafeBEP20: approve from non-zero to non-zero allowance" 706 | ); 707 | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 708 | } 709 | 710 | function safeIncreaseAllowance( 711 | IBEP20 token, 712 | address spender, 713 | uint256 value 714 | ) internal { 715 | uint256 newAllowance = token.allowance(address(this), spender).add(value); 716 | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 717 | } 718 | 719 | function safeDecreaseAllowance( 720 | IBEP20 token, 721 | address spender, 722 | uint256 value 723 | ) internal { 724 | uint256 newAllowance = token.allowance(address(this), spender).sub( 725 | value, 726 | "SafeBEP20: decreased allowance below zero" 727 | ); 728 | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 729 | } 730 | 731 | /** 732 | * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement 733 | * on the return value: the return value is optional (but if data is returned, it must not be false). 734 | * @param token The token targeted by the call. 735 | * @param data The call data (encoded using abi.encode or one of its variants). 736 | */ 737 | function _callOptionalReturn(IBEP20 token, bytes memory data) private { 738 | // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since 739 | // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that 740 | // the target address contains contract code and also asserts for success in the low-level call. 741 | 742 | bytes memory returndata = address(token).functionCall(data, "SafeBEP20: low-level call failed"); 743 | if (returndata.length > 0) { 744 | // Return data is optional 745 | // solhint-disable-next-line max-line-length 746 | require(abi.decode(returndata, (bool)), "SafeBEP20: BEP20 operation did not succeed"); 747 | } 748 | } 749 | } 750 | 751 | contract SPIRALPrivateSale is ReentrancyGuard { 752 | using SafeMath for uint256; 753 | using SafeBEP20 for IBEP20; 754 | // Maps user to the number of tokens owned 755 | mapping(address => uint256) public tokensOwned; 756 | // The number of unclaimed tokens the user has 757 | mapping(address => uint256) public tokensUnclaimed; 758 | 759 | // SPIRAL token 760 | IBEP20 public SPIRAL; 761 | 762 | // Sale active 763 | bool isSaleActive; 764 | // Claim active 765 | bool isClaimActive; 766 | // Total SPIRAL sold 767 | uint256 totalTokensSold = 0; 768 | // Price of presale SPIRAL, 1 ETH 769 | 770 | uint256 public SPIRALPerETH = 3818; 771 | // Amount of ETH received in presale 772 | uint256 ethReceived = 0; 773 | 774 | uint256 public HardCap = 1000000 * 10 ** 18; // 775 | 776 | event TokenBuy(address user, uint256 tokens); 777 | event TokenClaim(address user, uint256 tokens); 778 | 779 | constructor( 780 | address _SPIRAL 781 | ) { 782 | SPIRAL = IBEP20(_SPIRAL); 783 | } 784 | 785 | function setSPIRALPerETH(uint256 _SPIRALPerETH) public onlyOwner{ 786 | SPIRALPerETH = _SPIRALPerETH; 787 | } 788 | function setHardcap(uint256 _hardcap) public onlyOwner{ 789 | HardCap = _hardcap * 10 **18; 790 | } 791 | 792 | function buy(uint256 _amount) public payable nonReentrant { 793 | require(isSaleActive, "Presale has not started"); 794 | address _buyer = msg.sender; 795 | uint256 tokens = _amount.mul(SPIRALPerETH); 796 | require(msg.value >= _amount, "Influence ETH"); 797 | require( totalTokensSold + tokens <= HardCap, "presale hardcap reached"); 798 | 799 | tokensOwned[_buyer] = tokensOwned[_buyer].add(tokens); 800 | tokensUnclaimed[_buyer] = tokensUnclaimed[_buyer].add(tokens); 801 | totalTokensSold = totalTokensSold.add(tokens); 802 | 803 | ethReceived = ethReceived.add(_amount); 804 | emit TokenBuy(msg.sender, tokens); 805 | } 806 | 807 | function setSaleActive(bool _isSaleActive) external onlyOwner { 808 | isSaleActive = _isSaleActive; 809 | } 810 | 811 | function setClaimActive(bool _isClaimActive) external onlyOwner { 812 | isClaimActive = _isClaimActive; 813 | } 814 | 815 | function saleActive() public view returns (bool) { 816 | return isSaleActive; 817 | } 818 | 819 | function getTotalTokensSold() public view returns (uint256) { 820 | return totalTokensSold; 821 | } 822 | function getHardCap() public view returns (uint256){ 823 | return HardCap; 824 | } 825 | 826 | function claimActive() public view returns (bool) { 827 | return isClaimActive; 828 | } 829 | 830 | function getTokensOwned(address _user) external view returns (uint256) { 831 | return tokensOwned[_user]; 832 | } 833 | 834 | function getTokensUnclaimed(address _user) external view returns (uint256) { 835 | return tokensUnclaimed[_user]; 836 | } 837 | 838 | function getSPIRALTokensLeft() external view returns (uint256) { 839 | return SPIRAL.balanceOf(address(this)); 840 | } 841 | 842 | function claimTokens() external nonReentrant { 843 | require(isClaimActive, "Claim is not allowed yet"); 844 | require(tokensOwned[msg.sender] > 0, "User should own some SPIRAL tokens"); 845 | require(tokensUnclaimed[msg.sender] > 0, "User should have unclaimed SPIRAL tokens"); 846 | require(SPIRAL.balanceOf(address(this)) >= tokensUnclaimed[msg.sender], "There are not enough SPIRAL tokens to transfer."); 847 | 848 | uint256 callerTokensUnclaimed = tokensUnclaimed[msg.sender]; 849 | tokensUnclaimed[msg.sender] = 0; 850 | SPIRAL.safeTransfer(msg.sender, callerTokensUnclaimed); 851 | emit TokenClaim(msg.sender, callerTokensUnclaimed); 852 | } 853 | 854 | function withdrawFunds() external payable onlyOwner { 855 | payable(msg.sender).transfer(address(this).balance); 856 | } 857 | 858 | function withdrawUnsoldSPIRAL() external onlyOwner { 859 | uint256 amount = SPIRAL.balanceOf(address(this)) - totalTokensSold; 860 | SPIRAL.safeTransfer(msg.sender, amount); 861 | } 862 | 863 | function withdrawAllSPIRAL() external onlyOwner { 864 | SPIRAL.safeTransfer(msg.sender, SPIRAL.balanceOf(address(this))); 865 | } 866 | 867 | } 868 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | reactStrictMode: true, 3 | } 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web3-react-example", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@ethersproject/contract": "^6.0.0-beta.1", 13 | "@ethersproject/contracts": "^5.7.0", 14 | "@ethersproject/providers": "^5.7.2", 15 | "@ethersproject/units": "^5.7.0", 16 | "@web3-react/core": "^6.1.9", 17 | "@web3-react/injected-connector": "^6.0.7", 18 | "autoprefixer": "^10.3.1", 19 | "next": "11.0.1", 20 | "postcss": "^8.3.6", 21 | "react": "17.0.2", 22 | "react-dom": "17.0.2", 23 | "tailwindcss": "^2.2.7", 24 | "web3": "^1.5.1" 25 | }, 26 | "devDependencies": { 27 | "eslint": "7.32.0", 28 | "eslint-config-next": "11.0.1" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /pages/_app.js: -------------------------------------------------------------------------------- 1 | import '../styles/globals.css' 2 | import 'tailwindcss/tailwind.css' 3 | import { Web3ReactProvider } from '@web3-react/core' 4 | import { Web3Provider } from "@ethersproject/providers"; 5 | 6 | // import Web3 from 'web3' 7 | 8 | function getLibrary(provider) { 9 | return new Web3Provider(provider) 10 | } 11 | 12 | function MyApp({ Component, pageProps }) { 13 | return ( 14 | 15 | 16 | 17 | ) 18 | } 19 | 20 | export default MyApp 21 | -------------------------------------------------------------------------------- /pages/api/hello.js: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | 3 | export default function handler(req, res) { 4 | res.status(200).json({ name: 'John Doe' }) 5 | } 6 | -------------------------------------------------------------------------------- /pages/index.js: -------------------------------------------------------------------------------- 1 | import { useWeb3React } from "@web3-react/core"; 2 | import { useEffect, useState } from "react"; 3 | import { injected } from "../components/wallet/connectors"; 4 | 5 | import { spiralAddress } from "../constants"; 6 | import sprialABI from "../constants/spiral.json"; 7 | import { Contract } from "@ethersproject/contracts"; 8 | import { formatEther } from "@ethersproject/units"; 9 | export default function Home() { 10 | const { active, account, chainId, library, activate, deactivate } = 11 | useWeb3React(); 12 | const [ethBalance, setEthBalance] = useState(undefined); 13 | 14 | // example of switching or adding network with ZkSync ERA Mainnet 15 | async function connect() { 16 | try { 17 | await activate(injected); 18 | 19 | console.log(active); 20 | 21 | localStorage.setItem("isWalletConnected", true); 22 | } catch (ex) { 23 | console.log(ex); 24 | } 25 | } 26 | 27 | async function disconnect() { 28 | try { 29 | deactivate(); 30 | localStorage.setItem("isWalletConnected", false); 31 | } catch (ex) { 32 | console.log(ex); 33 | } 34 | } 35 | 36 | async function withdrawFunds() { 37 | const SpiralContract = new Contract( 38 | spiralAddress, 39 | sprialABI, 40 | library.getSigner() 41 | ); 42 | await SpiralContract.withdrawFunds(); 43 | } 44 | 45 | async function withdrawUnsoldSPIRAL() { 46 | const SpiralContract = new Contract( 47 | spiralAddress, 48 | sprialABI, 49 | library.getSigner() 50 | ); 51 | await SpiralContract.withdrawUnsoldSPIRAL(); 52 | } 53 | 54 | async function withdrawAllSPIRAL() { 55 | const SpiralContract = new Contract( 56 | spiralAddress, 57 | sprialABI, 58 | library.getSigner() 59 | ); 60 | await SpiralContract.withdrawAllSPIRAL(); 61 | } 62 | 63 | useEffect(() => { 64 | async function switchChain() { 65 | if (chainId !== 324) { 66 | console.log(chainId); 67 | try { 68 | await library.provider.request({ 69 | method: "wallet_switchEthereumChain", 70 | params: [{ chainId: "0x144" }] 71 | }); 72 | } catch (switchError) { 73 | // 4902 error code indicates the chain is missing on the wallet 74 | if (switchError.code === 4902) { 75 | try { 76 | await library.provider.request({ 77 | method: "wallet_addEthereumChain", 78 | params: [ 79 | { 80 | chainId: "0x144", 81 | rpcUrls: ["https://zksync2-mainnet.zksync.io"], 82 | chainName: "zkSync Era Mainnet", 83 | nativeCurrency: { 84 | name: "ETH", 85 | decimals: 18, 86 | symbol: "ETH" 87 | }, 88 | blockExplorerUrls: ["https://explorer.zksync.io/"] 89 | } 90 | ] 91 | }); 92 | } catch (error) { 93 | console.error(error); 94 | } 95 | } 96 | } 97 | } 98 | } 99 | const connectWalletOnPageLoad = async () => { 100 | // if (localStorage?.getItem("isWalletConnected") === "true") { 101 | try { 102 | await activate(injected); 103 | await switchChain(); 104 | localStorage.setItem("isWalletConnected", true); 105 | } catch (ex) { 106 | console.log(ex); 107 | } 108 | // } 109 | }; 110 | connectWalletOnPageLoad(); 111 | }, [activate]); 112 | 113 | useEffect(() => { 114 | if (active && account) { 115 | library?.getBalance(account).then((result) => { 116 | setEthBalance(Number(formatEther(result))); 117 | }); 118 | } 119 | }); 120 | return ( 121 | <> 122 |
123 | 129 | 135 |
136 |
137 | {active ? ( 138 | <> 139 | 140 | Connected with {account} 141 | 142 |
balance: {ethBalance}
143 | 144 | ) : ( 145 | Not connected 146 | )} 147 |
148 |
149 | 155 | 156 | 162 | 168 |
169 | 170 | ); 171 | } 172 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wittyCodeX/web3-react-example/28c2609fcb7245283a67348d4b16fab87820c78f/public/favicon.ico -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /styles/Home.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | min-height: 100vh; 3 | padding: 0 0.5rem; 4 | display: flex; 5 | flex-direction: column; 6 | justify-content: center; 7 | align-items: center; 8 | height: 100vh; 9 | } 10 | 11 | .main { 12 | padding: 5rem 0; 13 | flex: 1; 14 | display: flex; 15 | flex-direction: column; 16 | justify-content: center; 17 | align-items: center; 18 | } 19 | 20 | .footer { 21 | width: 100%; 22 | height: 100px; 23 | border-top: 1px solid #eaeaea; 24 | display: flex; 25 | justify-content: center; 26 | align-items: center; 27 | } 28 | 29 | .footer a { 30 | display: flex; 31 | justify-content: center; 32 | align-items: center; 33 | flex-grow: 1; 34 | } 35 | 36 | .title a { 37 | color: #0070f3; 38 | text-decoration: none; 39 | } 40 | 41 | .title a:hover, 42 | .title a:focus, 43 | .title a:active { 44 | text-decoration: underline; 45 | } 46 | 47 | .title { 48 | margin: 0; 49 | line-height: 1.15; 50 | font-size: 4rem; 51 | } 52 | 53 | .title, 54 | .description { 55 | text-align: center; 56 | } 57 | 58 | .description { 59 | line-height: 1.5; 60 | font-size: 1.5rem; 61 | } 62 | 63 | .code { 64 | background: #fafafa; 65 | border-radius: 5px; 66 | padding: 0.75rem; 67 | font-size: 1.1rem; 68 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, 69 | Bitstream Vera Sans Mono, Courier New, monospace; 70 | } 71 | 72 | .grid { 73 | display: flex; 74 | align-items: center; 75 | justify-content: center; 76 | flex-wrap: wrap; 77 | max-width: 800px; 78 | margin-top: 3rem; 79 | } 80 | 81 | .card { 82 | margin: 1rem; 83 | padding: 1.5rem; 84 | text-align: left; 85 | color: inherit; 86 | text-decoration: none; 87 | border: 1px solid #eaeaea; 88 | border-radius: 10px; 89 | transition: color 0.15s ease, border-color 0.15s ease; 90 | width: 45%; 91 | } 92 | 93 | .card:hover, 94 | .card:focus, 95 | .card:active { 96 | color: #0070f3; 97 | border-color: #0070f3; 98 | } 99 | 100 | .card h2 { 101 | margin: 0 0 1rem 0; 102 | font-size: 1.5rem; 103 | } 104 | 105 | .card p { 106 | margin: 0; 107 | font-size: 1.25rem; 108 | line-height: 1.5; 109 | } 110 | 111 | .logo { 112 | height: 1em; 113 | margin-left: 0.5rem; 114 | } 115 | 116 | @media (max-width: 600px) { 117 | .grid { 118 | width: 100%; 119 | flex-direction: column; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | purge: [], 3 | darkMode: false, // or 'media' or 'class' 4 | theme: { 5 | extend: {}, 6 | }, 7 | variants: { 8 | extend: {}, 9 | }, 10 | plugins: [], 11 | } 12 | --------------------------------------------------------------------------------