├── .babelrc ├── .gitattributes ├── .gitignore ├── README.md ├── README.zh.md ├── backpack.config.js ├── contract └── demo.sol ├── example.env ├── package.json ├── screenshots ├── img.png ├── img_1.png └── img_2.png ├── src ├── .gitignore ├── abi.json ├── abis │ ├── ERC20.json │ ├── bakeryswap.json │ └── pancakeAbi.json ├── config.ts ├── contracts │ ├── call.ts │ ├── index.ts │ ├── multicall │ │ ├── abi.json │ │ └── index.ts │ └── useContract.ts ├── data │ ├── reverse.test.ts │ └── reverses.ts ├── helper.ts ├── index.ts ├── monitor.ts ├── tests │ └── monitor_test.ts ├── tokens.json ├── utils │ ├── api.ts │ ├── int.ts │ ├── logger.ts │ ├── utils.ts │ └── wrappedCurrency.ts ├── wallet.ts └── wallet_test.ts ├── tsconfig.json └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["env", "stage-0"] 3 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | build 4 | .idea -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PancakeSwap or other on bsc chain auto trade bot 2 | 3 | Inspired by the uniswap arbitrage bot blog 4 | 5 | # features 6 | 7 | - [x] Automatic monitoring of liquidity 8 | - [x] Auto swap token choose a best route same like pancakeswap 9 | - [x] Automatically sell when the token value doubles 10 | - [x] Automatic stop loss when the price drops 11 | 12 | # future 13 | - [ ] I will productize it. 14 | - [ ] Supports multiple wallets, multiple tokens, and automatic task management. 15 | - [ ] Support UI manager. 16 | - [ ] SUpport more public chain like heco bsc and more. 17 | - [ ] I will open a paid version and provide services for members 18 | 19 | ## screenshots 20 | monitor wallet and liq 21 | ![Auto](./screenshots/img.png) 22 | 23 | start trade 24 | ![Auto](./screenshots/img_1.png) 25 | 26 | auto check sell point 27 | ![Auto](./screenshots/img_2.png) 28 | -------------------------------------------------------------------------------- /README.zh.md: -------------------------------------------------------------------------------- 1 | # PancakeSwap or other on bsc chain auto trade bot 2 | 3 | Inspired by the uniswap arbitrage bot blog 4 | 5 | # features 6 | 7 | - [x] Automatic monitoring of liquidity 8 | - [x] Auto swap token choose a best route same like pancakeswap 9 | - [x] Automatically sell when the token value doubles 10 | - [x] Automatic stop loss when the price drops 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /backpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | module.exports = { 3 | webpack: (config, options, webpack) => { 4 | config.entry.main = [ 5 | path.join(__dirname, './src/index.ts'), 6 | ]; 7 | // config.devtool = process.env.NODE_ENV === 'development'; 8 | config.mode = process.env.NODE_ENV === 'development' ? 'development' : 'production'; 9 | config.resolve = { 10 | extensions: [".ts", ".js", ".json"] 11 | }; 12 | config.module.rules.push({ 13 | test: /\.ts$/, 14 | loader: 'awesome-typescript-loader', 15 | options: { 16 | sourceMap: true, 17 | productionSourceMap: false, 18 | } 19 | }); 20 | if (process.env.NODE_ENV === 'production') { 21 | //config.productionSourceMap = false; 22 | config.plugins.slice(1, 1); 23 | } 24 | return config 25 | } 26 | }; -------------------------------------------------------------------------------- /contract/demo.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at BscScan.com on 2021-05-03 3 | */ 4 | 5 | // File: ../../../.brownie/packages/OpenZeppelin/openzeppelin-contracts@4.1.0/contracts/proxy/Proxy.sol 6 | 7 | 8 | pragma solidity ^0.8.0; 9 | 10 | /** 11 | * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM 12 | * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to 13 | * be specified by overriding the virtual {_implementation} function. 14 | * 15 | * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a 16 | * different contract through the {_delegate} function. 17 | * 18 | * The success and return data of the delegated call will be returned back to the caller of the proxy. 19 | */ 20 | abstract contract Proxy { 21 | /** 22 | * @dev Delegates the current call to `implementation`. 23 | * 24 | * This function does not return to its internall call site, it will return directly to the external caller. 25 | */ 26 | function _delegate(address implementation) internal virtual { 27 | // solhint-disable-next-line no-inline-assembly 28 | assembly { 29 | // Copy msg.data. We take full control of memory in this inline assembly 30 | // block because it will not return to Solidity code. We overwrite the 31 | // Solidity scratch pad at memory position 0. 32 | calldatacopy(0, 0, calldatasize()) 33 | 34 | // Call the implementation. 35 | // out and outsize are 0 because we don't know the size yet. 36 | let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) 37 | 38 | // Copy the returned data. 39 | returndatacopy(0, 0, returndatasize()) 40 | 41 | switch result 42 | // delegatecall returns 0 on error. 43 | case 0 { revert(0, returndatasize()) } 44 | default { return(0, returndatasize()) } 45 | } 46 | } 47 | 48 | /** 49 | * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function 50 | * and {_fallback} should delegate. 51 | */ 52 | function _implementation() internal view virtual returns (address); 53 | 54 | /** 55 | * @dev Delegates the current call to the address returned by `_implementation()`. 56 | * 57 | * This function does not return to its internall call site, it will return directly to the external caller. 58 | */ 59 | function _fallback() internal virtual { 60 | _beforeFallback(); 61 | _delegate(_implementation()); 62 | } 63 | 64 | /** 65 | * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other 66 | * function in the contract matches the call data. 67 | */ 68 | fallback () external payable virtual { 69 | _fallback(); 70 | } 71 | 72 | /** 73 | * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data 74 | * is empty. 75 | */ 76 | receive () external payable virtual { 77 | _fallback(); 78 | } 79 | 80 | /** 81 | * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback` 82 | * call, or as part of the Solidity `fallback` or `receive` functions. 83 | * 84 | * If overriden should call `super._beforeFallback()`. 85 | */ 86 | function _beforeFallback() internal virtual { 87 | } 88 | } 89 | 90 | // File: ../../../.brownie/packages/OpenZeppelin/openzeppelin-contracts@4.1.0/contracts/proxy/beacon/IBeacon.sol 91 | 92 | 93 | pragma solidity ^0.8.0; 94 | 95 | /** 96 | * @dev This is the interface that {BeaconProxy} expects of its beacon. 97 | */ 98 | interface IBeacon { 99 | /** 100 | * @dev Must return an address that can be used as a delegate call target. 101 | * 102 | * {BeaconProxy} will check that this address is a contract. 103 | */ 104 | function implementation() external view returns (address); 105 | } 106 | 107 | // File: ../../../.brownie/packages/OpenZeppelin/openzeppelin-contracts@4.1.0/contracts/utils/Address.sol 108 | 109 | 110 | pragma solidity ^0.8.0; 111 | 112 | /** 113 | * @dev Collection of functions related to the address type 114 | */ 115 | library Address { 116 | /** 117 | * @dev Returns true if `account` is a contract. 118 | * 119 | * [IMPORTANT] 120 | * ==== 121 | * It is unsafe to assume that an address for which this function returns 122 | * false is an externally-owned account (EOA) and not a contract. 123 | * 124 | * Among others, `isContract` will return false for the following 125 | * types of addresses: 126 | * 127 | * - an externally-owned account 128 | * - a contract in construction 129 | * - an address where a contract will be created 130 | * - an address where a contract lived, but was destroyed 131 | * ==== 132 | */ 133 | function isContract(address account) internal view returns (bool) { 134 | // This method relies on extcodesize, which returns 0 for contracts in 135 | // construction, since the code is only stored at the end of the 136 | // constructor execution. 137 | 138 | uint256 size; 139 | // solhint-disable-next-line no-inline-assembly 140 | assembly { size := extcodesize(account) } 141 | return size > 0; 142 | } 143 | 144 | /** 145 | * @dev Replacement for Solidity's `transfer`: sends `amount` wei to 146 | * `recipient`, forwarding all available gas and reverting on errors. 147 | * 148 | * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost 149 | * of certain opcodes, possibly making contracts go over the 2300 gas limit 150 | * imposed by `transfer`, making them unable to receive funds via 151 | * `transfer`. {sendValue} removes this limitation. 152 | * 153 | * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. 154 | * 155 | * IMPORTANT: because control is transferred to `recipient`, care must be 156 | * taken to not create reentrancy vulnerabilities. Consider using 157 | * {ReentrancyGuard} or the 158 | * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. 159 | */ 160 | function sendValue(address payable recipient, uint256 amount) internal { 161 | require(address(this).balance >= amount, "Address: insufficient balance"); 162 | 163 | // solhint-disable-next-line avoid-low-level-calls, avoid-call-value 164 | (bool success, ) = recipient.call{ value: amount }(""); 165 | require(success, "Address: unable to send value, recipient may have reverted"); 166 | } 167 | 168 | /** 169 | * @dev Performs a Solidity function call using a low level `call`. A 170 | * plain`call` is an unsafe replacement for a function call: use this 171 | * function instead. 172 | * 173 | * If `target` reverts with a revert reason, it is bubbled up by this 174 | * function (like regular Solidity function calls). 175 | * 176 | * Returns the raw returned data. To convert to the expected return value, 177 | * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. 178 | * 179 | * Requirements: 180 | * 181 | * - `target` must be a contract. 182 | * - calling `target` with `data` must not revert. 183 | * 184 | * _Available since v3.1._ 185 | */ 186 | function functionCall(address target, bytes memory data) internal returns (bytes memory) { 187 | return functionCall(target, data, "Address: low-level call failed"); 188 | } 189 | 190 | /** 191 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with 192 | * `errorMessage` as a fallback revert reason when `target` reverts. 193 | * 194 | * _Available since v3.1._ 195 | */ 196 | function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { 197 | return functionCallWithValue(target, data, 0, errorMessage); 198 | } 199 | 200 | /** 201 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 202 | * but also transferring `value` wei to `target`. 203 | * 204 | * Requirements: 205 | * 206 | * - the calling contract must have an ETH balance of at least `value`. 207 | * - the called Solidity function must be `payable`. 208 | * 209 | * _Available since v3.1._ 210 | */ 211 | function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { 212 | return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); 213 | } 214 | 215 | /** 216 | * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but 217 | * with `errorMessage` as a fallback revert reason when `target` reverts. 218 | * 219 | * _Available since v3.1._ 220 | */ 221 | function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { 222 | require(address(this).balance >= value, "Address: insufficient balance for call"); 223 | require(isContract(target), "Address: call to non-contract"); 224 | 225 | // solhint-disable-next-line avoid-low-level-calls 226 | (bool success, bytes memory returndata) = target.call{ value: value }(data); 227 | return _verifyCallResult(success, returndata, errorMessage); 228 | } 229 | 230 | /** 231 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 232 | * but performing a static call. 233 | * 234 | * _Available since v3.3._ 235 | */ 236 | function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { 237 | return functionStaticCall(target, data, "Address: low-level static call failed"); 238 | } 239 | 240 | /** 241 | * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], 242 | * but performing a static call. 243 | * 244 | * _Available since v3.3._ 245 | */ 246 | function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { 247 | require(isContract(target), "Address: static call to non-contract"); 248 | 249 | // solhint-disable-next-line avoid-low-level-calls 250 | (bool success, bytes memory returndata) = target.staticcall(data); 251 | return _verifyCallResult(success, returndata, errorMessage); 252 | } 253 | 254 | /** 255 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 256 | * but performing a delegate call. 257 | * 258 | * _Available since v3.4._ 259 | */ 260 | function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { 261 | return functionDelegateCall(target, data, "Address: low-level delegate call failed"); 262 | } 263 | 264 | /** 265 | * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], 266 | * but performing a delegate call. 267 | * 268 | * _Available since v3.4._ 269 | */ 270 | function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { 271 | require(isContract(target), "Address: delegate call to non-contract"); 272 | 273 | // solhint-disable-next-line avoid-low-level-calls 274 | (bool success, bytes memory returndata) = target.delegatecall(data); 275 | return _verifyCallResult(success, returndata, errorMessage); 276 | } 277 | 278 | function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { 279 | if (success) { 280 | return returndata; 281 | } else { 282 | // Look for revert reason and bubble it up if present 283 | if (returndata.length > 0) { 284 | // The easiest way to bubble the revert reason is using memory via assembly 285 | 286 | // solhint-disable-next-line no-inline-assembly 287 | assembly { 288 | let returndata_size := mload(returndata) 289 | revert(add(32, returndata), returndata_size) 290 | } 291 | } else { 292 | revert(errorMessage); 293 | } 294 | } 295 | } 296 | } 297 | 298 | // File: ../../../.brownie/packages/OpenZeppelin/openzeppelin-contracts@4.1.0/contracts/utils/StorageSlot.sol 299 | 300 | 301 | pragma solidity ^0.8.0; 302 | 303 | /** 304 | * @dev Library for reading and writing primitive types to specific storage slots. 305 | * 306 | * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. 307 | * This library helps with reading and writing to such slots without the need for inline assembly. 308 | * 309 | * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. 310 | * 311 | * Example usage to set ERC1967 implementation slot: 312 | * ``` 313 | * contract ERC1967 { 314 | * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; 315 | * 316 | * function _getImplementation() internal view returns (address) { 317 | * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; 318 | * } 319 | * 320 | * function _setImplementation(address newImplementation) internal { 321 | * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); 322 | * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; 323 | * } 324 | * } 325 | * ``` 326 | * 327 | * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ 328 | */ 329 | library StorageSlot { 330 | struct AddressSlot { 331 | address value; 332 | } 333 | 334 | struct BooleanSlot { 335 | bool value; 336 | } 337 | 338 | struct Bytes32Slot { 339 | bytes32 value; 340 | } 341 | 342 | struct Uint256Slot { 343 | uint256 value; 344 | } 345 | 346 | /** 347 | * @dev Returns an `AddressSlot` with member `value` located at `slot`. 348 | */ 349 | function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { 350 | assembly { 351 | r.slot := slot 352 | } 353 | } 354 | 355 | /** 356 | * @dev Returns an `BooleanSlot` with member `value` located at `slot`. 357 | */ 358 | function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { 359 | assembly { 360 | r.slot := slot 361 | } 362 | } 363 | 364 | /** 365 | * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. 366 | */ 367 | function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { 368 | assembly { 369 | r.slot := slot 370 | } 371 | } 372 | 373 | /** 374 | * @dev Returns an `Uint256Slot` with member `value` located at `slot`. 375 | */ 376 | function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { 377 | assembly { 378 | r.slot := slot 379 | } 380 | } 381 | } 382 | 383 | // File: ../../../.brownie/packages/OpenZeppelin/openzeppelin-contracts@4.1.0/contracts/proxy/ERC1967/ERC1967Upgrade.sol 384 | 385 | 386 | pragma solidity ^0.8.2; 387 | 388 | 389 | 390 | 391 | /** 392 | * @dev This abstract contract provides getters and event emitting update functions for 393 | * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. 394 | * 395 | * _Available since v4.1._ 396 | * 397 | * @custom:oz-upgrades-unsafe-allow delegatecall 398 | */ 399 | abstract contract ERC1967Upgrade { 400 | // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 401 | bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; 402 | 403 | /** 404 | * @dev Storage slot with the address of the current implementation. 405 | * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is 406 | * validated in the constructor. 407 | */ 408 | bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; 409 | 410 | /** 411 | * @dev Emitted when the implementation is upgraded. 412 | */ 413 | event Upgraded(address indexed implementation); 414 | 415 | /** 416 | * @dev Returns the current implementation address. 417 | */ 418 | function _getImplementation() internal view returns (address) { 419 | return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; 420 | } 421 | 422 | /** 423 | * @dev Stores a new address in the EIP1967 implementation slot. 424 | */ 425 | function _setImplementation(address newImplementation) private { 426 | require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); 427 | StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; 428 | } 429 | 430 | /** 431 | * @dev Perform implementation upgrade 432 | * 433 | * Emits an {Upgraded} event. 434 | */ 435 | function _upgradeTo(address newImplementation) internal { 436 | _setImplementation(newImplementation); 437 | emit Upgraded(newImplementation); 438 | } 439 | 440 | /** 441 | * @dev Perform implementation upgrade with additional setup call. 442 | * 443 | * Emits an {Upgraded} event. 444 | */ 445 | function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal { 446 | _setImplementation(newImplementation); 447 | emit Upgraded(newImplementation); 448 | if (data.length > 0 || forceCall) { 449 | Address.functionDelegateCall(newImplementation, data); 450 | } 451 | } 452 | 453 | /** 454 | * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. 455 | * 456 | * Emits an {Upgraded} event. 457 | */ 458 | function _upgradeToAndCallSecure(address newImplementation, bytes memory data, bool forceCall) internal { 459 | address oldImplementation = _getImplementation(); 460 | 461 | // Initial upgrade and setup call 462 | _setImplementation(newImplementation); 463 | if (data.length > 0 || forceCall) { 464 | Address.functionDelegateCall(newImplementation, data); 465 | } 466 | 467 | // Perform rollback test if not already in progress 468 | StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT); 469 | if (!rollbackTesting.value) { 470 | // Trigger rollback using upgradeTo from the new implementation 471 | rollbackTesting.value = true; 472 | Address.functionDelegateCall( 473 | newImplementation, 474 | abi.encodeWithSignature( 475 | "upgradeTo(address)", 476 | oldImplementation 477 | ) 478 | ); 479 | rollbackTesting.value = false; 480 | // Check rollback was effective 481 | require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades"); 482 | // Finally reset to the new implementation and log the upgrade 483 | _setImplementation(newImplementation); 484 | emit Upgraded(newImplementation); 485 | } 486 | } 487 | 488 | /** 489 | * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does 490 | * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). 491 | * 492 | * Emits a {BeaconUpgraded} event. 493 | */ 494 | function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal { 495 | _setBeacon(newBeacon); 496 | emit BeaconUpgraded(newBeacon); 497 | if (data.length > 0 || forceCall) { 498 | Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); 499 | } 500 | } 501 | 502 | /** 503 | * @dev Storage slot with the admin of the contract. 504 | * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is 505 | * validated in the constructor. 506 | */ 507 | bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; 508 | 509 | /** 510 | * @dev Emitted when the admin account has changed. 511 | */ 512 | event AdminChanged(address previousAdmin, address newAdmin); 513 | 514 | /** 515 | * @dev Returns the current admin. 516 | */ 517 | function _getAdmin() internal view returns (address) { 518 | return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; 519 | } 520 | 521 | /** 522 | * @dev Stores a new address in the EIP1967 admin slot. 523 | */ 524 | function _setAdmin(address newAdmin) private { 525 | require(newAdmin != address(0), "ERC1967: new admin is the zero address"); 526 | StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; 527 | } 528 | 529 | /** 530 | * @dev Changes the admin of the proxy. 531 | * 532 | * Emits an {AdminChanged} event. 533 | */ 534 | function _changeAdmin(address newAdmin) internal { 535 | emit AdminChanged(_getAdmin(), newAdmin); 536 | _setAdmin(newAdmin); 537 | } 538 | 539 | /** 540 | * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. 541 | * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. 542 | */ 543 | bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; 544 | 545 | /** 546 | * @dev Emitted when the beacon is upgraded. 547 | */ 548 | event BeaconUpgraded(address indexed beacon); 549 | 550 | /** 551 | * @dev Returns the current beacon. 552 | */ 553 | function _getBeacon() internal view returns (address) { 554 | return StorageSlot.getAddressSlot(_BEACON_SLOT).value; 555 | } 556 | 557 | /** 558 | * @dev Stores a new beacon in the EIP1967 beacon slot. 559 | */ 560 | function _setBeacon(address newBeacon) private { 561 | require( 562 | Address.isContract(newBeacon), 563 | "ERC1967: new beacon is not a contract" 564 | ); 565 | require( 566 | Address.isContract(IBeacon(newBeacon).implementation()), 567 | "ERC1967: beacon implementation is not a contract" 568 | ); 569 | StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; 570 | } 571 | } 572 | 573 | // File: ../../../.brownie/packages/OpenZeppelin/openzeppelin-contracts@4.1.0/contracts/proxy/ERC1967/ERC1967Proxy.sol 574 | 575 | 576 | pragma solidity ^0.8.0; 577 | 578 | 579 | 580 | /** 581 | * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an 582 | * implementation address that can be changed. This address is stored in storage in the location specified by 583 | * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the 584 | * implementation behind the proxy. 585 | */ 586 | contract ERC1967Proxy is Proxy, ERC1967Upgrade { 587 | /** 588 | * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`. 589 | * 590 | * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded 591 | * function call, and allows initializating the storage of the proxy like a Solidity constructor. 592 | */ 593 | constructor(address _logic, bytes memory _data) payable { 594 | assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1)); 595 | _upgradeToAndCall(_logic, _data, false); 596 | } 597 | 598 | /** 599 | * @dev Returns the current implementation address. 600 | */ 601 | function _implementation() internal view virtual override returns (address impl) { 602 | return ERC1967Upgrade._getImplementation(); 603 | } 604 | } 605 | 606 | // File: ../../../.brownie/packages/OpenZeppelin/openzeppelin-contracts@4.1.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol 607 | 608 | // SPDX-License-Identifier: MIT 609 | 610 | pragma solidity ^0.8.0; 611 | 612 | 613 | /** 614 | * @dev This contract implements a proxy that is upgradeable by an admin. 615 | * 616 | * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector 617 | * clashing], which can potentially be used in an attack, this contract uses the 618 | * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two 619 | * things that go hand in hand: 620 | * 621 | * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if 622 | * that call matches one of the admin functions exposed by the proxy itself. 623 | * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the 624 | * implementation. If the admin tries to call a function on the implementation it will fail with an error that says 625 | * "admin cannot fallback to proxy target". 626 | * 627 | * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing 628 | * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due 629 | * to sudden errors when trying to call a function from the proxy implementation. 630 | * 631 | * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way, 632 | * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy. 633 | */ 634 | contract TransparentUpgradeableProxy is ERC1967Proxy { 635 | /** 636 | * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and 637 | * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}. 638 | */ 639 | constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) { 640 | assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1)); 641 | _changeAdmin(admin_); 642 | } 643 | 644 | /** 645 | * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin. 646 | */ 647 | modifier ifAdmin() { 648 | if (msg.sender == _getAdmin()) { 649 | _; 650 | } else { 651 | _fallback(); 652 | } 653 | } 654 | 655 | /** 656 | * @dev Returns the current admin. 657 | * 658 | * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}. 659 | * 660 | * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the 661 | * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. 662 | * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` 663 | */ 664 | function admin() external ifAdmin returns (address admin_) { 665 | admin_ = _getAdmin(); 666 | } 667 | 668 | /** 669 | * @dev Returns the current implementation. 670 | * 671 | * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}. 672 | * 673 | * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the 674 | * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. 675 | * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc` 676 | */ 677 | function implementation() external ifAdmin returns (address implementation_) { 678 | implementation_ = _implementation(); 679 | } 680 | 681 | /** 682 | * @dev Changes the admin of the proxy. 683 | * 684 | * Emits an {AdminChanged} event. 685 | * 686 | * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}. 687 | */ 688 | function changeAdmin(address newAdmin) external virtual ifAdmin { 689 | _changeAdmin(newAdmin); 690 | } 691 | 692 | /** 693 | * @dev Upgrade the implementation of the proxy. 694 | * 695 | * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}. 696 | */ 697 | function upgradeTo(address newImplementation) external ifAdmin { 698 | _upgradeToAndCall(newImplementation, bytes(""), false); 699 | } 700 | 701 | /** 702 | * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified 703 | * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the 704 | * proxied contract. 705 | * 706 | * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}. 707 | */ 708 | function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin { 709 | _upgradeToAndCall(newImplementation, data, true); 710 | } 711 | 712 | /** 713 | * @dev Returns the current admin. 714 | */ 715 | function _admin() internal view virtual returns (address) { 716 | return _getAdmin(); 717 | } 718 | 719 | /** 720 | * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}. 721 | */ 722 | function _beforeFallback() internal virtual override { 723 | require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target"); 724 | super._beforeFallback(); 725 | } 726 | } -------------------------------------------------------------------------------- /example.env: -------------------------------------------------------------------------------- 1 | ROUTE_SWAP_CHOOSE=pancakeswap 2 | MAX_TAKE_PROFIT_POINT=1.5 3 | MIN_STOP_LOSS_POINT=0.5 4 | WALLET_PRIVATE_KEY= 5 | # token address which you want 6 | SWAP_OUTPUT_TOKEN=0x6a79e08db6c08b8f88703794bf1a47f5a01eb9dc 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "src/index.js", 3 | "license": "MIT", 4 | "private": false, 5 | "browser": { 6 | "crypto": false 7 | }, 8 | "scripts": { 9 | "start": "webpack-dev-server --mode development", 10 | "start:dev": "webpack-dev-server --hot --mode development", 11 | "build": "cross-env NODE_ENV=production backpack build", 12 | "dev": "cross-env NODE_ENV=development ts-node ./src/index.ts", 13 | "test": "jest" 14 | }, 15 | "dependencies": { 16 | "@binance-chain/javascript-sdk": "^4.1.1", 17 | "@ethersproject/contracts": "^5.1.1", 18 | "@ethersproject/units": "^5.1.0", 19 | "@godtoy/pancakeswap-sdk-v2": "^2.2.0", 20 | "@uniswap/v2-core": "^1.0.1", 21 | "@uniswap/v2-periphery": "^1.1.0-beta.0", 22 | "abi": "^0.0.0", 23 | "bn.js": "^5.2.0", 24 | "dotenv": "^10.0.0", 25 | "ethers": "^5.1.4", 26 | "jsbi": "^3.1.4", 27 | "lodash": "^4.17.21", 28 | "log4js": "^6.3.0", 29 | "node-schedule": "^2.0.0", 30 | "web3": "^1.3.6", 31 | "winston": "^3.3.3" 32 | }, 33 | "devDependencies": { 34 | "@babel/core": "^7.10.5", 35 | "@babel/plugin-proposal-class-properties": "^7.10.4", 36 | "@babel/plugin-proposal-object-rest-spread": "^7.0.0", 37 | "@babel/plugin-proposal-private-methods": "^7.10.4", 38 | "@babel/plugin-transform-runtime": "^7.10.5", 39 | "@babel/preset-env": "^7.10.4", 40 | "@babel/preset-stage-0": "^7.8.3", 41 | "@babel/preset-stage-3": "^7.8.3", 42 | "@types/big.js": "^6.1.0", 43 | "@types/bull": "^3.10.3", 44 | "@types/crypto-js": "^4.0.1", 45 | "@types/mongoose": "^5.10.2", 46 | "@types/node": "^11.13.0", 47 | "autoprefixer": "^9.8.5", 48 | "awesome-typescript-loader": "^5.2.1", 49 | "babel-loader": "^8.1.0", 50 | "babel-plugin-transform-imports": "1.5.0", 51 | "babel-plugin-transform-runtime": "^6.23.0", 52 | "backpack-core": "^0.8.4", 53 | "copy-webpack-plugin": "^6.0.4", 54 | "cross-env": "^7.0.3", 55 | "file-loader": "^6.0.0", 56 | "html-webpack-plugin": "^4.3.0", 57 | "jest": "^27.0.1", 58 | "mini-css-extract-plugin": "^0.9.0", 59 | "terser-webpack-plugin": "^5.0.3", 60 | "ts-node": "^10.0.0", 61 | "typescript": "^4.1.2", 62 | "uglify-es-webpack-plugin": "^0.10.0", 63 | "webpack": "^4.44.1", 64 | "webpack-cli": "^3.3.12", 65 | "webpack-dev-server": "^3.11.0", 66 | "webpack-merge": "^5.0.9" 67 | }, 68 | "peerDependencies": {} 69 | } 70 | -------------------------------------------------------------------------------- /screenshots/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gtsigner/bsc-swap-autotrade-bot-v1/58539a8bf62e83cd2b1422feac402a147547e640/screenshots/img.png -------------------------------------------------------------------------------- /screenshots/img_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gtsigner/bsc-swap-autotrade-bot-v1/58539a8bf62e83cd2b1422feac402a147547e640/screenshots/img_1.png -------------------------------------------------------------------------------- /screenshots/img_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gtsigner/bsc-swap-autotrade-bot-v1/58539a8bf62e83cd2b1422feac402a147547e640/screenshots/img_2.png -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | *.env -------------------------------------------------------------------------------- /src/abi.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /src/abis/ERC20.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "constant": true, 4 | "inputs": [], 5 | "name": "name", 6 | "outputs": [{ "name": "", "type": "string" }], 7 | "payable": false, 8 | "stateMutability": "view", 9 | "type": "function" 10 | }, 11 | { 12 | "constant": false, 13 | "inputs": [{ "name": "_spender", "type": "address" }, { "name": "_value", "type": "uint256" }], 14 | "name": "approve", 15 | "outputs": [{ "name": "", "type": "bool" }], 16 | "payable": false, 17 | "stateMutability": "nonpayable", 18 | "type": "function" 19 | }, 20 | { 21 | "constant": true, 22 | "inputs": [], 23 | "name": "totalSupply", 24 | "outputs": [{ "name": "", "type": "uint256" }], 25 | "payable": false, 26 | "stateMutability": "view", 27 | "type": "function" 28 | }, 29 | { 30 | "constant": false, 31 | "inputs": [ 32 | { "name": "_from", "type": "address" }, 33 | { "name": "_to", "type": "address" }, 34 | { "name": "_value", "type": "uint256" } 35 | ], 36 | "name": "transferFrom", 37 | "outputs": [{ "name": "", "type": "bool" }], 38 | "payable": false, 39 | "stateMutability": "nonpayable", 40 | "type": "function" 41 | }, 42 | { 43 | "constant": true, 44 | "inputs": [], 45 | "name": "decimals", 46 | "outputs": [{ "name": "", "type": "uint8" }], 47 | "payable": false, 48 | "stateMutability": "view", 49 | "type": "function" 50 | }, 51 | { 52 | "constant": true, 53 | "inputs": [{ "name": "_owner", "type": "address" }], 54 | "name": "balanceOf", 55 | "outputs": [{ "name": "balance", "type": "uint256" }], 56 | "payable": false, 57 | "stateMutability": "view", 58 | "type": "function" 59 | }, 60 | { 61 | "constant": true, 62 | "inputs": [], 63 | "name": "symbol", 64 | "outputs": [{ "name": "", "type": "string" }], 65 | "payable": false, 66 | "stateMutability": "view", 67 | "type": "function" 68 | }, 69 | { 70 | "constant": false, 71 | "inputs": [{ "name": "_to", "type": "address" }, { "name": "_value", "type": "uint256" }], 72 | "name": "transfer", 73 | "outputs": [{ "name": "", "type": "bool" }], 74 | "payable": false, 75 | "stateMutability": "nonpayable", 76 | "type": "function" 77 | }, 78 | { 79 | "constant": true, 80 | "inputs": [{ "name": "_owner", "type": "address" }, { "name": "_spender", "type": "address" }], 81 | "name": "allowance", 82 | "outputs": [{ "name": "", "type": "uint256" }], 83 | "payable": false, 84 | "stateMutability": "view", 85 | "type": "function" 86 | }, 87 | { "payable": true, "stateMutability": "payable", "type": "fallback" }, 88 | { 89 | "anonymous": false, 90 | "inputs": [ 91 | { "indexed": true, "name": "owner", "type": "address" }, 92 | { "indexed": true, "name": "spender", "type": "address" }, 93 | { "indexed": false, "name": "value", "type": "uint256" } 94 | ], 95 | "name": "Approval", 96 | "type": "event" 97 | }, 98 | { 99 | "anonymous": false, 100 | "inputs": [ 101 | { "indexed": true, "name": "from", "type": "address" }, 102 | { "indexed": true, "name": "to", "type": "address" }, 103 | { "indexed": false, "name": "value", "type": "uint256" } 104 | ], 105 | "name": "Transfer", 106 | "type": "event" 107 | } 108 | ] 109 | -------------------------------------------------------------------------------- /src/abis/bakeryswap.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "_factory", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "address", 11 | "name": "_WBNB", 12 | "type": "address" 13 | } 14 | ], 15 | "stateMutability": "nonpayable", 16 | "type": "constructor" 17 | }, 18 | { 19 | "inputs": [], 20 | "name": "WBNB", 21 | "outputs": [ 22 | { 23 | "internalType": "address", 24 | "name": "", 25 | "type": "address" 26 | } 27 | ], 28 | "stateMutability": "view", 29 | "type": "function" 30 | }, 31 | { 32 | "inputs": [ 33 | { 34 | "internalType": "address", 35 | "name": "tokenA", 36 | "type": "address" 37 | }, 38 | { 39 | "internalType": "address", 40 | "name": "tokenB", 41 | "type": "address" 42 | }, 43 | { 44 | "internalType": "uint256", 45 | "name": "amountADesired", 46 | "type": "uint256" 47 | }, 48 | { 49 | "internalType": "uint256", 50 | "name": "amountBDesired", 51 | "type": "uint256" 52 | }, 53 | { 54 | "internalType": "uint256", 55 | "name": "amountAMin", 56 | "type": "uint256" 57 | }, 58 | { 59 | "internalType": "uint256", 60 | "name": "amountBMin", 61 | "type": "uint256" 62 | }, 63 | { 64 | "internalType": "address", 65 | "name": "to", 66 | "type": "address" 67 | }, 68 | { 69 | "internalType": "uint256", 70 | "name": "deadline", 71 | "type": "uint256" 72 | } 73 | ], 74 | "name": "addLiquidity", 75 | "outputs": [ 76 | { 77 | "internalType": "uint256", 78 | "name": "amountA", 79 | "type": "uint256" 80 | }, 81 | { 82 | "internalType": "uint256", 83 | "name": "amountB", 84 | "type": "uint256" 85 | }, 86 | { 87 | "internalType": "uint256", 88 | "name": "liquidity", 89 | "type": "uint256" 90 | } 91 | ], 92 | "stateMutability": "nonpayable", 93 | "type": "function" 94 | }, 95 | { 96 | "inputs": [ 97 | { 98 | "internalType": "address", 99 | "name": "token", 100 | "type": "address" 101 | }, 102 | { 103 | "internalType": "uint256", 104 | "name": "amountTokenDesired", 105 | "type": "uint256" 106 | }, 107 | { 108 | "internalType": "uint256", 109 | "name": "amountTokenMin", 110 | "type": "uint256" 111 | }, 112 | { 113 | "internalType": "uint256", 114 | "name": "amountBNBMin", 115 | "type": "uint256" 116 | }, 117 | { 118 | "internalType": "address", 119 | "name": "to", 120 | "type": "address" 121 | }, 122 | { 123 | "internalType": "uint256", 124 | "name": "deadline", 125 | "type": "uint256" 126 | } 127 | ], 128 | "name": "addLiquidityBNB", 129 | "outputs": [ 130 | { 131 | "internalType": "uint256", 132 | "name": "amountToken", 133 | "type": "uint256" 134 | }, 135 | { 136 | "internalType": "uint256", 137 | "name": "amountBNB", 138 | "type": "uint256" 139 | }, 140 | { 141 | "internalType": "uint256", 142 | "name": "liquidity", 143 | "type": "uint256" 144 | } 145 | ], 146 | "stateMutability": "payable", 147 | "type": "function" 148 | }, 149 | { 150 | "inputs": [], 151 | "name": "factory", 152 | "outputs": [ 153 | { 154 | "internalType": "address", 155 | "name": "", 156 | "type": "address" 157 | } 158 | ], 159 | "stateMutability": "view", 160 | "type": "function" 161 | }, 162 | { 163 | "inputs": [ 164 | { 165 | "internalType": "uint256", 166 | "name": "amountOut", 167 | "type": "uint256" 168 | }, 169 | { 170 | "internalType": "uint256", 171 | "name": "reserveIn", 172 | "type": "uint256" 173 | }, 174 | { 175 | "internalType": "uint256", 176 | "name": "reserveOut", 177 | "type": "uint256" 178 | } 179 | ], 180 | "name": "getAmountIn", 181 | "outputs": [ 182 | { 183 | "internalType": "uint256", 184 | "name": "amountIn", 185 | "type": "uint256" 186 | } 187 | ], 188 | "stateMutability": "pure", 189 | "type": "function" 190 | }, 191 | { 192 | "inputs": [ 193 | { 194 | "internalType": "uint256", 195 | "name": "amountIn", 196 | "type": "uint256" 197 | }, 198 | { 199 | "internalType": "uint256", 200 | "name": "reserveIn", 201 | "type": "uint256" 202 | }, 203 | { 204 | "internalType": "uint256", 205 | "name": "reserveOut", 206 | "type": "uint256" 207 | } 208 | ], 209 | "name": "getAmountOut", 210 | "outputs": [ 211 | { 212 | "internalType": "uint256", 213 | "name": "amountOut", 214 | "type": "uint256" 215 | } 216 | ], 217 | "stateMutability": "pure", 218 | "type": "function" 219 | }, 220 | { 221 | "inputs": [ 222 | { 223 | "internalType": "uint256", 224 | "name": "amountOut", 225 | "type": "uint256" 226 | }, 227 | { 228 | "internalType": "address[]", 229 | "name": "path", 230 | "type": "address[]" 231 | } 232 | ], 233 | "name": "getAmountsIn", 234 | "outputs": [ 235 | { 236 | "internalType": "uint256[]", 237 | "name": "amounts", 238 | "type": "uint256[]" 239 | } 240 | ], 241 | "stateMutability": "view", 242 | "type": "function" 243 | }, 244 | { 245 | "inputs": [ 246 | { 247 | "internalType": "uint256", 248 | "name": "amountIn", 249 | "type": "uint256" 250 | }, 251 | { 252 | "internalType": "address[]", 253 | "name": "path", 254 | "type": "address[]" 255 | } 256 | ], 257 | "name": "getAmountsOut", 258 | "outputs": [ 259 | { 260 | "internalType": "uint256[]", 261 | "name": "amounts", 262 | "type": "uint256[]" 263 | } 264 | ], 265 | "stateMutability": "view", 266 | "type": "function" 267 | }, 268 | { 269 | "inputs": [ 270 | { 271 | "internalType": "uint256", 272 | "name": "amountA", 273 | "type": "uint256" 274 | }, 275 | { 276 | "internalType": "uint256", 277 | "name": "reserveA", 278 | "type": "uint256" 279 | }, 280 | { 281 | "internalType": "uint256", 282 | "name": "reserveB", 283 | "type": "uint256" 284 | } 285 | ], 286 | "name": "quote", 287 | "outputs": [ 288 | { 289 | "internalType": "uint256", 290 | "name": "amountB", 291 | "type": "uint256" 292 | } 293 | ], 294 | "stateMutability": "pure", 295 | "type": "function" 296 | }, 297 | { 298 | "inputs": [ 299 | { 300 | "internalType": "address", 301 | "name": "tokenA", 302 | "type": "address" 303 | }, 304 | { 305 | "internalType": "address", 306 | "name": "tokenB", 307 | "type": "address" 308 | }, 309 | { 310 | "internalType": "uint256", 311 | "name": "liquidity", 312 | "type": "uint256" 313 | }, 314 | { 315 | "internalType": "uint256", 316 | "name": "amountAMin", 317 | "type": "uint256" 318 | }, 319 | { 320 | "internalType": "uint256", 321 | "name": "amountBMin", 322 | "type": "uint256" 323 | }, 324 | { 325 | "internalType": "address", 326 | "name": "to", 327 | "type": "address" 328 | }, 329 | { 330 | "internalType": "uint256", 331 | "name": "deadline", 332 | "type": "uint256" 333 | } 334 | ], 335 | "name": "removeLiquidity", 336 | "outputs": [ 337 | { 338 | "internalType": "uint256", 339 | "name": "amountA", 340 | "type": "uint256" 341 | }, 342 | { 343 | "internalType": "uint256", 344 | "name": "amountB", 345 | "type": "uint256" 346 | } 347 | ], 348 | "stateMutability": "nonpayable", 349 | "type": "function" 350 | }, 351 | { 352 | "inputs": [ 353 | { 354 | "internalType": "address", 355 | "name": "token", 356 | "type": "address" 357 | }, 358 | { 359 | "internalType": "uint256", 360 | "name": "liquidity", 361 | "type": "uint256" 362 | }, 363 | { 364 | "internalType": "uint256", 365 | "name": "amountTokenMin", 366 | "type": "uint256" 367 | }, 368 | { 369 | "internalType": "uint256", 370 | "name": "amountBNBMin", 371 | "type": "uint256" 372 | }, 373 | { 374 | "internalType": "address", 375 | "name": "to", 376 | "type": "address" 377 | }, 378 | { 379 | "internalType": "uint256", 380 | "name": "deadline", 381 | "type": "uint256" 382 | } 383 | ], 384 | "name": "removeLiquidityBNB", 385 | "outputs": [ 386 | { 387 | "internalType": "uint256", 388 | "name": "amountToken", 389 | "type": "uint256" 390 | }, 391 | { 392 | "internalType": "uint256", 393 | "name": "amountBNB", 394 | "type": "uint256" 395 | } 396 | ], 397 | "stateMutability": "nonpayable", 398 | "type": "function" 399 | }, 400 | { 401 | "inputs": [ 402 | { 403 | "internalType": "address", 404 | "name": "token", 405 | "type": "address" 406 | }, 407 | { 408 | "internalType": "uint256", 409 | "name": "liquidity", 410 | "type": "uint256" 411 | }, 412 | { 413 | "internalType": "uint256", 414 | "name": "amountTokenMin", 415 | "type": "uint256" 416 | }, 417 | { 418 | "internalType": "uint256", 419 | "name": "amountBNBMin", 420 | "type": "uint256" 421 | }, 422 | { 423 | "internalType": "address", 424 | "name": "to", 425 | "type": "address" 426 | }, 427 | { 428 | "internalType": "uint256", 429 | "name": "deadline", 430 | "type": "uint256" 431 | } 432 | ], 433 | "name": "removeLiquidityBNBSupportingFeeOnTransferTokens", 434 | "outputs": [ 435 | { 436 | "internalType": "uint256", 437 | "name": "amountBNB", 438 | "type": "uint256" 439 | } 440 | ], 441 | "stateMutability": "nonpayable", 442 | "type": "function" 443 | }, 444 | { 445 | "inputs": [ 446 | { 447 | "internalType": "address", 448 | "name": "token", 449 | "type": "address" 450 | }, 451 | { 452 | "internalType": "uint256", 453 | "name": "liquidity", 454 | "type": "uint256" 455 | }, 456 | { 457 | "internalType": "uint256", 458 | "name": "amountTokenMin", 459 | "type": "uint256" 460 | }, 461 | { 462 | "internalType": "uint256", 463 | "name": "amountBNBMin", 464 | "type": "uint256" 465 | }, 466 | { 467 | "internalType": "address", 468 | "name": "to", 469 | "type": "address" 470 | }, 471 | { 472 | "internalType": "uint256", 473 | "name": "deadline", 474 | "type": "uint256" 475 | }, 476 | { 477 | "internalType": "bool", 478 | "name": "approveMax", 479 | "type": "bool" 480 | }, 481 | { 482 | "internalType": "uint8", 483 | "name": "v", 484 | "type": "uint8" 485 | }, 486 | { 487 | "internalType": "bytes32", 488 | "name": "r", 489 | "type": "bytes32" 490 | }, 491 | { 492 | "internalType": "bytes32", 493 | "name": "s", 494 | "type": "bytes32" 495 | } 496 | ], 497 | "name": "removeLiquidityBNBWithPermit", 498 | "outputs": [ 499 | { 500 | "internalType": "uint256", 501 | "name": "amountToken", 502 | "type": "uint256" 503 | }, 504 | { 505 | "internalType": "uint256", 506 | "name": "amountBNB", 507 | "type": "uint256" 508 | } 509 | ], 510 | "stateMutability": "nonpayable", 511 | "type": "function" 512 | }, 513 | { 514 | "inputs": [ 515 | { 516 | "internalType": "address", 517 | "name": "token", 518 | "type": "address" 519 | }, 520 | { 521 | "internalType": "uint256", 522 | "name": "liquidity", 523 | "type": "uint256" 524 | }, 525 | { 526 | "internalType": "uint256", 527 | "name": "amountTokenMin", 528 | "type": "uint256" 529 | }, 530 | { 531 | "internalType": "uint256", 532 | "name": "amountBNBMin", 533 | "type": "uint256" 534 | }, 535 | { 536 | "internalType": "address", 537 | "name": "to", 538 | "type": "address" 539 | }, 540 | { 541 | "internalType": "uint256", 542 | "name": "deadline", 543 | "type": "uint256" 544 | }, 545 | { 546 | "internalType": "bool", 547 | "name": "approveMax", 548 | "type": "bool" 549 | }, 550 | { 551 | "internalType": "uint8", 552 | "name": "v", 553 | "type": "uint8" 554 | }, 555 | { 556 | "internalType": "bytes32", 557 | "name": "r", 558 | "type": "bytes32" 559 | }, 560 | { 561 | "internalType": "bytes32", 562 | "name": "s", 563 | "type": "bytes32" 564 | } 565 | ], 566 | "name": "removeLiquidityBNBWithPermitSupportingFeeOnTransferTokens", 567 | "outputs": [ 568 | { 569 | "internalType": "uint256", 570 | "name": "amountBNB", 571 | "type": "uint256" 572 | } 573 | ], 574 | "stateMutability": "nonpayable", 575 | "type": "function" 576 | }, 577 | { 578 | "inputs": [ 579 | { 580 | "internalType": "address", 581 | "name": "tokenA", 582 | "type": "address" 583 | }, 584 | { 585 | "internalType": "address", 586 | "name": "tokenB", 587 | "type": "address" 588 | }, 589 | { 590 | "internalType": "uint256", 591 | "name": "liquidity", 592 | "type": "uint256" 593 | }, 594 | { 595 | "internalType": "uint256", 596 | "name": "amountAMin", 597 | "type": "uint256" 598 | }, 599 | { 600 | "internalType": "uint256", 601 | "name": "amountBMin", 602 | "type": "uint256" 603 | }, 604 | { 605 | "internalType": "address", 606 | "name": "to", 607 | "type": "address" 608 | }, 609 | { 610 | "internalType": "uint256", 611 | "name": "deadline", 612 | "type": "uint256" 613 | }, 614 | { 615 | "internalType": "bool", 616 | "name": "approveMax", 617 | "type": "bool" 618 | }, 619 | { 620 | "internalType": "uint8", 621 | "name": "v", 622 | "type": "uint8" 623 | }, 624 | { 625 | "internalType": "bytes32", 626 | "name": "r", 627 | "type": "bytes32" 628 | }, 629 | { 630 | "internalType": "bytes32", 631 | "name": "s", 632 | "type": "bytes32" 633 | } 634 | ], 635 | "name": "removeLiquidityWithPermit", 636 | "outputs": [ 637 | { 638 | "internalType": "uint256", 639 | "name": "amountA", 640 | "type": "uint256" 641 | }, 642 | { 643 | "internalType": "uint256", 644 | "name": "amountB", 645 | "type": "uint256" 646 | } 647 | ], 648 | "stateMutability": "nonpayable", 649 | "type": "function" 650 | }, 651 | { 652 | "inputs": [ 653 | { 654 | "internalType": "uint256", 655 | "name": "amountOut", 656 | "type": "uint256" 657 | }, 658 | { 659 | "internalType": "address[]", 660 | "name": "path", 661 | "type": "address[]" 662 | }, 663 | { 664 | "internalType": "address", 665 | "name": "to", 666 | "type": "address" 667 | }, 668 | { 669 | "internalType": "uint256", 670 | "name": "deadline", 671 | "type": "uint256" 672 | } 673 | ], 674 | "name": "swapBNBForExactTokens", 675 | "outputs": [ 676 | { 677 | "internalType": "uint256[]", 678 | "name": "amounts", 679 | "type": "uint256[]" 680 | } 681 | ], 682 | "stateMutability": "payable", 683 | "type": "function" 684 | }, 685 | { 686 | "inputs": [ 687 | { 688 | "internalType": "uint256", 689 | "name": "amountOutMin", 690 | "type": "uint256" 691 | }, 692 | { 693 | "internalType": "address[]", 694 | "name": "path", 695 | "type": "address[]" 696 | }, 697 | { 698 | "internalType": "address", 699 | "name": "to", 700 | "type": "address" 701 | }, 702 | { 703 | "internalType": "uint256", 704 | "name": "deadline", 705 | "type": "uint256" 706 | } 707 | ], 708 | "name": "swapExactBNBForTokens", 709 | "outputs": [ 710 | { 711 | "internalType": "uint256[]", 712 | "name": "amounts", 713 | "type": "uint256[]" 714 | } 715 | ], 716 | "stateMutability": "payable", 717 | "type": "function" 718 | }, 719 | { 720 | "inputs": [ 721 | { 722 | "internalType": "uint256", 723 | "name": "amountOutMin", 724 | "type": "uint256" 725 | }, 726 | { 727 | "internalType": "address[]", 728 | "name": "path", 729 | "type": "address[]" 730 | }, 731 | { 732 | "internalType": "address", 733 | "name": "to", 734 | "type": "address" 735 | }, 736 | { 737 | "internalType": "uint256", 738 | "name": "deadline", 739 | "type": "uint256" 740 | } 741 | ], 742 | "name": "swapExactBNBForTokensSupportingFeeOnTransferTokens", 743 | "outputs": [], 744 | "stateMutability": "payable", 745 | "type": "function" 746 | }, 747 | { 748 | "inputs": [ 749 | { 750 | "internalType": "uint256", 751 | "name": "amountIn", 752 | "type": "uint256" 753 | }, 754 | { 755 | "internalType": "uint256", 756 | "name": "amountOutMin", 757 | "type": "uint256" 758 | }, 759 | { 760 | "internalType": "address[]", 761 | "name": "path", 762 | "type": "address[]" 763 | }, 764 | { 765 | "internalType": "address", 766 | "name": "to", 767 | "type": "address" 768 | }, 769 | { 770 | "internalType": "uint256", 771 | "name": "deadline", 772 | "type": "uint256" 773 | } 774 | ], 775 | "name": "swapExactTokensForBNB", 776 | "outputs": [ 777 | { 778 | "internalType": "uint256[]", 779 | "name": "amounts", 780 | "type": "uint256[]" 781 | } 782 | ], 783 | "stateMutability": "nonpayable", 784 | "type": "function" 785 | }, 786 | { 787 | "inputs": [ 788 | { 789 | "internalType": "uint256", 790 | "name": "amountIn", 791 | "type": "uint256" 792 | }, 793 | { 794 | "internalType": "uint256", 795 | "name": "amountOutMin", 796 | "type": "uint256" 797 | }, 798 | { 799 | "internalType": "address[]", 800 | "name": "path", 801 | "type": "address[]" 802 | }, 803 | { 804 | "internalType": "address", 805 | "name": "to", 806 | "type": "address" 807 | }, 808 | { 809 | "internalType": "uint256", 810 | "name": "deadline", 811 | "type": "uint256" 812 | } 813 | ], 814 | "name": "swapExactTokensForBNBSupportingFeeOnTransferTokens", 815 | "outputs": [], 816 | "stateMutability": "nonpayable", 817 | "type": "function" 818 | }, 819 | { 820 | "inputs": [ 821 | { 822 | "internalType": "uint256", 823 | "name": "amountIn", 824 | "type": "uint256" 825 | }, 826 | { 827 | "internalType": "uint256", 828 | "name": "amountOutMin", 829 | "type": "uint256" 830 | }, 831 | { 832 | "internalType": "address[]", 833 | "name": "path", 834 | "type": "address[]" 835 | }, 836 | { 837 | "internalType": "address", 838 | "name": "to", 839 | "type": "address" 840 | }, 841 | { 842 | "internalType": "uint256", 843 | "name": "deadline", 844 | "type": "uint256" 845 | } 846 | ], 847 | "name": "swapExactTokensForTokens", 848 | "outputs": [ 849 | { 850 | "internalType": "uint256[]", 851 | "name": "amounts", 852 | "type": "uint256[]" 853 | } 854 | ], 855 | "stateMutability": "nonpayable", 856 | "type": "function" 857 | }, 858 | { 859 | "inputs": [ 860 | { 861 | "internalType": "uint256", 862 | "name": "amountIn", 863 | "type": "uint256" 864 | }, 865 | { 866 | "internalType": "uint256", 867 | "name": "amountOutMin", 868 | "type": "uint256" 869 | }, 870 | { 871 | "internalType": "address[]", 872 | "name": "path", 873 | "type": "address[]" 874 | }, 875 | { 876 | "internalType": "address", 877 | "name": "to", 878 | "type": "address" 879 | }, 880 | { 881 | "internalType": "uint256", 882 | "name": "deadline", 883 | "type": "uint256" 884 | } 885 | ], 886 | "name": "swapExactTokensForTokensSupportingFeeOnTransferTokens", 887 | "outputs": [], 888 | "stateMutability": "nonpayable", 889 | "type": "function" 890 | }, 891 | { 892 | "inputs": [ 893 | { 894 | "internalType": "uint256", 895 | "name": "amountOut", 896 | "type": "uint256" 897 | }, 898 | { 899 | "internalType": "uint256", 900 | "name": "amountInMax", 901 | "type": "uint256" 902 | }, 903 | { 904 | "internalType": "address[]", 905 | "name": "path", 906 | "type": "address[]" 907 | }, 908 | { 909 | "internalType": "address", 910 | "name": "to", 911 | "type": "address" 912 | }, 913 | { 914 | "internalType": "uint256", 915 | "name": "deadline", 916 | "type": "uint256" 917 | } 918 | ], 919 | "name": "swapTokensForExactBNB", 920 | "outputs": [ 921 | { 922 | "internalType": "uint256[]", 923 | "name": "amounts", 924 | "type": "uint256[]" 925 | } 926 | ], 927 | "stateMutability": "nonpayable", 928 | "type": "function" 929 | }, 930 | { 931 | "inputs": [ 932 | { 933 | "internalType": "uint256", 934 | "name": "amountOut", 935 | "type": "uint256" 936 | }, 937 | { 938 | "internalType": "uint256", 939 | "name": "amountInMax", 940 | "type": "uint256" 941 | }, 942 | { 943 | "internalType": "address[]", 944 | "name": "path", 945 | "type": "address[]" 946 | }, 947 | { 948 | "internalType": "address", 949 | "name": "to", 950 | "type": "address" 951 | }, 952 | { 953 | "internalType": "uint256", 954 | "name": "deadline", 955 | "type": "uint256" 956 | } 957 | ], 958 | "name": "swapTokensForExactTokens", 959 | "outputs": [ 960 | { 961 | "internalType": "uint256[]", 962 | "name": "amounts", 963 | "type": "uint256[]" 964 | } 965 | ], 966 | "stateMutability": "nonpayable", 967 | "type": "function" 968 | }, 969 | { 970 | "stateMutability": "payable", 971 | "type": "receive" 972 | } 973 | ] -------------------------------------------------------------------------------- /src/abis/pancakeAbi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "_factory", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "address", 11 | "name": "_WETH", 12 | "type": "address" 13 | } 14 | ], 15 | "stateMutability": "nonpayable", 16 | "type": "constructor" 17 | }, 18 | { 19 | "inputs": [], 20 | "name": "WETH", 21 | "outputs": [ 22 | { 23 | "internalType": "address", 24 | "name": "", 25 | "type": "address" 26 | } 27 | ], 28 | "stateMutability": "view", 29 | "type": "function" 30 | }, 31 | { 32 | "inputs": [ 33 | { 34 | "internalType": "address", 35 | "name": "tokenA", 36 | "type": "address" 37 | }, 38 | { 39 | "internalType": "address", 40 | "name": "tokenB", 41 | "type": "address" 42 | }, 43 | { 44 | "internalType": "uint256", 45 | "name": "amountADesired", 46 | "type": "uint256" 47 | }, 48 | { 49 | "internalType": "uint256", 50 | "name": "amountBDesired", 51 | "type": "uint256" 52 | }, 53 | { 54 | "internalType": "uint256", 55 | "name": "amountAMin", 56 | "type": "uint256" 57 | }, 58 | { 59 | "internalType": "uint256", 60 | "name": "amountBMin", 61 | "type": "uint256" 62 | }, 63 | { 64 | "internalType": "address", 65 | "name": "to", 66 | "type": "address" 67 | }, 68 | { 69 | "internalType": "uint256", 70 | "name": "deadline", 71 | "type": "uint256" 72 | } 73 | ], 74 | "name": "addLiquidity", 75 | "outputs": [ 76 | { 77 | "internalType": "uint256", 78 | "name": "amountA", 79 | "type": "uint256" 80 | }, 81 | { 82 | "internalType": "uint256", 83 | "name": "amountB", 84 | "type": "uint256" 85 | }, 86 | { 87 | "internalType": "uint256", 88 | "name": "liquidity", 89 | "type": "uint256" 90 | } 91 | ], 92 | "stateMutability": "nonpayable", 93 | "type": "function" 94 | }, 95 | { 96 | "inputs": [ 97 | { 98 | "internalType": "address", 99 | "name": "token", 100 | "type": "address" 101 | }, 102 | { 103 | "internalType": "uint256", 104 | "name": "amountTokenDesired", 105 | "type": "uint256" 106 | }, 107 | { 108 | "internalType": "uint256", 109 | "name": "amountTokenMin", 110 | "type": "uint256" 111 | }, 112 | { 113 | "internalType": "uint256", 114 | "name": "amountETHMin", 115 | "type": "uint256" 116 | }, 117 | { 118 | "internalType": "address", 119 | "name": "to", 120 | "type": "address" 121 | }, 122 | { 123 | "internalType": "uint256", 124 | "name": "deadline", 125 | "type": "uint256" 126 | } 127 | ], 128 | "name": "addLiquidityETH", 129 | "outputs": [ 130 | { 131 | "internalType": "uint256", 132 | "name": "amountToken", 133 | "type": "uint256" 134 | }, 135 | { 136 | "internalType": "uint256", 137 | "name": "amountETH", 138 | "type": "uint256" 139 | }, 140 | { 141 | "internalType": "uint256", 142 | "name": "liquidity", 143 | "type": "uint256" 144 | } 145 | ], 146 | "stateMutability": "payable", 147 | "type": "function" 148 | }, 149 | { 150 | "inputs": [], 151 | "name": "factory", 152 | "outputs": [ 153 | { 154 | "internalType": "address", 155 | "name": "", 156 | "type": "address" 157 | } 158 | ], 159 | "stateMutability": "view", 160 | "type": "function" 161 | }, 162 | { 163 | "inputs": [ 164 | { 165 | "internalType": "uint256", 166 | "name": "amountOut", 167 | "type": "uint256" 168 | }, 169 | { 170 | "internalType": "uint256", 171 | "name": "reserveIn", 172 | "type": "uint256" 173 | }, 174 | { 175 | "internalType": "uint256", 176 | "name": "reserveOut", 177 | "type": "uint256" 178 | } 179 | ], 180 | "name": "getAmountIn", 181 | "outputs": [ 182 | { 183 | "internalType": "uint256", 184 | "name": "amountIn", 185 | "type": "uint256" 186 | } 187 | ], 188 | "stateMutability": "pure", 189 | "type": "function" 190 | }, 191 | { 192 | "inputs": [ 193 | { 194 | "internalType": "uint256", 195 | "name": "amountIn", 196 | "type": "uint256" 197 | }, 198 | { 199 | "internalType": "uint256", 200 | "name": "reserveIn", 201 | "type": "uint256" 202 | }, 203 | { 204 | "internalType": "uint256", 205 | "name": "reserveOut", 206 | "type": "uint256" 207 | } 208 | ], 209 | "name": "getAmountOut", 210 | "outputs": [ 211 | { 212 | "internalType": "uint256", 213 | "name": "amountOut", 214 | "type": "uint256" 215 | } 216 | ], 217 | "stateMutability": "pure", 218 | "type": "function" 219 | }, 220 | { 221 | "inputs": [ 222 | { 223 | "internalType": "uint256", 224 | "name": "amountOut", 225 | "type": "uint256" 226 | }, 227 | { 228 | "internalType": "address[]", 229 | "name": "path", 230 | "type": "address[]" 231 | } 232 | ], 233 | "name": "getAmountsIn", 234 | "outputs": [ 235 | { 236 | "internalType": "uint256[]", 237 | "name": "amounts", 238 | "type": "uint256[]" 239 | } 240 | ], 241 | "stateMutability": "view", 242 | "type": "function" 243 | }, 244 | { 245 | "inputs": [ 246 | { 247 | "internalType": "uint256", 248 | "name": "amountIn", 249 | "type": "uint256" 250 | }, 251 | { 252 | "internalType": "address[]", 253 | "name": "path", 254 | "type": "address[]" 255 | } 256 | ], 257 | "name": "getAmountsOut", 258 | "outputs": [ 259 | { 260 | "internalType": "uint256[]", 261 | "name": "amounts", 262 | "type": "uint256[]" 263 | } 264 | ], 265 | "stateMutability": "view", 266 | "type": "function" 267 | }, 268 | { 269 | "inputs": [ 270 | { 271 | "internalType": "uint256", 272 | "name": "amountA", 273 | "type": "uint256" 274 | }, 275 | { 276 | "internalType": "uint256", 277 | "name": "reserveA", 278 | "type": "uint256" 279 | }, 280 | { 281 | "internalType": "uint256", 282 | "name": "reserveB", 283 | "type": "uint256" 284 | } 285 | ], 286 | "name": "quote", 287 | "outputs": [ 288 | { 289 | "internalType": "uint256", 290 | "name": "amountB", 291 | "type": "uint256" 292 | } 293 | ], 294 | "stateMutability": "pure", 295 | "type": "function" 296 | }, 297 | { 298 | "inputs": [ 299 | { 300 | "internalType": "address", 301 | "name": "tokenA", 302 | "type": "address" 303 | }, 304 | { 305 | "internalType": "address", 306 | "name": "tokenB", 307 | "type": "address" 308 | }, 309 | { 310 | "internalType": "uint256", 311 | "name": "liquidity", 312 | "type": "uint256" 313 | }, 314 | { 315 | "internalType": "uint256", 316 | "name": "amountAMin", 317 | "type": "uint256" 318 | }, 319 | { 320 | "internalType": "uint256", 321 | "name": "amountBMin", 322 | "type": "uint256" 323 | }, 324 | { 325 | "internalType": "address", 326 | "name": "to", 327 | "type": "address" 328 | }, 329 | { 330 | "internalType": "uint256", 331 | "name": "deadline", 332 | "type": "uint256" 333 | } 334 | ], 335 | "name": "removeLiquidity", 336 | "outputs": [ 337 | { 338 | "internalType": "uint256", 339 | "name": "amountA", 340 | "type": "uint256" 341 | }, 342 | { 343 | "internalType": "uint256", 344 | "name": "amountB", 345 | "type": "uint256" 346 | } 347 | ], 348 | "stateMutability": "nonpayable", 349 | "type": "function" 350 | }, 351 | { 352 | "inputs": [ 353 | { 354 | "internalType": "address", 355 | "name": "token", 356 | "type": "address" 357 | }, 358 | { 359 | "internalType": "uint256", 360 | "name": "liquidity", 361 | "type": "uint256" 362 | }, 363 | { 364 | "internalType": "uint256", 365 | "name": "amountTokenMin", 366 | "type": "uint256" 367 | }, 368 | { 369 | "internalType": "uint256", 370 | "name": "amountETHMin", 371 | "type": "uint256" 372 | }, 373 | { 374 | "internalType": "address", 375 | "name": "to", 376 | "type": "address" 377 | }, 378 | { 379 | "internalType": "uint256", 380 | "name": "deadline", 381 | "type": "uint256" 382 | } 383 | ], 384 | "name": "removeLiquidityETH", 385 | "outputs": [ 386 | { 387 | "internalType": "uint256", 388 | "name": "amountToken", 389 | "type": "uint256" 390 | }, 391 | { 392 | "internalType": "uint256", 393 | "name": "amountETH", 394 | "type": "uint256" 395 | } 396 | ], 397 | "stateMutability": "nonpayable", 398 | "type": "function" 399 | }, 400 | { 401 | "inputs": [ 402 | { 403 | "internalType": "address", 404 | "name": "token", 405 | "type": "address" 406 | }, 407 | { 408 | "internalType": "uint256", 409 | "name": "liquidity", 410 | "type": "uint256" 411 | }, 412 | { 413 | "internalType": "uint256", 414 | "name": "amountTokenMin", 415 | "type": "uint256" 416 | }, 417 | { 418 | "internalType": "uint256", 419 | "name": "amountETHMin", 420 | "type": "uint256" 421 | }, 422 | { 423 | "internalType": "address", 424 | "name": "to", 425 | "type": "address" 426 | }, 427 | { 428 | "internalType": "uint256", 429 | "name": "deadline", 430 | "type": "uint256" 431 | } 432 | ], 433 | "name": "removeLiquidityETHSupportingFeeOnTransferTokens", 434 | "outputs": [ 435 | { 436 | "internalType": "uint256", 437 | "name": "amountETH", 438 | "type": "uint256" 439 | } 440 | ], 441 | "stateMutability": "nonpayable", 442 | "type": "function" 443 | }, 444 | { 445 | "inputs": [ 446 | { 447 | "internalType": "address", 448 | "name": "token", 449 | "type": "address" 450 | }, 451 | { 452 | "internalType": "uint256", 453 | "name": "liquidity", 454 | "type": "uint256" 455 | }, 456 | { 457 | "internalType": "uint256", 458 | "name": "amountTokenMin", 459 | "type": "uint256" 460 | }, 461 | { 462 | "internalType": "uint256", 463 | "name": "amountETHMin", 464 | "type": "uint256" 465 | }, 466 | { 467 | "internalType": "address", 468 | "name": "to", 469 | "type": "address" 470 | }, 471 | { 472 | "internalType": "uint256", 473 | "name": "deadline", 474 | "type": "uint256" 475 | }, 476 | { 477 | "internalType": "bool", 478 | "name": "approveMax", 479 | "type": "bool" 480 | }, 481 | { 482 | "internalType": "uint8", 483 | "name": "v", 484 | "type": "uint8" 485 | }, 486 | { 487 | "internalType": "bytes32", 488 | "name": "r", 489 | "type": "bytes32" 490 | }, 491 | { 492 | "internalType": "bytes32", 493 | "name": "s", 494 | "type": "bytes32" 495 | } 496 | ], 497 | "name": "removeLiquidityETHWithPermit", 498 | "outputs": [ 499 | { 500 | "internalType": "uint256", 501 | "name": "amountToken", 502 | "type": "uint256" 503 | }, 504 | { 505 | "internalType": "uint256", 506 | "name": "amountETH", 507 | "type": "uint256" 508 | } 509 | ], 510 | "stateMutability": "nonpayable", 511 | "type": "function" 512 | }, 513 | { 514 | "inputs": [ 515 | { 516 | "internalType": "address", 517 | "name": "token", 518 | "type": "address" 519 | }, 520 | { 521 | "internalType": "uint256", 522 | "name": "liquidity", 523 | "type": "uint256" 524 | }, 525 | { 526 | "internalType": "uint256", 527 | "name": "amountTokenMin", 528 | "type": "uint256" 529 | }, 530 | { 531 | "internalType": "uint256", 532 | "name": "amountETHMin", 533 | "type": "uint256" 534 | }, 535 | { 536 | "internalType": "address", 537 | "name": "to", 538 | "type": "address" 539 | }, 540 | { 541 | "internalType": "uint256", 542 | "name": "deadline", 543 | "type": "uint256" 544 | }, 545 | { 546 | "internalType": "bool", 547 | "name": "approveMax", 548 | "type": "bool" 549 | }, 550 | { 551 | "internalType": "uint8", 552 | "name": "v", 553 | "type": "uint8" 554 | }, 555 | { 556 | "internalType": "bytes32", 557 | "name": "r", 558 | "type": "bytes32" 559 | }, 560 | { 561 | "internalType": "bytes32", 562 | "name": "s", 563 | "type": "bytes32" 564 | } 565 | ], 566 | "name": "removeLiquidityETHWithPermitSupportingFeeOnTransferTokens", 567 | "outputs": [ 568 | { 569 | "internalType": "uint256", 570 | "name": "amountETH", 571 | "type": "uint256" 572 | } 573 | ], 574 | "stateMutability": "nonpayable", 575 | "type": "function" 576 | }, 577 | { 578 | "inputs": [ 579 | { 580 | "internalType": "address", 581 | "name": "tokenA", 582 | "type": "address" 583 | }, 584 | { 585 | "internalType": "address", 586 | "name": "tokenB", 587 | "type": "address" 588 | }, 589 | { 590 | "internalType": "uint256", 591 | "name": "liquidity", 592 | "type": "uint256" 593 | }, 594 | { 595 | "internalType": "uint256", 596 | "name": "amountAMin", 597 | "type": "uint256" 598 | }, 599 | { 600 | "internalType": "uint256", 601 | "name": "amountBMin", 602 | "type": "uint256" 603 | }, 604 | { 605 | "internalType": "address", 606 | "name": "to", 607 | "type": "address" 608 | }, 609 | { 610 | "internalType": "uint256", 611 | "name": "deadline", 612 | "type": "uint256" 613 | }, 614 | { 615 | "internalType": "bool", 616 | "name": "approveMax", 617 | "type": "bool" 618 | }, 619 | { 620 | "internalType": "uint8", 621 | "name": "v", 622 | "type": "uint8" 623 | }, 624 | { 625 | "internalType": "bytes32", 626 | "name": "r", 627 | "type": "bytes32" 628 | }, 629 | { 630 | "internalType": "bytes32", 631 | "name": "s", 632 | "type": "bytes32" 633 | } 634 | ], 635 | "name": "removeLiquidityWithPermit", 636 | "outputs": [ 637 | { 638 | "internalType": "uint256", 639 | "name": "amountA", 640 | "type": "uint256" 641 | }, 642 | { 643 | "internalType": "uint256", 644 | "name": "amountB", 645 | "type": "uint256" 646 | } 647 | ], 648 | "stateMutability": "nonpayable", 649 | "type": "function" 650 | }, 651 | { 652 | "inputs": [ 653 | { 654 | "internalType": "uint256", 655 | "name": "amountOut", 656 | "type": "uint256" 657 | }, 658 | { 659 | "internalType": "address[]", 660 | "name": "path", 661 | "type": "address[]" 662 | }, 663 | { 664 | "internalType": "address", 665 | "name": "to", 666 | "type": "address" 667 | }, 668 | { 669 | "internalType": "uint256", 670 | "name": "deadline", 671 | "type": "uint256" 672 | } 673 | ], 674 | "name": "swapETHForExactTokens", 675 | "outputs": [ 676 | { 677 | "internalType": "uint256[]", 678 | "name": "amounts", 679 | "type": "uint256[]" 680 | } 681 | ], 682 | "stateMutability": "payable", 683 | "type": "function" 684 | }, 685 | { 686 | "inputs": [ 687 | { 688 | "internalType": "uint256", 689 | "name": "amountOutMin", 690 | "type": "uint256" 691 | }, 692 | { 693 | "internalType": "address[]", 694 | "name": "path", 695 | "type": "address[]" 696 | }, 697 | { 698 | "internalType": "address", 699 | "name": "to", 700 | "type": "address" 701 | }, 702 | { 703 | "internalType": "uint256", 704 | "name": "deadline", 705 | "type": "uint256" 706 | } 707 | ], 708 | "name": "swapExactETHForTokens", 709 | "outputs": [ 710 | { 711 | "internalType": "uint256[]", 712 | "name": "amounts", 713 | "type": "uint256[]" 714 | } 715 | ], 716 | "stateMutability": "payable", 717 | "type": "function" 718 | }, 719 | { 720 | "inputs": [ 721 | { 722 | "internalType": "uint256", 723 | "name": "amountOutMin", 724 | "type": "uint256" 725 | }, 726 | { 727 | "internalType": "address[]", 728 | "name": "path", 729 | "type": "address[]" 730 | }, 731 | { 732 | "internalType": "address", 733 | "name": "to", 734 | "type": "address" 735 | }, 736 | { 737 | "internalType": "uint256", 738 | "name": "deadline", 739 | "type": "uint256" 740 | } 741 | ], 742 | "name": "swapExactETHForTokensSupportingFeeOnTransferTokens", 743 | "outputs": [], 744 | "stateMutability": "payable", 745 | "type": "function" 746 | }, 747 | { 748 | "inputs": [ 749 | { 750 | "internalType": "uint256", 751 | "name": "amountIn", 752 | "type": "uint256" 753 | }, 754 | { 755 | "internalType": "uint256", 756 | "name": "amountOutMin", 757 | "type": "uint256" 758 | }, 759 | { 760 | "internalType": "address[]", 761 | "name": "path", 762 | "type": "address[]" 763 | }, 764 | { 765 | "internalType": "address", 766 | "name": "to", 767 | "type": "address" 768 | }, 769 | { 770 | "internalType": "uint256", 771 | "name": "deadline", 772 | "type": "uint256" 773 | } 774 | ], 775 | "name": "swapExactTokensForETH", 776 | "outputs": [ 777 | { 778 | "internalType": "uint256[]", 779 | "name": "amounts", 780 | "type": "uint256[]" 781 | } 782 | ], 783 | "stateMutability": "nonpayable", 784 | "type": "function" 785 | }, 786 | { 787 | "inputs": [ 788 | { 789 | "internalType": "uint256", 790 | "name": "amountIn", 791 | "type": "uint256" 792 | }, 793 | { 794 | "internalType": "uint256", 795 | "name": "amountOutMin", 796 | "type": "uint256" 797 | }, 798 | { 799 | "internalType": "address[]", 800 | "name": "path", 801 | "type": "address[]" 802 | }, 803 | { 804 | "internalType": "address", 805 | "name": "to", 806 | "type": "address" 807 | }, 808 | { 809 | "internalType": "uint256", 810 | "name": "deadline", 811 | "type": "uint256" 812 | } 813 | ], 814 | "name": "swapExactTokensForETHSupportingFeeOnTransferTokens", 815 | "outputs": [], 816 | "stateMutability": "nonpayable", 817 | "type": "function" 818 | }, 819 | { 820 | "inputs": [ 821 | { 822 | "internalType": "uint256", 823 | "name": "amountIn", 824 | "type": "uint256" 825 | }, 826 | { 827 | "internalType": "uint256", 828 | "name": "amountOutMin", 829 | "type": "uint256" 830 | }, 831 | { 832 | "internalType": "address[]", 833 | "name": "path", 834 | "type": "address[]" 835 | }, 836 | { 837 | "internalType": "address", 838 | "name": "to", 839 | "type": "address" 840 | }, 841 | { 842 | "internalType": "uint256", 843 | "name": "deadline", 844 | "type": "uint256" 845 | } 846 | ], 847 | "name": "swapExactTokensForTokens", 848 | "outputs": [ 849 | { 850 | "internalType": "uint256[]", 851 | "name": "amounts", 852 | "type": "uint256[]" 853 | } 854 | ], 855 | "stateMutability": "nonpayable", 856 | "type": "function" 857 | }, 858 | { 859 | "inputs": [ 860 | { 861 | "internalType": "uint256", 862 | "name": "amountIn", 863 | "type": "uint256" 864 | }, 865 | { 866 | "internalType": "uint256", 867 | "name": "amountOutMin", 868 | "type": "uint256" 869 | }, 870 | { 871 | "internalType": "address[]", 872 | "name": "path", 873 | "type": "address[]" 874 | }, 875 | { 876 | "internalType": "address", 877 | "name": "to", 878 | "type": "address" 879 | }, 880 | { 881 | "internalType": "uint256", 882 | "name": "deadline", 883 | "type": "uint256" 884 | } 885 | ], 886 | "name": "swapExactTokensForTokensSupportingFeeOnTransferTokens", 887 | "outputs": [], 888 | "stateMutability": "nonpayable", 889 | "type": "function" 890 | }, 891 | { 892 | "inputs": [ 893 | { 894 | "internalType": "uint256", 895 | "name": "amountOut", 896 | "type": "uint256" 897 | }, 898 | { 899 | "internalType": "uint256", 900 | "name": "amountInMax", 901 | "type": "uint256" 902 | }, 903 | { 904 | "internalType": "address[]", 905 | "name": "path", 906 | "type": "address[]" 907 | }, 908 | { 909 | "internalType": "address", 910 | "name": "to", 911 | "type": "address" 912 | }, 913 | { 914 | "internalType": "uint256", 915 | "name": "deadline", 916 | "type": "uint256" 917 | } 918 | ], 919 | "name": "swapTokensForExactETH", 920 | "outputs": [ 921 | { 922 | "internalType": "uint256[]", 923 | "name": "amounts", 924 | "type": "uint256[]" 925 | } 926 | ], 927 | "stateMutability": "nonpayable", 928 | "type": "function" 929 | }, 930 | { 931 | "inputs": [ 932 | { 933 | "internalType": "uint256", 934 | "name": "amountOut", 935 | "type": "uint256" 936 | }, 937 | { 938 | "internalType": "uint256", 939 | "name": "amountInMax", 940 | "type": "uint256" 941 | }, 942 | { 943 | "internalType": "address[]", 944 | "name": "path", 945 | "type": "address[]" 946 | }, 947 | { 948 | "internalType": "address", 949 | "name": "to", 950 | "type": "address" 951 | }, 952 | { 953 | "internalType": "uint256", 954 | "name": "deadline", 955 | "type": "uint256" 956 | } 957 | ], 958 | "name": "swapTokensForExactTokens", 959 | "outputs": [ 960 | { 961 | "internalType": "uint256[]", 962 | "name": "amounts", 963 | "type": "uint256[]" 964 | } 965 | ], 966 | "stateMutability": "nonpayable", 967 | "type": "function" 968 | }, 969 | { 970 | "stateMutability": "payable", 971 | "type": "receive" 972 | } 973 | ] -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | import {Currency, Pair, ChainId, Token, Percent, JSBI, WETH} from "@godtoy/pancakeswap-sdk-v2"; 2 | import * as ethers from "ethers"; 3 | import env from 'dotenv' 4 | 5 | const envConfig = env.config(); 6 | 7 | export const config: any = { 8 | id: 1, 9 | name: 'BSC Mainnet', 10 | // provider: 'https://bsc-dataseed1.binance.org', 11 | provider: 'https://bsc-dataseed1.defibit.io', 12 | scan: 'https://api.bscscan.com/api', 13 | ws: "wss://bsc-ws-node.nariox.org:443", 14 | explore: 'https://bscscan.com/', 15 | type: 'mainnet', 16 | chainId: 56, 17 | apiKey: '', 18 | icon: 'images/bscpay.png', 19 | walletPvKey: "", 20 | ...envConfig.parsed, 21 | }; 22 | config.walletPvKey = config.WALLET_PRIVATE_KEY; 23 | export const ROUTES = { 24 | pancakeswap: "0x10ED43C718714eb63d5aA57B78B54704E256024E", 25 | BakerySwap: "0xcde540d7eafe93ac5fe6233bee57e1270d3e330f", 26 | } 27 | config.ROUTE_ADDRESS = ROUTES[config.ROUTE_SWAP_CHOOSE] 28 | 29 | if (!config.ROUTE_ADDRESS) { 30 | throw new Error("require route swap address") 31 | } 32 | 33 | export const provider = new ethers.providers.JsonRpcProvider(config.provider) //https://dataseed1.binance.org 34 | export const websocketProvider = new ethers.providers.WebSocketProvider(config.ws) //https://dataseed1.binance.org 35 | 36 | //multicall contract address 37 | //合约 https://bscscan.com/address/0x1Ee38d535d541c55C9dae27B12edf090C608E6Fb#code 38 | const MULTICALL_NETWORKS: { [chainId in ChainId]: string } = { 39 | [ChainId.MAINNET]: '0x1Ee38d535d541c55C9dae27B12edf090C608E6Fb', // TODO 40 | [ChainId.BSCTESTNET]: '0x301907b5835a2d723Fe3e9E8C5Bc5375d5c1236A' 41 | } 42 | 43 | 44 | //BSC chain 45 | export const WBNB = WETH[config.chainId]; 46 | export const CAKE = new Token(ChainId.MAINNET, '0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82', 18, 'CAKE', 'PancakeSwap Token') 47 | export const DAI = new Token(ChainId.MAINNET, '0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3', 18, 'DAI', 'Dai Stablecoin') 48 | export const BUSD = new Token(ChainId.MAINNET, '0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56', 18, 'BUSD', 'Binance USD') 49 | export const BTCB = new Token(ChainId.MAINNET, '0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c', 18, 'BTCB', 'Binance BTC') 50 | export const USDT = new Token(ChainId.MAINNET, '0x55d398326f99059fF775485246999027B3197955', 18, 'USDT', 'Tether USD') 51 | export const UST = new Token(ChainId.MAINNET, '0x23396cF899Ca06c4472205fC903bDB4de249D6fC', 18, 'UST', 'Wrapped UST Token') 52 | export const ETH = new Token(ChainId.MAINNET, '0x2170Ed0880ac9A755fd29B2688956BD959F933F8', 18, 'ETH', 'Binance-Peg Ethereum Token') 53 | 54 | export const TRADE_TOKENS = [WBNB, DAI, BUSD, BTCB, USDT, UST, ETH]; 55 | -------------------------------------------------------------------------------- /src/contracts/call.ts: -------------------------------------------------------------------------------- 1 | export async function callMethod(contract, methodName, inputs) { 2 | return new Promise((resolve, reject) => { 3 | contract.methods[methodName]().call(inputs, (err, result) => { 4 | if (err) { 5 | return reject(err) 6 | } 7 | return resolve(result) 8 | }); 9 | }) 10 | } 11 | 12 | export async function callContractMethod(contract, methodName, inputs?: any, options?: any): Promise { 13 | return new Promise((resolve, reject) => { 14 | contract.methods[methodName](inputs).call(options, (err, result) => { 15 | if (err) { 16 | return reject(err) 17 | } 18 | return resolve(result) 19 | }); 20 | }) 21 | } -------------------------------------------------------------------------------- /src/contracts/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useContract' 2 | export * from './call' -------------------------------------------------------------------------------- /src/contracts/multicall/abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "constant": true, 4 | "inputs": [], 5 | "name": "getCurrentBlockTimestamp", 6 | "outputs": [ 7 | { 8 | "name": "timestamp", 9 | "type": "uint256" 10 | } 11 | ], 12 | "payable": false, 13 | "stateMutability": "view", 14 | "type": "function" 15 | }, 16 | { 17 | "constant": true, 18 | "inputs": [ 19 | { 20 | "components": [{"name": "target","type": "address"},{"name": "callData","type": "bytes"}], 21 | "name": "calls", 22 | "type": "tuple[]" 23 | } 24 | ], 25 | "name": "aggregate", 26 | "outputs": [ 27 | { 28 | "name": "blockNumber", 29 | "type": "uint256" 30 | }, 31 | { 32 | "name": "returnData", 33 | "type": "bytes[]" 34 | } 35 | ], 36 | "payable": false, 37 | "stateMutability": "view", 38 | "type": "function" 39 | }, 40 | { 41 | "constant": true, 42 | "inputs": [], 43 | "name": "getLastBlockHash", 44 | "outputs": [ 45 | { 46 | "name": "blockHash", 47 | "type": "bytes32" 48 | } 49 | ], 50 | "payable": false, 51 | "stateMutability": "view", 52 | "type": "function" 53 | }, 54 | { 55 | "constant": true, 56 | "inputs": [ 57 | { 58 | "name": "addr", 59 | "type": "address" 60 | } 61 | ], 62 | "name": "getEthBalance", 63 | "outputs": [ 64 | { 65 | "name": "balance", 66 | "type": "uint256" 67 | } 68 | ], 69 | "payable": false, 70 | "stateMutability": "view", 71 | "type": "function" 72 | }, 73 | { 74 | "constant": true, 75 | "inputs": [], 76 | "name": "getCurrentBlockDifficulty", 77 | "outputs": [ 78 | { 79 | "name": "difficulty", 80 | "type": "uint256" 81 | } 82 | ], 83 | "payable": false, 84 | "stateMutability": "view", 85 | "type": "function" 86 | }, 87 | { 88 | "constant": true, 89 | "inputs": [], 90 | "name": "getCurrentBlockGasLimit", 91 | "outputs": [ 92 | { 93 | "name": "gaslimit", 94 | "type": "uint256" 95 | } 96 | ], 97 | "payable": false, 98 | "stateMutability": "view", 99 | "type": "function" 100 | }, 101 | { 102 | "constant": true, 103 | "inputs": [], 104 | "name": "getCurrentBlockCoinbase", 105 | "outputs": [ 106 | { 107 | "name": "coinbase", 108 | "type": "address" 109 | } 110 | ], 111 | "payable": false, 112 | "stateMutability": "view", 113 | "type": "function" 114 | }, 115 | { 116 | "constant": true, 117 | "inputs": [ 118 | { 119 | "name": "blockNumber", 120 | "type": "uint256" 121 | } 122 | ], 123 | "name": "getBlockHash", 124 | "outputs": [ 125 | { 126 | "name": "blockHash", 127 | "type": "bytes32" 128 | } 129 | ], 130 | "payable": false, 131 | "stateMutability": "view", 132 | "type": "function" 133 | } 134 | ] -------------------------------------------------------------------------------- /src/contracts/multicall/index.ts: -------------------------------------------------------------------------------- 1 | import MULTICALL_ABI from './abi.json' 2 | import {ChainId} from "@godtoy/pancakeswap-sdk-v2"; 3 | 4 | const MULTICALL_NETWORKS: { [chainId in ChainId]: string } = { 5 | [ChainId.MAINNET]: '0x1Ee38d535d541c55C9dae27B12edf090C608E6Fb', // TODO 6 | [ChainId.BSCTESTNET]: '0x301907b5835a2d723Fe3e9E8C5Bc5375d5c1236A' 7 | } 8 | 9 | export {MULTICALL_ABI, MULTICALL_NETWORKS} 10 | -------------------------------------------------------------------------------- /src/contracts/useContract.ts: -------------------------------------------------------------------------------- 1 | import {MULTICALL_ABI, MULTICALL_NETWORKS} from "./multicall"; 2 | import {web3} from "../wallet"; 3 | import {config} from "../config"; 4 | 5 | //https://docs.binance.org/smart-chain/developer/rpc.html 6 | 7 | export function useMulticallContract(): any { 8 | const chainId = config.chainId 9 | const address = chainId && MULTICALL_NETWORKS[chainId] 10 | // @ts-ignore 11 | return new web3.eth.Contract(MULTICALL_ABI, address) 12 | } 13 | 14 | -------------------------------------------------------------------------------- /src/data/reverse.test.ts: -------------------------------------------------------------------------------- 1 | describe('#chunkArray', () => { 2 | it('size 1', () => { 3 | }) 4 | }) 5 | -------------------------------------------------------------------------------- /src/data/reverses.ts: -------------------------------------------------------------------------------- 1 | import {wrappedCurrency} from '../utils/wrappedCurrency' 2 | import {FunctionFragment, Interface} from "@ethersproject/abi"; 3 | import {abi as IUniswapV2PairABI} from '@uniswap/v2-core/build/IUniswapV2Pair.json' 4 | import {Currency, Pair, TokenAmount} from "@godtoy/pancakeswap-sdk-v2"; 5 | import {config} from "../config"; 6 | import {useMulticallContract, callContractMethod} from "../contracts"; 7 | 8 | const PAIR_INTERFACE = new Interface(IUniswapV2PairABI) 9 | 10 | export enum PairState { 11 | LOADING, 12 | NOT_EXISTS, 13 | EXISTS, 14 | INVALID 15 | } 16 | 17 | const multicallContract = useMulticallContract() 18 | 19 | function decodeMultipleContractSData(data, contractInterface: Interface | undefined, fragment: FunctionFragment | undefined, latestBlockNumber: number | undefined) { 20 | const res: any = { 21 | success: false, 22 | }; 23 | try { 24 | res.success = true; 25 | res.result = contractInterface.decodeFunctionResult(fragment, data) 26 | } catch (e) { 27 | return res; 28 | } 29 | return res 30 | } 31 | 32 | async function useMultipleContractSingleData(addresses: string[], contractInterface: Interface, methodName: string, callInputs?: any, options?: any) { 33 | const fragment = PAIR_INTERFACE.getFunction(methodName) 34 | if (fragment === null) return []; 35 | const callData = contractInterface.encodeFunctionData(fragment, callInputs) 36 | const callers = addresses.map((address) => { 37 | return address && callData ? {address, callData,} : undefined 38 | }) 39 | // return results 40 | let resultsBlockNumber 41 | let returnData 42 | try { 43 | const inputs = callers.filter((obj) => obj).map((obj) => { 44 | return [obj.address, obj.callData] 45 | }); 46 | const res = await callContractMethod(multicallContract, "aggregate", inputs, { 47 | n: Infinity, 48 | minWait: 2500, 49 | maxWait: 3500, 50 | }); 51 | const {returnData, blockNumber} = res; 52 | 53 | //demo results 54 | const data = res.returnData.map((data) => { 55 | return decodeMultipleContractSData(data, contractInterface, fragment, blockNumber) 56 | }) 57 | return data; 58 | } catch (error) { 59 | console.info('Failed to fetch chunk inside retry', error) 60 | throw error 61 | } 62 | } 63 | 64 | export async function usePairs(currencies): Promise<[PairState, Pair | null][]> { 65 | const chainId = config.chainId; 66 | const tokens = currencies.map(([currencyA, currencyB]) => [ 67 | wrappedCurrency(currencyA, chainId), 68 | wrappedCurrency(currencyB, chainId) 69 | ]); 70 | const pairAddresses = tokens.map(([tokenA, tokenB]) => { 71 | return tokenA && tokenB && !tokenA.equals(tokenB) ? Pair.getAddress(tokenA, tokenB) : undefined 72 | }); 73 | const results = await useMultipleContractSingleData(pairAddresses, PAIR_INTERFACE, 'getReserves') 74 | return results.map((result, i) => { 75 | const {result: reserves, success} = result 76 | const tokenA = tokens[i][0] 77 | const tokenB = tokens[i][1] 78 | if (!success) return [PairState.LOADING, null] 79 | if (!tokenA || !tokenB || tokenA.equals(tokenB)) return [PairState.INVALID, null] 80 | if (!reserves) return [PairState.NOT_EXISTS, null] 81 | const {reserve0, reserve1} = reserves 82 | const [token0, token1] = tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA] 83 | return [ 84 | PairState.EXISTS, 85 | new Pair( 86 | new TokenAmount(token0, reserve0.toString()), 87 | new TokenAmount(token1, reserve1.toString()), 88 | ) 89 | ] 90 | }) 91 | } 92 | 93 | export function usePair(tokenA?: Currency, tokenB?: Currency): [PairState, Pair | null] { 94 | return usePairs([[tokenA, tokenB]])[0] 95 | } 96 | -------------------------------------------------------------------------------- /src/helper.ts: -------------------------------------------------------------------------------- 1 | import ERC20_ABI from "./abis/ERC20.json"; 2 | import {config, TRADE_TOKENS} from "./config"; 3 | import * as lodash from "lodash"; 4 | import {Currency, Pair, Token} from "@godtoy/pancakeswap-sdk-v2"; 5 | import {wrappedCurrency} from "./utils/wrappedCurrency"; 6 | import {PairState, usePairs} from "./data/reverses"; 7 | import {callMethod} from "./contracts"; 8 | 9 | const Web3 = require('web3'); 10 | const web3 = new Web3('https://bsc-dataseed1.binance.org:443'); 11 | 12 | //ERC20_ABI 13 | //https://blog.csdn.net/weixin_40345905/article/details/81290891 14 | export async function getContractToken(address: string, decimals?: number, symbol?: string, name?: string): Promise { 15 | const ts = Date.now(); 16 | const tokenAddress = address //ADA ada token address 17 | const contract = new web3.eth.Contract(ERC20_ABI, tokenAddress) 18 | if (!decimals) { 19 | // @ts-ignore 20 | decimals = await callMethod(contract, "decimals", {}) 21 | } 22 | if (!symbol) { 23 | // @ts-ignore 24 | symbol = await callMethod(contract, "symbol", {}) 25 | } 26 | const token = new Token(config.chainId, tokenAddress, decimals, symbol, name) //bnb 27 | return {tokenOutput: token, contract, time: Date.now() - ts} 28 | } 29 | 30 | const basePairs: [Token, Token][] = lodash.flatMap(TRADE_TOKENS, (base): [Token, Token][] => TRADE_TOKENS.map((otherBase) => [base, otherBase])).filter( 31 | ([t0, t1]) => t0.address !== t1.address 32 | ) 33 | 34 | //组装 35 | export async function useAllCommonPairs(currencyA?: Currency, currencyB?: Currency): Promise { 36 | const pairs: any = [...basePairs] 37 | const chainId = config.chainId; 38 | const [tokenA, tokenB] = chainId ? [wrappedCurrency(currencyA, chainId), wrappedCurrency(currencyB, chainId)] : [undefined, undefined]; 39 | if (tokenA && tokenB) { 40 | pairs.push([tokenA, tokenB]) 41 | pairs.push( 42 | ...TRADE_TOKENS.map((base): [Token, Token] => [tokenB, base]), 43 | ...TRADE_TOKENS.map((base): [Token, Token] => [tokenA, base]), 44 | ) 45 | } 46 | const allPairs = await usePairs(pairs) 47 | 48 | const results = allPairs 49 | // filter out invalid pairs 50 | .filter((result): result is [PairState.EXISTS, Pair] => Boolean(result[0] === PairState.EXISTS && result[1])) 51 | // filter out duplicated pairs 52 | .reduce((memo, [, curr]) => { 53 | memo[curr.liquidityToken.address] = memo[curr.liquidityToken.address] ?? curr 54 | return memo 55 | }, {}); 56 | return Object.values(results) 57 | } -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import {ETHER, Percent, Router, Token, Trade} from "@godtoy/pancakeswap-sdk-v2"; 2 | import {MaxUint256} from '@ethersproject/constants' 3 | import {abi as IUniswapV2Router02ABI} from '@uniswap/v2-periphery/build/IUniswapV2Router02.json' 4 | import ERC20 from './abis/ERC20.json' 5 | import {activateAccount, wallet, web3} from './wallet' 6 | import {getContractToken, useAllCommonPairs} from "./helper"; 7 | import {config, provider, WBNB, websocketProvider} from "./config"; 8 | import {parseUnits} from '@ethersproject/units' 9 | import {logger} from "./utils/logger"; 10 | import {Contract, ethers} from "ethers"; 11 | import isZero from "./utils/int"; 12 | import {tryParseAmount} from "./utils/wrappedCurrency"; 13 | import {sleep} from "./utils/utils"; 14 | import EventEmitter from "events"; 15 | 16 | const schedule = require('node-schedule'); 17 | const JSBI = require('jsbi') 18 | 19 | const BIPS_BASE = JSBI.BigInt(10000) 20 | // const ROUTER_ADDRESS = '0x05fF2B0DB69458A0750badebc4f9e13aDd608C7F';//PancakeSwap: Router v1 21 | // const ROUTER_ADDRESS = '0x10ED43C718714eb63d5aA57B78B54704E256024E';//PancakeSwap: Router v2 22 | const ROUTER_ADDRESS = config.ROUTE_ADDRESS 23 | 24 | // @ts-ignore 25 | const routerContract = new web3.eth.Contract(IUniswapV2Router02ABI, ROUTER_ADDRESS); //路由合约 26 | 27 | const outputAddress = config.SWAP_OUTPUT_TOKEN; 28 | 29 | const ERROR = 'Insufficient liquidity for this trade.'; 30 | 31 | // https://www.cnblogs.com/jameszou/p/10131443.html ERC20合约 32 | //监控区块变动 33 | (() => { 34 | const contract = new ethers.Contract(outputAddress, ERC20, websocketProvider).connect(wallet) 35 | contract.on('Transfer', function (from, to, amount) { 36 | // logger.warn("Transfer.event: ", from, to, amount.toString()) 37 | // console.log('started event1'); 38 | // console.log("purchaser:" + purchaser); 39 | // console.log("value:" + value); 40 | // console.log("amount:" + amount, typeof amount); 41 | }) 42 | })(); 43 | 44 | enum TaskStep { 45 | Selling, 46 | Buying 47 | } 48 | 49 | enum SellType { 50 | None = 0, 51 | TakeProfit = 1, 52 | StopLoss = 2, 53 | } 54 | 55 | const task = { 56 | tradeAmount: "0.002",//交换3个 57 | swapOptions: { 58 | feeOnTransfer: false, 59 | allowedSlippage: new Percent(JSBI.BigInt(Math.floor(1200)), BIPS_BASE), //12% 60 | recipient: activateAccount.address, //account address 61 | ttl: 60 * 2, //2min 62 | }, 63 | tradeOptions: { 64 | maxHops: 3, 65 | maxNumResults: 1 66 | }, 67 | _loaded: false, //是否加载完毕 68 | _buyedPrice: 0,//买入的价格 69 | MAX_TAKE_PROFIT_POINT: 1, //翻倍pec 70 | MIN_STOP_LOSS_POINT: 0.5,//最低跌价卖出 71 | wallet: { 72 | outputAmount: "0", 73 | }, 74 | step: TaskStep.Buying, //状态 75 | swap: { 76 | currentPrice: "", 77 | } 78 | } 79 | 80 | class Monitor extends EventEmitter { 81 | private swapper: any 82 | 83 | constructor(swapper) { 84 | super(); 85 | this.swapper = swapper 86 | } 87 | 88 | private running: boolean = false; 89 | 90 | private liquidity = false; 91 | 92 | start() { 93 | this.running = true 94 | this.run().then() 95 | this.monitWallet().then() 96 | } 97 | 98 | private async fetchTrade() { 99 | try { 100 | const amount = task.tradeAmount 101 | const trade = await this.swapper.GetBuyTrade(amount) 102 | const oldQ = this.liquidity; 103 | const newQ = !!trade; 104 | if (oldQ !== newQ) { 105 | this.emit('liquidity.on', trade) //有交易流动性 106 | } 107 | this.liquidity = newQ 108 | if (!trade) { 109 | return 110 | } 111 | this.emit('liquidity.timer', amount, trade) //有交易流动性 112 | } catch (e) { 113 | console.error(e.message) 114 | } 115 | } 116 | 117 | private async run() { 118 | while (this.running) { 119 | await sleep(500) 120 | await this.fetchTrade() 121 | } 122 | // //这个时间不能太短了,不然会被ban 123 | // schedule.scheduleJob('*/1 * * * * *', async () => { 124 | // await this.fetchTrade() 125 | // }); 126 | } 127 | 128 | private async monitWallet() { 129 | while (this.running) { 130 | await sleep(500) 131 | let {output, outputAmount} = await this.swapper.getBalances();//查询出来的账户月 132 | const am = {outputAmount: outputAmount, amount: outputAmount.toString()} 133 | this.emit('wallet.update.output_token', am); 134 | if (!task._loaded) { 135 | task._loaded = true 136 | this.emit('wallet.loaded', am) 137 | } 138 | } 139 | } 140 | 141 | private async monitorSwap() { 142 | //1w * 300 143 | } 144 | } 145 | 146 | const scheduleMonitor = async () => { 147 | const swapper = new Swapper(outputAddress); 148 | await swapper.init() //初始化合约信息 149 | const monitor = new Monitor(swapper) 150 | monitor.start() 151 | 152 | //具有流动性了 153 | monitor.on('liquidity.on', (trade) => { 154 | logger.warn("liquidity changed") 155 | }) 156 | 157 | monitor.on('liquidity.timer', async (amount, trade) => { 158 | const info = swapper.printTrade("liquidity.timer", amount, trade) 159 | //设置当前价格 160 | task.swap.currentPrice = info.executionPrice; 161 | logger.trace(`swap.price.update: ${task.wallet.outputAmount} / percent:${swapper.getPrc(task.swap.currentPrice).toFixed(5)} / [C=${task.swap.currentPrice},B=${task._buyedPrice}]`) //当前价格 162 | if (task._buyedPrice <= 0) return; 163 | await swapper.autoSell(task.wallet.outputAmount, info) //自动卖出 164 | }) 165 | 166 | //当达到一定倍数后自动卖出 167 | monitor.on('wallet.update.output_token', async (wallet) => { 168 | if (task.wallet.outputAmount !== wallet.amount && task._buyedPrice) { 169 | logger.trace(`wallet.update.output_token: ${wallet.amount} / ${swapper.getPrc(task.swap.currentPrice).toFixed(5)}`) //当前价格 170 | } 171 | task.wallet.outputAmount = wallet.amount; 172 | }) 173 | 174 | let running = false; 175 | //任务加载完毕 176 | monitor.on('wallet.loaded', (wallet) => { 177 | running = true; 178 | logger.warn("wallet loaded:", wallet) 179 | }) 180 | 181 | //每分钟的第30秒定时执行一次: //future will set a loop under bsc requests limit instead of a timer schedule 182 | schedule.scheduleJob('*/1 * * * * *', async () => { 183 | if (!running) return; 184 | try { 185 | const amount = task.tradeAmount; 186 | const trade = await swapper.GetBuyTrade(amount); 187 | if (!trade) { 188 | logger.trace("GetBuyTrade:", ERROR); 189 | return 190 | } 191 | await swapper.doBuyTrade(amount, trade); 192 | } catch (e) { 193 | console.error(e.message) 194 | } 195 | }); 196 | } 197 | 198 | export class Swapper { 199 | private outputToken: any; 200 | private readonly outputTokenAddress: string; 201 | private outputTokenContract 202 | private inputTokenContract; 203 | 204 | private inputToken: Token = WBNB; 205 | private tradeOptions = { 206 | maxHops: 3, 207 | maxNumResults: 1, 208 | ...task.tradeOptions 209 | }; 210 | private swapOptions = { 211 | feeOnTransfer: false, 212 | allowedSlippage: new Percent(JSBI.BigInt(Math.floor(1200)), BIPS_BASE), //滑动万分之.. 213 | recipient: activateAccount.address, //account address 214 | ttl: 60 * 2, //2min, 215 | ...task.swapOptions 216 | } 217 | 218 | private accountContract: Contract; 219 | private accountSwapContract: Contract; 220 | 221 | private isTrading = false; 222 | private cached: any = {route: "", price: "",}; 223 | 224 | constructor(outAddress: string) { 225 | this.outputTokenAddress = outAddress 226 | this.accountContract = new ethers.Contract(this.inputToken.address, ERC20, provider) 227 | this.accountContract = this.accountContract.connect(wallet) 228 | this.accountSwapContract = new ethers.Contract(ROUTER_ADDRESS, IUniswapV2Router02ABI, provider).connect(wallet) 229 | } 230 | 231 | async init() { 232 | //init contract 233 | const {tokenOutput} = await getContractToken(this.outputTokenAddress) 234 | this.outputToken = tokenOutput 235 | logger.info(`OutputToken loaded:${this.outputTokenAddress} / ${this.outputToken.symbol} / ${this.outputToken.decimals}`) 236 | 237 | //1.授权output Token交易 238 | await this.approve(this.inputToken.address, MaxUint256) 239 | await this.approve(this.outputToken.address, MaxUint256) 240 | // await this.approve(BUSD.address, MaxUint256) //授权 241 | 242 | // this.inputTokenContract = new ethers.Contract(WBNB, ERC20, provider) 243 | this.outputTokenContract = new ethers.Contract(this.outputToken.address, ERC20, provider) 244 | } 245 | 246 | private async approve(spender: string, amount: any) { 247 | const add = await this.accountContract.allowance(wallet.address, spender) 248 | const apped = ethers.BigNumber.from(add) 249 | if (!apped.gt(0)) { 250 | const res = await this.accountContract.approve(spender, amount) //授权 251 | logger.warn(`approved: ${spender}`, apped.toString()) 252 | } 253 | } 254 | 255 | //获取交易pairs列表 256 | async getPairs(): Promise { 257 | return useAllCommonPairs(this.inputToken, this.outputToken) 258 | } 259 | 260 | //获取账户的现金余额 261 | async getBalances(): Promise { 262 | const walletAddress = await wallet.getAddress() 263 | const outputBalance = await this.outputTokenContract.balanceOf(walletAddress) ///输出token的金额 264 | const valB = ethers.utils.formatUnits(outputBalance, this.outputToken.decimals).toString() //余额1 265 | return {output: outputBalance, outputAmount: valB} 266 | } 267 | 268 | async GetBuyTrade(amount) { 269 | const pairsList = await useAllCommonPairs(this.inputToken, this.outputToken) 270 | const curr = tryParseAmount(amount, ETHER) //parse amount 使用默认 ETHER 才会调用 swapExactETHForTokens 271 | return Trade.bestTradeExactIn(pairsList, curr, this.outputToken, this.tradeOptions)[0] ?? null 272 | } 273 | 274 | async GetSellTrade(amount) { 275 | const pairsList = await this.getPairs() 276 | const ip = this.outputToken 277 | // const op = this.inputToken //将什么给换出来 278 | const op = ETHER //BNB换出来 279 | const curr = tryParseAmount(amount, ip) //换出来 280 | return Trade.bestTradeExactIn(pairsList, curr, op, this.tradeOptions)[0] ?? null 281 | } 282 | 283 | tradeInfo(trade) { 284 | const executionPrice = trade.executionPrice.invert().toSignificant(6); 285 | const nextMidPrice = trade.nextMidPrice.invert().toSignificant(6); 286 | const outputAmount = trade.outputAmount.toSignificant(6); 287 | const inputAmount = trade.inputAmount.toSignificant(6); 288 | const priceImpact = trade.priceImpact.toSignificant(6); 289 | return {executionPrice, nextMidPrice, outputAmount, inputAmount, priceImpact} 290 | } 291 | 292 | private async gas(parameters, options): Promise { 293 | return await this.accountSwapContract.estimateGas[parameters.methodName](...parameters.args, options); 294 | } 295 | 296 | async execSwap(amount: string, trade) { 297 | try { 298 | const info = this.tradeInfo(trade) //交易信息 299 | const startTime = Date.now() 300 | const parameters = Router.swapCallParameters(trade, this.swapOptions) 301 | const encoded_tx = routerContract.methods[parameters.methodName](...parameters.args).encodeABI(); 302 | amount = ethers.utils.formatEther(parameters.value) 303 | const value = parseUnits(amount, trade.inputAmount.decimals) 304 | let transactionObject: any = { 305 | gasLimit: 2062883, //gas费用 306 | // value: value,//转账金额 307 | data: encoded_tx, 308 | from: activateAccount.address, 309 | to: ROUTER_ADDRESS, 310 | value: value, 311 | }; 312 | task._buyedPrice = info.executionPrice; 313 | let routeTag = `Swap:[${trade.inputAmount.currency.symbol}->${trade.outputAmount.currency.symbol}][price=${task._buyedPrice}]` 314 | let gas: any = ""; 315 | try { 316 | const value = parameters.value; 317 | const options = !value || isZero(value) ? {} : {value} 318 | gas = await this.gas(parameters, options) 319 | } catch (e) { 320 | logger.error("gas.error:", e.reason) 321 | } 322 | if (gas) { 323 | // transactionObject.gasLimit = gas.toNumber() * 3 //使用3倍gas费 324 | } 325 | const wasteGas = Date.now() - startTime 326 | logger.trace(`Start.swap: ${routeTag} | ${parameters.methodName}, gasLimit:${gas.toString()} / Time:${wasteGas}ms,value: ${ethers.utils.formatUnits(value, trade.inputAmount.decimals).toString()}`) 327 | const res = await wallet.sendTransaction(transactionObject); 328 | const receipt = await res.wait();//等待区块确认 329 | const transTime = Date.now() - startTime 330 | if (receipt.status) { 331 | logger.info(`Transaction.success: ${routeTag} gasUsed:${receipt.gasUsed.toString()},time:${transTime}ms,confirmations:${receipt.confirmations}`); 332 | task.step = TaskStep.Selling;//已经买入成功 333 | } else { 334 | logger.error("Swap.error:", receipt) 335 | } 336 | } catch (e) { 337 | logger.error("execSwapSell:", e.reason) 338 | } 339 | return 340 | } 341 | 342 | printTrade(tag: string, amount, trade) { 343 | const info = this.tradeInfo(trade) 344 | const old = {...this.cached} 345 | this.cached.route = SwapRoutePrint(trade).join('->') 346 | this.cached.price = info.executionPrice 347 | if (this.cached.route != old.route || this.cached.price != old.price) { 348 | logger.warn(`[${tag}]Route.stateChange: ${SwapRoutePrint(trade).join('->')} / Price:${info.executionPrice},Input:${info.inputAmount},Output:${info.outputAmount}`) 349 | } 350 | return info 351 | } 352 | 353 | //do Sell 354 | async doBuyTrade(amount, trade) { 355 | const info = this.tradeInfo(trade) 356 | amount = info.inputAmount; 357 | if (!this.isTrading && this.canBuyMore()) { 358 | this.isTrading = true 359 | await this.execSwap(amount, trade).finally(() => { 360 | this.isTrading = false 361 | }) 362 | } 363 | } 364 | 365 | //是否能买 366 | private canBuyMore(): boolean { 367 | if (!task._loaded) return false;//加载完毕 368 | if (this.isSelling) return false;//正在卖出 369 | return task.step === TaskStep.Buying; 370 | } 371 | 372 | //自动卖出 373 | private isSelling = false;//是否正在卖出 374 | 375 | public getPrc(currentPrice) { 376 | return (currentPrice / task._buyedPrice) 377 | } 378 | 379 | private async _doSell(amount, currentPrice) { 380 | try { 381 | const prc = (currentPrice / task._buyedPrice) 382 | let needSellType = SellType.None; 383 | if (prc >= task.MAX_TAKE_PROFIT_POINT) { 384 | needSellType = SellType.TakeProfit 385 | } 386 | if (prc <= task.MIN_STOP_LOSS_POINT) { 387 | needSellType = SellType.StopLoss 388 | } 389 | if (needSellType === SellType.None) return; //Unknown 390 | logger.trace(`AutoSell->[${prc},${needSellType}]->BuyPrice:${task._buyedPrice}->CurrentPrice:${currentPrice},amount:${task.wallet.outputAmount}`) 391 | const trade = await this.GetSellTrade(amount); 392 | if (!trade) { 393 | logger.trace("SellTrade:", ERROR); 394 | return 395 | } 396 | const info = this.tradeInfo(trade) 397 | amount = info.inputAmount; 398 | await this.execSwap(amount, trade); 399 | } catch (e) { 400 | console.error(e.message) 401 | } 402 | } 403 | 404 | public async autoSell(amount, info) { 405 | if (this.isSelling) return; //返回 406 | this.isSelling = true; 407 | await this._doSell(amount, info.executionPrice).finally(() => { 408 | this.isSelling = false; 409 | }) 410 | } 411 | } 412 | 413 | scheduleMonitor(); 414 | 415 | function SwapRoutePrint(trade: Trade) { 416 | return trade.route.path.map((token, i, path) => { 417 | return token.symbol 418 | }) 419 | } 420 | -------------------------------------------------------------------------------- /src/monitor.ts: -------------------------------------------------------------------------------- 1 | import EventEmitter from "events"; 2 | const schedule = require('node-schedule'); 3 | 4 | export class Monitor extends EventEmitter { 5 | constructor() { 6 | super(); 7 | } 8 | } -------------------------------------------------------------------------------- /src/tests/monitor_test.ts: -------------------------------------------------------------------------------- 1 | import {ethers} from "ethers"; 2 | import ERC20 from "../abis/ERC20.json"; 3 | import {websocketProvider} from "../config"; 4 | import {wallet} from "../wallet"; 5 | import {logger} from "../utils/logger"; 6 | 7 | const outputAddress = "0xac51066d7bec65dc4589368da368b212745d63e8" //"ALICE" 8 | 9 | const ERROR = 'Insufficient liquidity for this trade.'; 10 | 11 | // https://www.cnblogs.com/jameszou/p/10131443.html ERC20合约 12 | //监控区块变动 13 | (() => { 14 | const contract = new ethers.Contract(outputAddress, ERC20, websocketProvider).connect(wallet) 15 | contract.on('Transfer', function (from, to, amount) { 16 | logger.warn("Transfer.event: ", from, to, amount.toString()) 17 | }) 18 | })(); -------------------------------------------------------------------------------- /src/utils/api.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import URL from 'url' 3 | 4 | //判断是否是服务端渲染 5 | const baseURL = process.env.BASE_API; 6 | const instance = axios.create({ 7 | baseURL: baseURL, 8 | timeout: 5000, 9 | withCredentials: false, 10 | }); 11 | 12 | //加入Token在Request拦截器中 13 | instance.interceptors.request.use(config => { 14 | //console.log(config.baseURL = getSocketHost()); 15 | //并且是服务端渲染的时候 16 | return config 17 | }); 18 | 19 | // http response 拦截器,标准的restful请求 20 | instance.interceptors.response.use((res: any): Promise => { 21 | const ret: any = {data: res.data, status: 200, ok: true, message: res.data.message || 'Request Success'} 22 | return ret 23 | }, 24 | (error) => { 25 | if (error && !error.response) { 26 | error.response = {data: {message: 'Server Request Fail'}, status: 502} 27 | } 28 | const res: any = { 29 | ok: false, 30 | message: '访问服务器失败', 31 | status: 500, 32 | }; 33 | if (!error.response) { 34 | res.status = 500; 35 | res.message = 'API服务器访问失败' 36 | } else { 37 | const data = error.response.data; 38 | res.status = error.response.status; 39 | res.message = data.message || 'API服务器访问失败'; 40 | res.data = data; 41 | } 42 | //401 43 | if (res.status === 401) { 44 | // return router.push({name: 'passport-login'}); 45 | } 46 | return Promise.resolve(res) 47 | } 48 | ); 49 | 50 | export const http = instance; 51 | 52 | export default instance; 53 | 54 | -------------------------------------------------------------------------------- /src/utils/int.ts: -------------------------------------------------------------------------------- 1 | export default function isZero(hexNumberString: string) { 2 | return /^0x0*$/.test(hexNumberString) 3 | } -------------------------------------------------------------------------------- /src/utils/logger.ts: -------------------------------------------------------------------------------- 1 | // const winston = require('winston'); 2 | // 3 | // const logger = winston.createLogger({ 4 | // level: 'verbose', 5 | // format: winston.format.combine( 6 | // winston.format.colorize({all: true}), 7 | // winston.format.timestamp({format: 'YYYY-MM-DD HH:mm:ss'}), 8 | // winston.format.printf((info: any) => `[${info.timestamp}] ${info.level}: ${info.message}`), 9 | // ), 10 | // transports: [ 11 | // new winston.transports.Console(), 12 | // ], 13 | // }); 14 | // export default logger; 15 | const path = require('path'); 16 | import log4js from 'log4js'; 17 | 18 | const dir = process.cwd(); 19 | 20 | log4js.configure({ 21 | appenders: { 22 | console: {type: 'console'}, 23 | app: {type: 'file', filename: path.join(dir, "./logs/app.log")} 24 | }, 25 | categories: { 26 | default: { 27 | appenders: ['console', 'app'], level: 'trace',//all log 28 | }, 29 | } 30 | }); 31 | 32 | 33 | export default log4js; 34 | 35 | export const logger = log4js.getLogger("app"); 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/utils/utils.ts: -------------------------------------------------------------------------------- 1 | export async function sleep(t): Promise { 2 | return new Promise(resolve => { 3 | setTimeout(() => { 4 | resolve(null) 5 | }, t) 6 | }) 7 | } -------------------------------------------------------------------------------- /src/utils/wrappedCurrency.ts: -------------------------------------------------------------------------------- 1 | import {ChainId, Currency, CurrencyAmount, ETHER, Token, TokenAmount, WETH} from "@godtoy/pancakeswap-sdk-v2"; 2 | import {parseUnits} from "@ethersproject/units"; 3 | import JSBI from "jsbi"; 4 | 5 | export function wrappedCurrency(currency: Currency | undefined, chainId: ChainId | undefined): Token | undefined { 6 | // eslint-disable-next-line no-nested-ternary 7 | return chainId && currency === ETHER ? WETH[chainId] : currency instanceof Token ? currency : undefined 8 | } 9 | 10 | export function wrappedCurrencyAmount(currencyAmount: CurrencyAmount | undefined, chainId: ChainId | undefined): TokenAmount | undefined { 11 | const token = currencyAmount && chainId ? wrappedCurrency(currencyAmount.currency, chainId) : undefined 12 | return token && currencyAmount ? new TokenAmount(token, currencyAmount.raw) : undefined 13 | } 14 | 15 | export function unwrappedToken(token: Token): Currency { 16 | if (token.equals(WETH[token.chainId])) return ETHER 17 | return token 18 | } 19 | 20 | export function tryParseAmount(value?: string, currency?: Currency): CurrencyAmount | undefined { 21 | if (!value || !currency) { 22 | return undefined 23 | } 24 | try { 25 | const typedValueParsed = parseUnits(value, currency.decimals).toString() 26 | if (typedValueParsed !== '0') { 27 | return currency instanceof Token ? new TokenAmount(currency, JSBI.BigInt(typedValueParsed)) : CurrencyAmount.ether(JSBI.BigInt(typedValueParsed)) 28 | } 29 | } catch (error) { 30 | // should fail if the user specifies too many decimal places of precision (or maybe exceed max uint?) 31 | console.info(`Failed to parse input amount: "${value}"`, error) 32 | } 33 | // necessary for all paths to return a value 34 | return undefined 35 | } 36 | -------------------------------------------------------------------------------- /src/wallet.ts: -------------------------------------------------------------------------------- 1 | import {config, provider} from "./config"; 2 | import {Signer} from '@ethersproject/abstract-signer' 3 | import {ethers} from 'ethers' 4 | 5 | import Web3 from 'web3'; 6 | 7 | export const web3 = new Web3(config.provider); 8 | export const activateAccount: any = web3.eth.accounts.privateKeyToAccount(config.walletPvKey); 9 | 10 | export const wallet = new ethers.Wallet(config.walletPvKey, provider) 11 | -------------------------------------------------------------------------------- /src/wallet_test.ts: -------------------------------------------------------------------------------- 1 | //import account bnb 2 | import {ethers} from "ethers"; 3 | import {config, provider} from "./config"; 4 | 5 | async function run() { 6 | const wallet = new ethers.Wallet(config.walletPvKey, provider) 7 | const addr = await wallet.getAddress() 8 | const bal = await wallet.getBalance() 9 | } 10 | 11 | run() -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "removeComments": true, 4 | "preserveConstEnums": true, 5 | "experimentalDecorators": true, 6 | "outDir": "./build", 7 | "strictFunctionTypes": false, 8 | "noEmitOnError": false, 9 | "esModuleInterop": true, 10 | "strict": false, 11 | "allowJs": false, 12 | "target": "es2018", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "importHelpers": true, 16 | "declaration": true, 17 | "sourceMap": true, 18 | "lib": [ 19 | "es5", 20 | "dom", 21 | "es2015" 22 | ] 23 | }, 24 | "include": [ 25 | "./src/**/*", 26 | ] 27 | } --------------------------------------------------------------------------------