├── .babelrc ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .gitpod.yml ├── .prettierignore ├── .prettierrc.json ├── Changelog.md ├── LICENSE ├── README.md ├── book.json ├── docs ├── .bookignore ├── Changelog.md ├── README.md ├── SUMMARY.md ├── about_us.md └── js_sdk │ ├── Deposit.md │ ├── NFTAction │ ├── collectionNFT.md │ ├── deployNFT.md │ ├── metaNFT.md │ ├── mintNFT.md │ ├── tradeNFT.md │ └── validateNFTOrder.md │ ├── README.md │ ├── account │ ├── activeAccount.md │ ├── fee.md │ ├── historyRecord.md │ ├── signature.md │ ├── wallet_api.md │ └── whitelisted_user_api.md │ ├── deposit │ ├── depositERC20.md │ └── depositNFT.md │ ├── erc20Trade │ └── orderERC20.md │ ├── exchange │ ├── ammpool_api.md │ ├── exchange.md │ └── webSocket.md │ ├── transfer │ ├── transferERC20.md │ └── transferNFT.md │ └── withdraw │ ├── withdrawERC20.md │ └── withdrawNFT.md ├── jest.config.cjs ├── package.json ├── rollup.config.mjs ├── src ├── api │ ├── ammpool_api.ts │ ├── base_api.ts │ ├── config │ │ ├── abis │ │ │ ├── contractWallet.ts │ │ │ ├── erc1155.ts │ │ │ ├── erc20.ts │ │ │ ├── erc721.ts │ │ │ ├── exchange_3_6.ts │ │ │ ├── hebao.ts │ │ │ ├── index.ts │ │ │ └── smartWallet.ts │ │ ├── guardianTypeData.ts │ │ └── index.ts │ ├── contacts_api.ts │ ├── contract_api.ts │ ├── defi_api.ts │ ├── delegate_api.ts │ ├── ethereum │ │ └── contracts │ │ │ ├── AbiFunction.ts │ │ │ ├── Contract.ts │ │ │ ├── Contracts.ts │ │ │ └── index.ts │ ├── exchange_api.ts │ ├── global_api.ts │ ├── index.ts │ ├── luckToken_api.ts │ ├── nft_api.ts │ ├── rabbitWithdraw_api.ts │ ├── request.ts │ ├── sign │ │ ├── poseidon │ │ │ ├── EDDSAUtil.ts │ │ │ ├── TestsEDDSAUtil_test.ts │ │ │ ├── babyJub.ts │ │ │ ├── eddsa.ts │ │ │ ├── eddsa_test.ts │ │ │ ├── field.ts │ │ │ ├── field_test.ts │ │ │ ├── jubjub.ts │ │ │ ├── jubjub_test.ts │ │ │ ├── permutation.ts │ │ │ └── permutation_test.ts │ │ └── sign_tools.ts │ ├── user_api.ts │ ├── vault_api.ts │ ├── wallet_api.ts │ ├── whitelisted_user_api.ts │ └── ws_api.ts ├── defs │ ├── account_defs.ts │ ├── error_codes.ts │ ├── index.ts │ ├── loopring_constants.ts │ ├── loopring_defs.ts │ ├── loopring_enums.ts │ ├── nft_defs.ts │ ├── url_defs.ts │ ├── web3_defs.ts │ └── ws_defs.ts ├── index.ts ├── tests │ ├── .eslintrc │ ├── .gitignore │ ├── MockData.ts │ ├── MockSwapData.ts │ ├── README.md │ ├── UTC--2021-02-04T02-55-36.490219109Z--ef439044717c3af35f4f46e52aa99280217a7114 │ ├── demo │ │ ├── NFTAction │ │ │ ├── collectionNFT.md │ │ │ ├── collectionNFT.test.ts │ │ │ ├── deployNFT.md │ │ │ ├── deployNFT.test.ts │ │ │ ├── metaNFT.md │ │ │ ├── metaNFT.test.ts │ │ │ ├── mintNFT.md │ │ │ ├── mintNFT.test.ts │ │ │ ├── tradeNFT.md │ │ │ ├── tradeNFT.test.ts │ │ │ ├── validateNFTOrder.md │ │ │ └── validateNFTOrder.test.ts │ │ ├── account │ │ │ ├── account.test.ts │ │ │ ├── activeAccount.md │ │ │ ├── activeAccount.test.ts │ │ │ ├── fee.md │ │ │ ├── fee.test.ts │ │ │ ├── historyRecord.md │ │ │ ├── historyRecord.test.ts │ │ │ ├── signature.md │ │ │ └── signature.test.ts │ │ ├── deposit │ │ │ ├── deposit.md │ │ │ ├── deposit.test.ts │ │ │ ├── depositNFT.md │ │ │ └── depositNFT.test.ts │ │ ├── erc20Trade │ │ │ ├── orderERC20.md │ │ │ └── orderERC20.test.ts │ │ ├── exchange │ │ │ ├── exchange.md │ │ │ ├── exchange.test.ts │ │ │ ├── webSocket.md │ │ │ └── webSocket.test.ts │ │ ├── transfer │ │ │ ├── transferERC20.md │ │ │ ├── transferERC20.test.ts │ │ │ ├── transferNFT.md │ │ │ └── transferNFT.test.ts │ │ └── withdraw │ │ │ ├── withdrawERC20.md │ │ │ ├── withdrawERC20.test.ts │ │ │ ├── withdrawNFT.md │ │ │ └── withdrawNFT.test.ts │ ├── formatter.test.ts │ └── unitTest │ │ ├── account │ │ ├── account.test.ts │ │ └── sign_tools.test.ts │ │ ├── appWallet │ │ └── wallet.test.ts │ │ ├── erc20Trade │ │ ├── amm.test.ts │ │ ├── amm_calc.test.ts │ │ └── defi.test.ts │ │ ├── exchange │ │ └── exchange.test.ts │ │ ├── transfer │ │ └── transferUT.test.ts │ │ └── withdraw │ │ ├── forceWithdrawls.test.ts │ │ └── withdrawUT.test.ts ├── types.d.ts ├── types │ └── eddsa.d.ts └── utils │ ├── formatter.ts │ ├── index.ts │ ├── log_tools.ts │ ├── network_tools.ts │ ├── obj_tools.ts │ ├── swap_calc_utils.ts │ ├── symbol_tools.ts │ └── window_utils.ts ├── tsconfig.json └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "esmBundled": { 4 | "presets": [ 5 | ["@babel/env", { 6 | "targets": "> 0.25%, not dead" 7 | }], "@babel/typescript"] 8 | }, 9 | "cjs": { 10 | "presets": [ 11 | ["@babel/env", { 12 | "modules":"commonjs" 13 | }], "@babel/typescript"] 14 | }, 15 | "prod": { 16 | "presets": [ 17 | [ 18 | "@babel/env", 19 | { 20 | "targets": { "node": "18" }, 21 | "useBuiltIns": "usage", 22 | "corejs": 3 23 | } 24 | ], 25 | "@babel/typescript" 26 | ] 27 | } 28 | }, 29 | "plugins": [ 30 | "@babel/plugin-transform-optional-chaining", 31 | "@babel/plugin-transform-typescript", 32 | "transform-class-properties" 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # Ignore artifacts: 2 | build 3 | coverage 4 | _book 5 | dist 6 | node_modules 7 | dist -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "plugins": [ 5 | "@typescript-eslint" 6 | ], 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:@typescript-eslint/eslint-recommended", 10 | "plugin:@typescript-eslint/recommended" 11 | ], 12 | "rules": { 13 | "no-console": 2 , 14 | // Remember, this means error! 15 | "camelcase": ["warn"] 16 | } 17 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | yarn-error.log 2 | *.tgz 3 | *testfile* 4 | .idea 5 | _book 6 | dist 7 | node_modules 8 | coverage 9 | ./docs 10 | .DS_Store 11 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | # This configuration file was automatically generated by Gitpod. 2 | # Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file) 3 | # and commit this file to your remote git repository to share the goodness with others. 4 | 5 | tasks: 6 | - init: yarn install && yarn run build 7 | command: yarn run start 8 | 9 | 10 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore artifacts: 2 | build 3 | coverage 4 | _book 5 | dist 6 | node_modules -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /Changelog.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## JS SDK Version ChangeLog 4 | #### 3.6.14 5 | 1) Guardian approve 6 | #### v3.5.0 7 | 1)ecdsaSignature update to `eth_signTypedData_v4` use method `sendAsync` 8 | #### v3.4.15 9 | 1)Internal browser contract signarue support 10 | 2)referral signature at active account 11 | 3)referral reword 12 | 4)Explorer Collection related Entry and feature optimization 13 | 5)insufficient quota reminder for Dual Invest 14 | 6)Add tutorial on Block trade 15 | #### v3.3.16 16 | 1)Change Ecrecove function 17 | 2)Stop limit 18 | 3) Red Packet 19 | 4) Block trade 20 | 21 | #### v3.3.0 22 | 1) GLOBAL information update 23 | 24 | #### v3.2.6 25 | 1) BlindBox Redpacket 26 | 27 | #### v3.2.1 28 | 1) LRC staking 29 | 2) signature bug fix 30 | 31 | #### v3.1.5 32 | 1) hardware wallet last digital match / hard-code 33 | generateKeyPair(_, publicKey: { x: string; y: string } | undefined = undefined) 34 | 35 | #### v3.1.0 36 | 1) dual API update (support for Partial order) 37 | 2) red Packet feature 38 | 3) amm redeem mini order 39 | 40 | #### v3.0.1 - v3.0.8 41 | 1) reformate Error throw code states 42 | 2) new feature for collection group 43 | 3) method split for localStorage 44 | 45 | #### v2.0.24 46 | 47 | 1)collection feature 48 | 2)investment feature 49 | 50 | #### v2.0.17 51 | 52 | 1) submitForceWithdrawals 53 | 2) return a result hash 54 | 3) order/swap demo 55 | 56 | #### v2.0.12 57 | 58 | 1) ipfs cid to nftId startWith 0 59 | 2) server-side retturn nftId startWith 0 60 | 61 | #### v2.0.11 62 | 1) add deposit to 63 | 2) get Account by account id 64 | 3) add HEBAO_META_TYPE deposit_wallet 65 | 66 | #### v2.0.7 67 | 1) Fix isMobile 68 | 69 | #### v2.0.6 70 | 1) mintNFT nftData 71 | #### v2.0.5 (If you use v2 please move to >= v2.0.4 ) 72 | 1) payPayeeUpdateAccount 73 | 2) fix generateApiKey error 74 | 75 | #### v2.0.0 76 | 1) update poseidon 77 | 78 | *** 79 | #### v1.10.3 80 | 1) Demo update 81 | 82 | #### v1.10.1 83 | 1) getAllowances formatter update 84 | 2) getTokenBalances formatter update 85 | 3) unit test update 86 | 87 | #### v1.9.6 88 | 1) add is Mobile in personalSign 89 | #### v1.9.4 90 | 1) remove Authereum & walletLink 91 | 2) DEPLOYMENT_STATUS 92 | #### v1.8.13 93 | 1)Update web3_defs.ts CREATION_CODE 94 | 2)submitDeployNFT transfer.maxFee tokenId: transfer.token.tokenId, 95 | #### v1.8.7 96 | 1)getAmmPoolTxs V3 97 | #### v1.8.5 98 | 1)validateNftOrder 99 | 100 | #### v1.8.1 101 | 1)validateNftOrder 102 | 2)NFTCounterFactualInfo 103 | #### v1.7.9 104 | 1) nftMint NFTCounterFactualInfo 105 | ####v1.7.6 106 | 1) Doc update,UT update 107 | ####v1.7.2 108 | 1) NFT ACTION 109 | 2) AMM Bug 110 | 111 | ####v1.6.6 112 | 1) NFT MINT IPFS 113 | 114 | ####v1.6.5 115 | 1) The eddsaKey is generated by a keyseed, default format is 'Sign this message to access Loopring 116 | 117 | ####v1.6.3 118 | 1) Error format bug fix {code:number,message:string} 119 | 120 | ####v1.6.0 121 | 1) Error format `{code:number, msg|message: string}` 122 | 123 | ####v1.5.7 124 | 1) 721 NFT URI function 125 | 126 | #### v1.5.6 127 | 1) submitDeployNFT 128 | 129 | #### v1.5.2 130 | 1) NFT deposit 131 | 132 | #### v1.4.9 133 | 1) Counter Factual check 134 | 2) updateAccount 135 | 136 | #### v1.4.7 137 | 1) NFT META 138 | 2) HEBAO 139 | #### v1.4.5 140 | 1) CF wallet action sign update 141 | 142 | #### v1.4.4 (alpha) 143 | 1) fix unlock FC wallet 144 | 145 | #### v1.4.3 (alpha) 146 | 1) bug fix for NFT get contractMeta 147 | 2) FC wallet connect signature 148 | 3) Error code 149 | 150 | #### v1.4.2 151 | 1) update activity 152 | 153 | #### v1.3.10 154 | 1) Add recognizing header for web 155 | 156 | #### v1.3.9 157 | 1) Update getLatestTokenPrice url 158 | 159 | #### v1.3.8 160 | 1) SDK update for error type 161 | 162 | #### v1.3.4 - v1.3.7 destroy 163 | 164 | #### v1.3.3 165 | 1) add computeNFTAddress 166 | 2) add eslint and prettie for the code format 167 | 168 | #### v1.3.2 169 | 1) Fix some bug 170 | 2) Update withdraw NFT unit test 171 | 172 | #### v1.3.0 && v1.3.1 -- !!! revert 173 | formatter Uint8Array support 174 | # !!! revert 175 | 176 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Licensor: Loopring Technology Limited 2 | 3 | Licensed Work: Loopring-web/loopring-sdk 4 | The Licensed Work is (c) 2022 Loopring Technology Limited 5 | 6 | ----------------------------------------------------------------------------- 7 | 8 | Terms 9 | 10 | The Licensor hereby grants you the right to copy, modify, create derivative 11 | works, redistribute, and make limited-production use of the Licensed Work, on condition that Loopring L2 protocol/technology is supported on your platform that this Licensed Work is being used. 12 | 13 | If your use of the Licensed Work does not comply with the requirements 14 | currently in effect as described in this License, you must acquire a 15 | full licensing agreement from the Licensor, or its affiliated entities, 16 | or you must refrain from using the Licensed Work. 17 | 18 | All copies of the original and modified Licensed Work, and derivative works 19 | of the Licensed Work, are subject to this License. This License applies 20 | separately for each version of the Licensed Work. 21 | 22 | You must conspicuously display this License on each original or modified copy 23 | of the Licensed Work. If you receive the Licensed Work in original or 24 | modified form from a third party, the terms and conditions set forth in this 25 | License apply to your use of that work. 26 | 27 | Any use of the Licensed Work in violation of this License will automatically 28 | terminate your rights under this License for the current and all other 29 | versions of the Licensed Work. 30 | 31 | This License does not grant you any right in any trademark or logo of 32 | Licensor or its affiliates (provided that you may use a trademark or logo of 33 | Licensor as expressly required by this License). 34 | 35 | TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON 36 | AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, 37 | EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF 38 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND 39 | TITLE. 40 | 41 | ----------------------------------------------------------------------------- 42 | 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Loopring SDK 2 | 3 | [![license](https://img.shields.io/badge/license-Loopring-blue)](https://raw.githubusercontent.com/Loopring/loopring_sdk/master/LICENSE) 4 | [![type-badge](https://img.shields.io/npm/types/react-data-grid)](https://www.npmjs.com/package/react-data-grid) 5 | [![Discord](https://img.shields.io/discord/687207715902193673)](https://discord.com/invite/KkYccYp) 6 | 7 | ## 🚀 Quick Start 8 | ```shell 9 | # Using npm 10 | npm i @loopring-web/loopring-sdk --save 11 | # Using yarn 12 | yarn add @loopring-web/loopring-sdk 13 | ``` 14 | when using for browser make sure set up `NODE_ENV=production|development` 15 | 16 | > Make sure you are using the original npm registry. 17 | > `npm config set registry http://registry.npmjs.org` 18 | 19 | 20 | ## 📒 Documentation 21 | 22 | Please see the [documentation page](https://loopring.github.io/loopring_sdk/) for information about getting started and developing with the Loopring SDK. 23 | 24 | - [JS SDK](https://loopring.github.io/loopring_sdk) 25 | - [APIs](https://docs-protocol.loopring.io) 26 | 27 | ## ✨ Changelog 28 | 29 | - [Changelog](https://loopring.github.io/loopring_sdk/ChangeLog.html) 30 | 31 | ## 🫂 Community 32 | 33 | - [Loopring Website](https://loopring.org/) 34 | - [Loopring Exchange](https://loopring.io/#/layer2) 35 | - [Loopring Reddit](https://www.reddit.com/r/loopringorg/) 36 | - [Loopring Medium](https://medium.com/loopring-protocol) 37 | - [Loopring Twitter](https://twitter.com/loopringorg) 38 | - [Loopring Telegram](https://t.me/loopring_en) 39 | 40 | ## 🎒 Getting Started 41 | 42 | Please see our [introduction page](https://loopring.github.io/loopring_sdk/) for details on integrating the SDK into your application. 43 | 44 | ## 🙋 Protocol & Architecture 45 | 46 | - [Whitepaper](https://loopring.org/resources/en_whitepaper.pdf) 47 | - [Design Docs](https://github.com/LoopringSecondary/docs/wiki/Loopring3_Design) 48 | 49 | ## ❓[Help](https://desk.zoho.com/portal/loopring/en/home) 50 | 51 | ## 👉 [What is Loopring?](https://loopring.org/#/) 52 | 53 | ## 🔑 Security 54 | 55 | - [Wallet](https://security.loopring.io/) 56 | - [Protocol Audit](https://loopring.org/resources/loopring1.0_audit.pdf) 57 | -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": "./docs", 3 | "description": "loopring sdk", 4 | "author": "Loopring Dev Team", 5 | "title": "Loopring SDK", 6 | "gitbook": ">=3.0.0", 7 | "links": { 8 | "sidebar": { 9 | "Home": "https://loopring.io" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /docs/.bookignore: -------------------------------------------------------------------------------- 1 | docs/detail 2 | docs/README.md 3 | docs/Changelog.mdv 4 | -------------------------------------------------------------------------------- /docs/Changelog.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## JS SDK Version ChangeLog 4 | #### v3.6.0 5 | 1) dual Invest autoReinvest 6 | 2) guardina singature typeData 7 | 3) remove signature 02/03 ended 8 | 9 | #### v3.2.1 10 | 1) LRC staking 11 | 2) signature bug fix 12 | 13 | #### v3.1.5 14 | 1) hardware wallet last digital match / hard-code 15 | generateKeyPair(_, publicKey: { x: string; y: string } | undefined = undefined) 16 | 17 | #### v3.1.0 18 | 1) dual API update (support for Partial order) 19 | 2) red Packet feature 20 | 3) amm redeem mini order 21 | 22 | #### v3.0.1 - v3.0.8 23 | 1) reformate Error throw code states 24 | 2) new feature for collection group 25 | 3) method split for localStorage 26 | 27 | #### v2.0.24 28 | 29 | 1)collection feature 30 | 2)investment feature 31 | 32 | #### v2.0.17 33 | 34 | 1) submitForceWithdrawals 35 | 2) return a result hash 36 | 3) order/swap demo 37 | 38 | #### v2.0.12 39 | 40 | 1) ipfs cid to nftId startWith 0 41 | 2) server-side retturn nftId startWith 0 42 | 43 | #### v2.0.11 44 | 1) add deposit to 45 | 2) get Account by account id 46 | 3) add HEBAO_META_TYPE deposit_wallet 47 | 48 | #### v2.0.7 49 | 1) Fix isMobile 50 | 51 | #### v2.0.6 52 | 1) mintNFT nftData 53 | #### v2.0.5 (If you use v2 please move to >= v2.0.4 ) 54 | 1) payPayeeUpdateAccount 55 | 2) fix generateApiKey error 56 | 57 | #### v2.0.0 58 | 1) update poseidon 59 | 60 | *** 61 | #### v1.10.3 62 | 1) Demo update 63 | 64 | #### v1.10.1 65 | 1) getAllowances formatter update 66 | 2) getTokenBalances formatter update 67 | 3) unit test update 68 | 69 | #### v1.9.6 70 | 1) add is Mobile in personalSign 71 | #### v1.9.4 72 | 1) remove Authereum & walletLink 73 | 2) DEPLOYMENT_STATUS 74 | #### v1.8.13 75 | 1)Update web3_defs.ts CREATION_CODE 76 | 2)submitDeployNFT transfer.maxFee tokenId: transfer.token.tokenId, 77 | #### v1.8.7 78 | 1)getAmmPoolTxs V3 79 | #### v1.8.5 80 | 1)validateNftOrder 81 | 82 | #### v1.8.1 83 | 1)validateNftOrder 84 | 2)NFTCounterFactualInfo 85 | #### v1.7.9 86 | 1) nftMint NFTCounterFactualInfo 87 | ####v1.7.6 88 | 1) Doc update,UT update 89 | ####v1.7.2 90 | 1) NFT ACTION 91 | 2) AMM Bug 92 | 93 | ####v1.6.6 94 | 1) NFT MINT IPFS 95 | 96 | ####v1.6.5 97 | 1) The eddsaKey is generated by a keyseed, default format is 'Sign this message to access Loopring 98 | 99 | ####v1.6.3 100 | 1) Error format bug fix {code:number,message:string} 101 | 102 | ####v1.6.0 103 | 1) Error format `{code:number, msg|message: string}` 104 | 105 | ####v1.5.7 106 | 1) 721 NFT URI function 107 | 108 | #### v1.5.6 109 | 1) submitDeployNFT 110 | 111 | #### v1.5.2 112 | 1) NFT deposit 113 | 114 | #### v1.4.9 115 | 1) Counter Factual check 116 | 2) updateAccount 117 | 118 | #### v1.4.7 119 | 1) NFT META 120 | 2) HEBAO 121 | #### v1.4.5 122 | 1) CF wallet action sign update 123 | 124 | #### v1.4.4 (alpha) 125 | 1) fix unlock FC wallet 126 | 127 | #### v1.4.3 (alpha) 128 | 1) bug fix for NFT get contractMeta 129 | 2) FC wallet connect signature 130 | 3) Error code 131 | 132 | #### v1.4.2 133 | 1) update activity 134 | 135 | #### v1.3.10 136 | 1) Add recognizing header for web 137 | 138 | #### v1.3.9 139 | 1) Update getLatestTokenPrice url 140 | 141 | #### v1.3.8 142 | 1) SDK update for error type 143 | 144 | #### v1.3.4 - v1.3.7 destroy 145 | 146 | #### v1.3.3 147 | 1) add computeNFTAddress 148 | 2) add eslint and prettie for the code format 149 | 150 | #### v1.3.2 151 | 1) Fix some bug 152 | 2) Update withdraw NFT unit test 153 | 154 | #### v1.3.0 && v1.3.1 -- !!! revert 155 | formatter Uint8Array support 156 | # !!! revert 157 | 158 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Loopring SDK 2 | 3 | [![license](https://img.shields.io/badge/license-Loopring-blue)](https://raw.githubusercontent.com/Loopring/loopring_sdk/master/LICENSE) 4 | [![type-badge](https://img.shields.io/npm/types/react-data-grid)](https://www.npmjs.com/package/react-data-grid) 5 | [![Discord](https://img.shields.io/discord/687207715902193673)](https://discord.com/invite/KkYccYp) 6 | 7 | ## 🚀 Quick Start 8 | ```shell 9 | # Using npm 10 | npm i @loopring-web/loopring-sdk --save 11 | # Using yarn 12 | yarn add @loopring-web/loopring-sdk 13 | ``` 14 | > Make sure you are using the original npm registry. 15 | > `npm config set registry http://registry.npmjs.org` 16 | 17 | 18 | ## 📒 Documentation 19 | 20 | Please see the [documentation page](https://loopring.github.io/loopring_sdk/) for information about getting started and developing with the Loopring SDK. 21 | 22 | - [JS SDK](https://loopring.github.io/loopring_sdk) 23 | - [Python](https://github.com/Loopring/hello_loopring) 24 | - [APIs](https://docs.loopring.io/en/) 25 | 26 | ## ✨ Changelog 27 | 28 | - [Changelog](https://loopring.github.io/loopring_sdk/ChangeLog.html) 29 | 30 | ## 🫂 Community 31 | 32 | - [Loopring Website](https://loopring.org/) 33 | - [Loopring Exchange](https://loopring.io/#/layer2) 34 | - [Loopring Reddit](https://www.reddit.com/r/loopringorg/) 35 | - [Loopring Medium](https://medium.com/loopring-protocol) 36 | - [Loopring Twitter](https://twitter.com/loopringorg) 37 | - [Loopring Telegram](https://t.me/loopring_en) 38 | 39 | ## 🎒 Getting Started 40 | 41 | Please see our [introduction page](https://loopring.github.io/loopring_sdk/) for details on integrating the SDK into your application. 42 | 43 | ## 🙋 Protocol & Architecture 44 | 45 | - [Whitepaper](https://loopring.org/resources/en_whitepaper.pdf) 46 | - [Design Docs](https://github.com/LoopringSecondary/docs/wiki/Loopring3_Design) 47 | 48 | ## ❓[Help](https://desk.zoho.com/portal/loopring/en/home) 49 | 50 | ## 👉 [What is Loopring?](https://loopring.org/#/) 51 | 52 | ## 🔑 Security 53 | 54 | - [Wallet](https://security.loopring.io/) 55 | - [Protocol Audit](https://loopring.org/resources/loopring1.0_audit.pdf) 56 | -------------------------------------------------------------------------------- /docs/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | ### Overview 4 | 5 | - [Introduction](README.md) 6 | - [Changelog](Changelog.md) 7 | - [GitHub](https://github.com/Loopring/loopring_sdk) 8 | 9 | ### SDKs demo 10 | 11 | - [JS SDK](./js_sdk/README.md) 12 | - [Exchange](./js_sdk/exchange/exchange.md) 13 | - [Web Socket](./js_sdk/exchange/webSocket.md) 14 | - [Amm](./js_sdk/exchange/ammpool_api.md) 15 | - [Account](./js_sdk/README.md#mock-account) 16 | - [Active Account](./js_sdk/account/activeAccount.md) 17 | - [Fees](./js_sdk/account/fee.md) 18 | - [Signature](./js_sdk/account/signature.md) 19 | - [Transaction Recorder](./js_sdk/account/historyRecord.md) 20 | - [ERC20](./js_sdk/README.md#mock-erc20-token-map) 21 | - [Deposit](./js_sdk/deposit/depositERC20.md) 22 | - [Transfer](./js_sdk/transfer/transferERC20.md) 23 | - [Withdraw](./js_sdk/withdraw/withdrawERC20.md) 24 | - [Order](./js_sdk/erc20Trade/orderERC20.md) 25 | - [NFT](./js_sdk/README.md#mock-account) 26 | - [Deposit](./js_sdk/deposit/depositNFT.md) 27 | - [Transfer](./js_sdk/transfer/transferNFT.md) 28 | - [Withdraw](./js_sdk/withdraw/withdrawNFT.md) 29 | - [Mint](./js_sdk/NFTAction/mintNFT.md) 30 | - [MetaData](./js_sdk/NFTAction/metaNFT.md) 31 | - [Collection](./js_sdk/NFTAction/collectionNFT.md) 32 | - [Deploy](./js_sdk/NFTAction/deployNFT.md) 33 | - [Trade](./js_sdk/NFTAction/tradeNFT.md) 34 | - [Validate Order](./js_sdk/NFTAction/validateNFTOrder.md) 35 | 36 | ### Links 37 | 38 | - [Python](https://github.com/Loopring/hello_loopring) 39 | - [APIs](https://docs.loopring.io/en/) 40 | - [About us](https://loopring.org/#/) 41 | - [Submit a Request](https://desk.zoho.com/portal/loopring/en/newticket) 42 | -------------------------------------------------------------------------------- /docs/about_us.md: -------------------------------------------------------------------------------- 1 | ##### written by loopring dev team. 2 | -------------------------------------------------------------------------------- /docs/js_sdk/NFTAction/deployNFT.md: -------------------------------------------------------------------------------- 1 | # Deploy NFT 2 | 3 | Definition: Only nft minter can deploy NFT 4 | 5 | *** 6 | 7 | ## Step 1. get Account 8 | 9 | ```ts 10 | const {accInfo} = await LoopringAPI.exchangeAPI.getAccount({ 11 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 12 | }); 13 | console.log("accInfo:", accInfo); 14 | ``` 15 | 16 | *** 17 | 18 | ## Step 2. get eddsaKey 19 | 20 | ```ts 21 | const eddsaKey = await signatureKeyPairMock(accInfo); 22 | console.log("eddsaKey:", eddsaKey.sk); 23 | ``` 24 | 25 | *** 26 | 27 | ## Step 3. get apiKey 28 | 29 | ```ts 30 | const {apiKey} = await LoopringAPI.userAPI.getUserApiKey( 31 | { 32 | accountId: accInfo.accountId, 33 | }, 34 | eddsaKey.sk 35 | ); 36 | console.log("apiKey:", apiKey); 37 | ``` 38 | 39 | *** 40 | 41 | 42 | ## Step 4. get fee 43 | 44 | ```ts 45 | const fee = await LoopringAPI.userAPI.getNFTOffchainFeeAmt( 46 | { 47 | accountId: accInfo.accountId, 48 | requestType: sdk.OffchainNFTFeeReqType.NFT_DEPLOY, 49 | amount: "0", 50 | }, 51 | apiKey 52 | ); 53 | console.log(fee); 54 | ``` 55 | *** 56 | ## Step 5. get storageId 57 | 58 | ```ts 59 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 60 | { 61 | accountId: accInfo.accountId, 62 | sellTokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, // same as Step 7. transfer->token->tokenId 63 | }, 64 | apiKey 65 | ); 66 | ``` 67 | 68 | *** 69 | 70 | ## Step 6. broker 71 | 72 | ```ts 73 | const {broker} = await LoopringAPI.exchangeAPI.getAvailableBroker(); 74 | ``` 75 | 76 | *** 77 | ## Step 7. Build transfer & Deploy 78 | 79 | ```ts 80 | const transfer = { 81 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 82 | payerAddr: LOOPRING_EXPORTED_ACCOUNT.address, 83 | payerId: LOOPRING_EXPORTED_ACCOUNT.accountId, 84 | payeeAddr: broker, 85 | // payeeAddr: LOOPRING_EXPORTED_ACCOUNT.address2, 86 | storageId: storageId.offchainId, 87 | token: { 88 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 89 | volume: fee.fees["LRC"].fee ?? "9400000000000000000", 90 | }, 91 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 92 | }; 93 | const response = await LoopringAPI.userAPI.submitDeployNFT({ 94 | request: { 95 | transfer, 96 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 97 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 98 | }, 99 | web3, 100 | chainId: sdk.ChainId.GOERLI, 101 | walletType: sdk.ConnectorNames.Unknown, 102 | eddsaKey: eddsaKey.sk, 103 | apiKey: apiKey, 104 | }); 105 | 106 | console.log(response); 107 | ``` 108 | 109 | 110 | -------------------------------------------------------------------------------- /docs/js_sdk/NFTAction/metaNFT.md: -------------------------------------------------------------------------------- 1 | # NFT META METHODS 2 | 3 | *** 4 | 5 | ## getContractNFTMeta 6 | 7 | ```ts 8 | const result = await LoopringAPI.nftAPI.getContractNFTMeta({ 9 | web3, 10 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 11 | nftId: LOOPRING_EXPORTED_ACCOUNT.nftId, 12 | nftType: sdk.NFTType.ERC1155, 13 | }); 14 | console.log(result); 15 | ``` 16 | 17 | *** 18 | 19 | ## getInfoForNFTTokens 20 | 21 | ```ts 22 | const response = await LoopringAPI.nftAPI.getInfoForNFTTokens({ 23 | nftDatas: [LOOPRING_EXPORTED_ACCOUNT.nftData], 24 | }); 25 | console.log(`getInfoForNFTTokens: response: `, JSON.stringify(response)); 26 | ``` 27 | 28 | *** 29 | 30 | ## computeNFTAddress 31 | 32 | ```ts 33 | const response = LoopringAPI.nftAPI.computeNFTAddress({ 34 | nftOwner: "0xE20cF871f1646d8651ee9dC95AAB1d93160b3467", 35 | nftFactory: "0x40F2C1770E11c5bbA3A26aEeF89616D209705C5D", 36 | }); 37 | console.log( 38 | `computeNFTAddress:`, 39 | response, 40 | "0xee354d81778a4c5a08fd9dbeb5cfd01a840a746d" 41 | ); 42 | ``` 43 | 44 | *** 45 | 46 | ## ipfsCid0ToNftID 47 | 48 | ```ts 49 | const ipfs = "QmNuqdeWUJ9iEiw5qZfJ2pJ9onqAS45ZffvV8JQSUzp7DQ"; 50 | const nftID = 51 | "0x0880847b7587968f32ba6c741f9d797d9dc64971979922a80c4e590453b8dc2f"; 52 | console.log( 53 | `ipfsCid0ToNftID: ipfs: `, 54 | ipfs, 55 | LoopringAPI.nftAPI.ipfsCid0ToNftID(ipfs) 56 | ); 57 | ``` 58 | 59 | *** 60 | 61 | ## ipfsNftIDToCid 62 | 63 | ```ts 64 | const ipfs = "QmNuqdeWUJ9iEiw5qZfJ2pJ9onqAS45ZffvV8JQSUzp7DQ"; 65 | const nftID = 66 | "0x0880847b7587968f32ba6c741f9d797d9dc64971979922a80c4e590453b8dc2f"; 67 | 68 | console.log( 69 | `ipfsCid0ToNftID: nftID: `, 70 | nftID, 71 | LoopringAPI.nftAPI.ipfsNftIDToCid(nftID) 72 | ); 73 | ``` 74 | -------------------------------------------------------------------------------- /docs/js_sdk/NFTAction/tradeNFT.md: -------------------------------------------------------------------------------- 1 | # Trade NFT 2 | 3 | Definition: This method is help for understand how to match a maker with a taker order 4 | 5 | *** 6 | 7 | ## tradeNFT 8 | > Private or third account can signature and approve this order 9 | 10 | [mock order](#MockOrder) 11 | ```ts 12 | // Step 1. getAccount 13 | const accInfoC = ( 14 | await LoopringAPI.exchangeAPI.getAccount({ 15 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 16 | }) 17 | ).accInfo; 18 | 19 | // Step 1. eddsaKeyC 20 | const eddsaKeyC = await signatureKeyPairMock(accInfoC); 21 | 22 | // Step 3. apiKey 23 | const apiKeyC = ( 24 | await LoopringAPI.userAPI.getUserApiKey( 25 | { 26 | accountId: accInfoC.accountId, 27 | }, 28 | eddsaKeyC.sk 29 | ) 30 | ).apiKey; 31 | // NFT Trade 32 | const response = await LoopringAPI.userAPI.submitNFTTrade({ 33 | request: { 34 | maker: { 35 | ...mockData.makerOrder, 36 | eddsaSignature: mockData.makerOrderEddsaSignature, 37 | }, 38 | makerFeeBips: 1000, 39 | taker: { 40 | ...mockData.takerOrder, 41 | eddsaSignature: mockData.takerOrderEddsaSignature, 42 | }, 43 | takerFeeBips: 100, 44 | }, 45 | web3, 46 | chainId: sdk.ChainId.GOERLI, 47 | walletType: sdk.ConnectorNames.Unknown, 48 | apiKey: apiKeyC, 49 | eddsaKey: eddsaKeyC.sk, 50 | }); 51 | 52 | console.log(response); 53 | ``` 54 | 55 | *** 56 | 57 | ## MockOrder 58 | 59 | > Validate NFT Order please reader @Validate NFT Order 60 | 61 | ```ts 62 | // Step 1. getAccount 63 | const accInfo = ( 64 | await LoopringAPI.exchangeAPI.getAccount({ 65 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 66 | }) 67 | ).accInfo; 68 | const accInfo2 = ( 69 | await LoopringAPI.exchangeAPI.getAccount({ 70 | owner: LOOPRING_EXPORTED_ACCOUNT.address2, 71 | }) 72 | ).accInfo; 73 | // Step 2. eddsaKey 74 | const eddsaKey = await signatureKeyPairMock(accInfo); 75 | const eddsaKey2 = await signatureKeyPairMock(accInfo2, web3_2); 76 | // Step 3. apiKey 77 | const apiKey = ( 78 | await LoopringAPI.userAPI.getUserApiKey( 79 | { 80 | accountId: accInfo.accountId, 81 | }, 82 | eddsaKey.sk 83 | ) 84 | ).apiKey; 85 | const apiKey2 = ( 86 | await LoopringAPI.userAPI.getUserApiKey( 87 | { 88 | accountId: accInfo2.accountId, 89 | }, 90 | eddsaKey2.sk 91 | ) 92 | ).apiKey; 93 | 94 | // Step 4. storageId 95 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 96 | { 97 | accountId: accInfo.accountId, 98 | sellTokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 99 | }, 100 | apiKey 101 | ); 102 | const storageId2 = await LoopringAPI.userAPI.getNextStorageId( 103 | { 104 | accountId: accInfo2.accountId, 105 | sellTokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 106 | }, 107 | apiKey2 108 | ); 109 | // Step 5. generate Order, please read validateNFTOrder 110 | const makerOrder: sdk.NFTOrderRequestV3 = { 111 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 112 | accountId: accInfo.accountId, 113 | storageId: storageId.orderId, 114 | sellToken: { 115 | tokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 116 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 117 | amount: "1", 118 | }, 119 | buyToken: { 120 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 121 | amount: LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue.toString(), 122 | }, 123 | allOrNone: false, 124 | fillAmountBOrS: false, 125 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 126 | maxFeeBips: 1000, 127 | }; 128 | const makerOrderEddsaSignature = sdk.get_EddsaSig_NFT_Order( 129 | makerOrder, 130 | eddsaKey.sk 131 | ); 132 | 133 | const takerOrder: sdk.NFTOrderRequestV3 = { 134 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 135 | accountId: accInfo2.accountId, 136 | storageId: storageId2.orderId, 137 | sellToken: { 138 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 139 | amount: LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue.toString(), 140 | }, 141 | buyToken: { 142 | tokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 143 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 144 | amount: "1", 145 | }, 146 | allOrNone: false, 147 | fillAmountBOrS: true, 148 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 149 | maxFeeBips: 100, 150 | }; 151 | const takerOrderEddsaSignature = sdk.get_EddsaSig_NFT_Order( 152 | takerOrder, 153 | eddsaKey2.sk 154 | ); 155 | 156 | mockData = { 157 | takerOrder, 158 | takerOrderEddsaSignature, 159 | makerOrder, 160 | makerOrderEddsaSignature, 161 | makerFeeBips: 1000, 162 | maxFeeBips: 100, 163 | }; 164 | 165 | ``` 166 | -------------------------------------------------------------------------------- /docs/js_sdk/NFTAction/validateNFTOrder.md: -------------------------------------------------------------------------------- 1 | # Validate NFT Order 2 | 3 | Definition: Loopring L2 support a method help for Validate NFT one side Order, validate NFT Order is not required for 4 | Loopring, but when make NFT Trade, it should pass this validation 5 | 6 | ## SellNFTByERC20 7 | 8 | ```ts 9 | // Step 1. getAccount 10 | const {accInfo} = await LoopringAPI.exchangeAPI.getAccount({ 11 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 12 | }); 13 | console.log("accInfo:", accInfo); 14 | 15 | // Step 2. eddsaKey 16 | const eddsaKey = await signatureKeyPairMock(accInfo); 17 | console.log("eddsaKey:", eddsaKey.sk); 18 | 19 | // Step 3. apiKey 20 | const {apiKey} = await LoopringAPI.userAPI.getUserApiKey( 21 | { 22 | accountId: accInfo.accountId, 23 | }, 24 | eddsaKey.sk 25 | ); 26 | console.log("apiKey:", apiKey); 27 | 28 | // Step 4. storageId 29 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 30 | { 31 | accountId: accInfo.accountId, 32 | sellTokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 33 | }, 34 | apiKey 35 | ); 36 | console.log("storageId:", storageId); 37 | // let hash: any = new BN(nftId,'hex') 38 | // hash = toHex(hash);//new BigInteger(sha256(nftId.toString()).toString(), 16) 39 | 40 | // Step 5. submitNFTValidateOrder 41 | const response = await LoopringAPI.userAPI.submitNFTValidateOrder({ 42 | request: { 43 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 44 | accountId: accInfo.accountId, 45 | storageId: storageId.orderId, 46 | sellToken: { 47 | tokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 48 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 49 | amount: "1", 50 | }, 51 | buyToken: { 52 | tokenId: 1, 53 | amount: "10000000000000", 54 | }, 55 | allOrNone: false, 56 | fillAmountBOrS: false, 57 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 58 | maxFeeBips: 1000, 59 | }, 60 | web3, 61 | chainId: sdk.ChainId.GOERLI, 62 | walletType: sdk.ConnectorNames.Unknown, 63 | eddsaKey: eddsaKey.sk, 64 | apiKey: apiKey, 65 | }); 66 | 67 | console.log("sellNFT NFTOrderRequestV3:", response); 68 | ``` 69 | 70 | *** 71 | 72 | ## BuyNFTByERC20 73 | 74 | ```ts 75 | // Step 1. getAccount 76 | const {accInfo} = await LoopringAPI.exchangeAPI.getAccount({ 77 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 78 | }); 79 | console.log("accInfo:", accInfo); 80 | 81 | // Step 2. eddsaKey 82 | const eddsaKey = await signatureKeyPairMock(accInfo); 83 | console.log("eddsaKey:", eddsaKey.sk); 84 | 85 | // Step 3. apiKey 86 | const {apiKey} = await LoopringAPI.userAPI.getUserApiKey( 87 | { 88 | accountId: accInfo.accountId, 89 | }, 90 | eddsaKey.sk 91 | ); 92 | console.log("apiKey:", apiKey); 93 | 94 | // Step 5. submitNFTValidateOrder 95 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 96 | { 97 | accountId: accInfo.accountId, 98 | sellTokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 99 | }, 100 | apiKey 101 | ); 102 | console.log("storageId:", storageId); 103 | 104 | const response = await LoopringAPI.userAPI.submitNFTValidateOrder({ 105 | request: { 106 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 107 | accountId: accInfo.accountId, 108 | storageId: storageId.orderId, 109 | sellToken: { 110 | tokenId: 1, 111 | amount: "10000000000000", 112 | }, 113 | buyToken: { 114 | tokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 115 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 116 | amount: "1", 117 | }, 118 | fillAmountBOrS: true, 119 | allOrNone: false, 120 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 121 | maxFeeBips: 100, 122 | }, 123 | web3, 124 | chainId: sdk.ChainId.GOERLI, 125 | walletType: sdk.ConnectorNames.Unknown, 126 | eddsaKey: eddsaKey.sk, 127 | apiKey: apiKey, 128 | }); 129 | ``` 130 | 131 | -------------------------------------------------------------------------------- /docs/js_sdk/account/activeAccount.md: -------------------------------------------------------------------------------- 1 | # Active Account 2 | 3 | Definition: After user Deposit or (Third-Part Transfer), how to active Loopring L2 account. 4 | 5 | *** 6 | 7 | ## Step 1. get account info 8 | 9 | ```ts 10 | const {accInfo} = await LoopringAPI.exchangeAPI.getAccount({ 11 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 12 | }); 13 | ``` 14 | 15 | *** 16 | 17 | ## Step 2. use keySeed or CUSTOMER_KEY_SEED generateKeyPair 18 | 19 | ```ts 20 | const keySeed = sdk.BaseAPI.KEY_MESSAGE.replace( 21 | "${exchangeAddress}", 22 | LOOPRING_EXPORTED_ACCOUNT.exchangeAddress 23 | ).replace("${nonce}", accInfo.nonce.toString()); 24 | const eddsaKey = await sdk.generateKeyPair({ 25 | web3, 26 | address: accInfo.owner, 27 | keySeed, 28 | walletType: sdk.ConnectorNames.MetaMask, 29 | chainId: sdk.ChainId.GOERLI, 30 | }); 31 | console.log("eddsakey:", eddsaKey.sk); 32 | ``` 33 | 34 | Or 35 | 36 | ```ts 37 | // CUSTOMER_KEY_SEED = "XXXXXX" + " with key nonce: " + "${nonce}"; 38 | const keySeed = CUSTOMER_KEY_SEED.replace( 39 | "${nonce}", 40 | accInfo.nonce.toString() 41 | const eddsaKey = await sdk.generateKeyPair({ 42 | web3, 43 | address: accInfo.owner, 44 | keySeed, 45 | walletType: sdk.ConnectorNames.MetaMask, 46 | chainId: sdk.ChainId.GOERLI, 47 | }); 48 | console.log("eddsakey:", eddsaKey.sk); 49 | ``` 50 | 51 | *** 52 | 53 | ## Step 3. get fee 54 | 55 | ```ts 56 | const fee = await LoopringAPI.globalAPI.getActiveFeeInfo({ 57 | accountId: accInfo.accountId, 58 | }); 59 | console.log("fee:", fee); 60 | ``` 61 | 62 | *** 63 | 64 | ## Step 4. updateAccount (active or rest) 65 | 66 | ```ts 67 | const result = await LoopringAPI.userAPI.updateAccount({ 68 | request: { 69 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 70 | owner: accInfo.owner, 71 | accountId: accInfo.accountId, 72 | publicKey: {x: eddsaKey.formatedPx, y: eddsaKey.formatedPy}, 73 | maxFee: { 74 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 75 | volume: fee.fees["LRC"].fee ?? "9400000000000000000", 76 | }, 77 | keySeed, 78 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 79 | nonce: accInfo.nonce as number, 80 | }, 81 | web3, 82 | chainId: sdk.ChainId.GOERLI, 83 | walletType: sdk.ConnectorNames.Unknown, 84 | isHWAddr: false, 85 | }); 86 | 87 | const {accInfo: updateAccountInfo} = 88 | await LoopringAPI.exchangeAPI.getAccount({ 89 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 90 | }); 91 | console.log( 92 | "updateAccount Result: ", 93 | result, 94 | "updateAccountInfo:", 95 | updateAccountInfo 96 | ); 97 | ``` -------------------------------------------------------------------------------- /docs/js_sdk/account/historyRecord.md: -------------------------------------------------------------------------------- 1 | # User Actions History 2 | For check account Actions, more detail such as filters please read SDK interface or API . 3 | 4 | *** 5 | 6 | ## getUserTrades 7 | 8 | ```ts 9 | async () => { 10 | const result = await LoopringAPI.userAPI.getUserTrades( 11 | { 12 | accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 13 | offset: 0, 14 | limit: 20, 15 | fillTypes: sdk.TradesFillTypes.dex, 16 | }, 17 | apiKey 18 | ); 19 | console.log("getUserTrades:", result); 20 | ``` 21 | 22 | *** 23 | 24 | ## getUserTxs 25 | 26 | ```ts 27 | async () => { 28 | const result = await LoopringAPI.userAPI.getUserTxs( 29 | { 30 | accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 31 | types: [ 32 | sdk.UserTxTypes.DEPOSIT, 33 | sdk.UserTxTypes.TRANSFER, 34 | sdk.UserTxTypes.ONCHAIN_WITHDRAWAL, 35 | ], 36 | }, 37 | apiKey 38 | ); 39 | console.log("getUserTxs:", result); 40 | ``` 41 | 42 | *** 43 | 44 | ## getUserNFTTransactionHistory 45 | 46 | ```ts 47 | async () => { 48 | const result = await LoopringAPI.userAPI.getUserNFTTransactionHistory( 49 | { 50 | accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 51 | types: [ 52 | sdk.UserNFTTxTypes.DEPOSIT, 53 | sdk.UserNFTTxTypes.TRANSFER, 54 | sdk.UserNFTTxTypes.WITHDRAW, 55 | sdk.UserNFTTxTypes.MINT, 56 | ], 57 | }, 58 | apiKey 59 | ); 60 | console.log("getUserNFTTransactionHistory:", result); 61 | ``` 62 | 63 | *** 64 | 65 | ## getOrders 66 | 67 | ```ts 68 | async () => { 69 | const result = await LoopringAPI.userAPI.getOrders( 70 | { 71 | accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 72 | orderTypes: sdk.OrderType.LimitOrder, 73 | }, 74 | apiKey 75 | ); 76 | 77 | console.log("getOrders:", result); 78 | ``` 79 | -------------------------------------------------------------------------------- /docs/js_sdk/account/wallet_api.md: -------------------------------------------------------------------------------- 1 | # Whitelisted User Part 2 | 3 | ##### 1) getUserAssets 4 | 5 | ```javascript 6 | // step 1. get account info 7 | const request: GetUserAssetsRequest = { 8 | wallet: "0xeF041462825bFdF79b2f1f02A70b2753cB5b1516", 9 | offset: 10, 10 | limit: 10, 11 | }; 12 | 13 | const response = await api.getUserAssets(request); 14 | ``` 15 | 16 | ##### 2) getTokenPrices 17 | 18 | ```javascript 19 | // step 1. get account info 20 | const request: GetTokenPricesRequest = { 21 | token: "0xdac17f958d2ee523a2206206994597c13d831ec7", 22 | }; 23 | 24 | const response = await api.getTokenPrices(request); 25 | ``` 26 | 27 | ##### 3) getLatestTokenPrices 28 | 29 | ```javascript 30 | // step 1. get account info 31 | const response = await api.getLatestTokenPrices(); 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/js_sdk/account/whitelisted_user_api.md: -------------------------------------------------------------------------------- 1 | # Whitelisted User Part 2 | 3 | ## submitInternalTransfer 4 | 5 | ```javascript 6 | // step 1. get account info 7 | 8 | let addressWhitlisted = "0x35405E1349658BcA12810d0f879Bf6c5d89B512C"; 9 | 10 | let eddkeyWhitelisted = 11 | "0x27a5b716c7309a30703ede3f1a218cdec857e424a31543f8a658e7d2208db33"; 12 | 13 | const { accInfo } = await exchange.getAccount({ owner: addressWhitlisted }); 14 | 15 | console.log("accInfo:", accInfo); 16 | 17 | const { exchangeInfo } = await exchange.getExchangeInfo(); 18 | 19 | // step 2 get apikey 20 | const request: GetUserApiKeyRequest = { 21 | accountId: accInfo.accountId, 22 | }; 23 | 24 | const { apiKey } = await userApi.getUserApiKey(request, eddkeyWhitelisted); 25 | 26 | console.log("apiKey:", apiKey); 27 | 28 | // step 3 get storageId 29 | const request2: GetNextStorageIdRequest = { 30 | accountId: accInfo.accountId, 31 | sellTokenId: 1, 32 | }; 33 | const storageId = await userApi.getNextStorageId(request2, apiKey); 34 | 35 | // step 4 transfer 36 | const request3: OriginTransferRequestV3 = { 37 | exchange: exchangeInfo.exchangeAddress, 38 | payerAddr: addressWhitlisted, 39 | payerId: accInfo.accountId, 40 | payeeAddr: "0xb6AdaC3e924B4985Ad74646FEa3610f14cDFB79c", 41 | payeeId: 0, 42 | storageId: storageId.offchainId, 43 | token: { 44 | tokenId: 1, 45 | volume: "100000000000000000000", 46 | }, 47 | maxFee: { 48 | tokenId: 1, 49 | volume: "9400000000000000000", 50 | }, 51 | validUntil: VALID_UNTIL, 52 | }; 53 | 54 | console.log("request3:", request3); 55 | 56 | const response = await whitelistedUserApi.submitInternalTransfer( 57 | request3, 58 | eddkeyWhitelisted, 59 | apiKey 60 | ); 61 | 62 | console.log(response); 63 | ``` 64 | 65 | ## submitOffchainWithdraw is unavailable. 66 | 67 | TODO: submitOffchainWithdraw example 68 | -------------------------------------------------------------------------------- /docs/js_sdk/deposit/depositERC20.md: -------------------------------------------------------------------------------- 1 | # Deposit ERC20 2 | 3 | Definition: Move user L1 ERC20 assets to Loopring L2 4 | > **All Deposit Method, User should have enough `ETH` pay for the Ethereum Gas (Loopring have no charge, no fee for Deposit).** 5 | 6 | Provider will give the Gas Price & Limit, sdk also have a method get gasPrice: 7 | `const gasPrice = (await LoopringAPI.exchangeAPI.getGasPrice() ).gasPrice;` 8 | 9 | # ETH 10 | 11 | *** 12 | 13 | ## Step 1. getNonce 14 | 15 | ```ts 16 | const nonce = await sdk.getNonce(web3, LOOPRING_EXPORTED_ACCOUNT.address); 17 | console.log( 18 | `deposit: ${TOKEN_INFO.tokenMap.ETH.symbol}-${LOOPRING_EXPORTED_ACCOUNT.tradeETHValue}, gasPrice: ${LOOPRING_EXPORTED_ACCOUNT.gasPrice}, ` 19 | ); 20 | ``` 21 | 22 | *** 23 | 24 | ## Step 2. deposit 25 | 26 | ```ts 27 | const response = await sdk.deposit( 28 | web3, 29 | LOOPRING_EXPORTED_ACCOUNT.address, 30 | LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 31 | TOKEN_INFO.tokenMap.ETH, 32 | LOOPRING_EXPORTED_ACCOUNT.tradeETHValue, 33 | 0, 34 | LOOPRING_EXPORTED_ACCOUNT.gasPrice, 35 | LOOPRING_EXPORTED_ACCOUNT.gasLimit, 36 | sdk.ChainId.GOERLI, 37 | nonce, 38 | true 39 | ); 40 | 41 | console.log(`nonce: ${nonce} deposit_ETH: `, response); 42 | ``` 43 | 44 | # ERC20 45 | 46 | *** 47 | 48 | ## Step 1. getAllowances 49 | 50 | ```ts 51 | const {tokenAllowances} = await LoopringAPI.exchangeAPI.getAllowances({ 52 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 53 | token: [TOKEN_INFO.tokenMap.LRC.address], 54 | }); 55 | if ( 56 | tokenAllowances.has(TOKEN_INFO.tokenMap.LRC.address) && 57 | Number(tokenAllowances.get(TOKEN_INFO.tokenMap.LRC.address)) < 58 | LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue 59 | ) { 60 | const nonce = await web3.eth.getTransactionCount( 61 | LOOPRING_EXPORTED_ACCOUNT.address 62 | ); 63 | await sdk.approveMax( 64 | web3, 65 | LOOPRING_EXPORTED_ACCOUNT.address, 66 | TOKEN_INFO.tokenMap.LRC.address, // LRC address {tokenIdMap} = getTokens(); tokenIdMap['LRC'] 67 | LOOPRING_EXPORTED_ACCOUNT.depositAddress, //{exchangeInfo} = getExchangeInfo() exchangeInfo.depositAddress 68 | LOOPRING_EXPORTED_ACCOUNT.gasPrice, 69 | LOOPRING_EXPORTED_ACCOUNT.gasLimit, 70 | sdk.ChainId.GOERLI, 71 | nonce, 72 | true 73 | ); 74 | } 75 | ``` 76 | 77 | *** 78 | 79 | ## Step 2. getNonce 80 | 81 | ```ts 82 | const nonce = await sdk.getNonce(web3, LOOPRING_EXPORTED_ACCOUNT.address); 83 | console.log( 84 | `deposit: ${TOKEN_INFO.tokenMap.LRC.symbol}-${LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue}, gasPrice: ${LOOPRING_EXPORTED_ACCOUNT.gasPrice}, ` 85 | ); 86 | ``` 87 | 88 | *** 89 | 90 | ## Step 3. deposit 91 | 92 | ```ts 93 | const response = await sdk.deposit( 94 | web3, 95 | LOOPRING_EXPORTED_ACCOUNT.address, 96 | LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 97 | TOKEN_INFO.tokenMap.LRC, 98 | sdk 99 | .toBig(LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue) 100 | .div("1e" + TOKEN_INFO.tokenMap.LRC.decimals) 101 | .toNumber(), 102 | 0, 103 | LOOPRING_EXPORTED_ACCOUNT.gasPrice, 104 | LOOPRING_EXPORTED_ACCOUNT.gasLimit, 105 | sdk.ChainId.GOERLI, 106 | nonce, 107 | true 108 | ); 109 | 110 | console.log(`nonce: ${nonce} deposit_LRC: `, response); 111 | ``` 112 | 113 | -------------------------------------------------------------------------------- /docs/js_sdk/deposit/depositNFT.md: -------------------------------------------------------------------------------- 1 | # Deposit NFT 2 | 3 | Definition: Move user L1 NFT assets to Loopring L2 4 | 5 | > **All Deposit Method, User should have enough `ETH` pay for the Ethereum Gas (Loopring have no charge, no fee for Deposit).** 6 | 7 | 8 | *** 9 | 10 | ## Step 1. getNFTBalance & getEthBalances 11 | 12 | ```ts 13 | const {ethBalance} = await LoopringAPI.exchangeAPI.getEthBalances({ 14 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 15 | }); 16 | const nftBalance = await LoopringAPI.nftAPI.getNFTBalance({ 17 | web3, 18 | account: LOOPRING_EXPORTED_ACCOUNT.address, 19 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 20 | nftId: LOOPRING_EXPORTED_ACCOUNT.nftId, 21 | nftType: sdk.NFTType.ERC1155, 22 | }); 23 | ``` 24 | 25 | *** 26 | 27 | ## Step 2. isApprovedForAll 28 | 29 | ```ts 30 | const isApprovedForAll = await LoopringAPI.nftAPI.isApprovedForAll({ 31 | web3, 32 | from: LOOPRING_EXPORTED_ACCOUNT.address, 33 | exchangeAddress: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 34 | nftType: sdk.NFTType.ERC1155, // todo: sdk.NFTType.ERC721 35 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 36 | }); 37 | console.log(`check is approveNFT`, isApprovedForAll); 38 | 39 | ``` 40 | 41 | *** 42 | 43 | ## Step 3. approveNFT All 44 | 45 | ```ts 46 | if (!isApprovedForAll) { 47 | const nonce = await sdk.getNonce( 48 | web3, 49 | LOOPRING_EXPORTED_ACCOUNT.address 50 | ); 51 | const approveNFT = await LoopringAPI.nftAPI.approveNFT({ 52 | web3, 53 | from: LOOPRING_EXPORTED_ACCOUNT.address, 54 | depositAddress: LOOPRING_EXPORTED_ACCOUNT.depositAddress, 55 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 56 | nftType: sdk.NFTType.ERC1155, // todo: sdk.NFTType.ERC721 57 | gasPrice: LOOPRING_EXPORTED_ACCOUNT.gasPrice, 58 | gasLimit: LOOPRING_EXPORTED_ACCOUNT.gasLimit, 59 | chainId: sdk.ChainId.GOERLI, 60 | nonce, 61 | sendByMetaMask: true, 62 | }); 63 | console.log(`nonce: ${nonce} approveNFT: ${approveNFT?.result}`); 64 | } 65 | ``` 66 | 67 | *** 68 | 69 | ## Step 3. nonce 70 | 71 | ```ts 72 | const nonce = await sdk.getNonce(web3, LOOPRING_EXPORTED_ACCOUNT.address); 73 | 74 | console.log( 75 | `deposit: NFT, gasPrice: ${LOOPRING_EXPORTED_ACCOUNT.gasPrice}, ` 76 | ); 77 | ``` 78 | 79 | *** 80 | 81 | ## Step 4. depositNFT 82 | 83 | ```ts 84 | const response = await LoopringAPI.nftAPI.depositNFT({ 85 | web3, 86 | from: LOOPRING_EXPORTED_ACCOUNT.address, 87 | exchangeAddress: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 88 | nftType: sdk.NFTType.ERC1155, // todo: sdk.NFTType.ERC721 89 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 90 | nftId: LOOPRING_EXPORTED_ACCOUNT.nftId, 91 | amount: 2, // todo:when sdk.NFTType.ERC721 amount: 1, 92 | gasPrice: LOOPRING_EXPORTED_ACCOUNT.gasPrice, 93 | gasLimit: LOOPRING_EXPORTED_ACCOUNT.gasLimit + 100000, 94 | chainId: sdk.ChainId.GOERLI, 95 | nonce, 96 | sendByMetaMask: true, 97 | }); 98 | console.log(`nonce: ${nonce} deposit NFT ERC1155: `, response); 99 | 100 | ``` 101 | -------------------------------------------------------------------------------- /docs/js_sdk/exchange/ammpool_api.md: -------------------------------------------------------------------------------- 1 | # AmmPool API 2 | 3 | ## getAmmPoolConf 4 | 5 | ```typescript 6 | const { ammpools, pairs } = await api.getAmmPoolConf(); 7 | ``` 8 | 9 | ## getAmmPoolUserRewards 10 | 11 | ```typescript 12 | const response: any = await api.getAmmPoolUserRewards({ 13 | owner: acc.accountId.toString(), 14 | }); 15 | ``` 16 | 17 | ## getAmmPoolActivityRules 18 | 19 | ```typescript 20 | const response: any = await api.getAmmPoolActivityRules(); 21 | ``` 22 | 23 | ## getAmmPoolStats 24 | 25 | ```typescript 26 | const response: any = await api.getAmmPoolStats(); 27 | ``` 28 | 29 | ## getAmmPoolSnapshot 30 | 31 | ```typescript 32 | const request: GetAmmPoolSnapshotRequest = { 33 | poolAddress, 34 | }; 35 | const response = await api.getAmmPoolSnapshot(request, acc.apiKey); 36 | ``` 37 | 38 | ## getAmmPoolBalances 39 | 40 | ```typescript 41 | const response = await api.getAmmPoolBalances(); 42 | ``` 43 | 44 | ## getAmmPoolTrades 45 | 46 | ```typescript 47 | const request: GetAmmPoolTradesRequest = { 48 | ammPoolAddress: poolAddress, 49 | }; 50 | 51 | const response = await api.getAmmPoolTrades(request); 52 | ``` 53 | 54 | ## getUserAmmPoolTxs 55 | 56 | ```typescript 57 | const request: GetUserAmmPoolTxsRequest = { 58 | accountId: acc.accountId, 59 | }; 60 | 61 | const response = await api.getUserAmmPoolTxs(request, acc.apiKey); 62 | ``` 63 | 64 | ## joinAmmPool 65 | 66 | ```typescript 67 | const request2: JoinAmmPoolRequest = { 68 | owner: acc.address, 69 | poolAddress, 70 | joinTokens: { 71 | pooled: [ 72 | { tokenId: "1", volume: "1000000000000000000000" }, 73 | { tokenId: "0", volume: "1000000000000000000" }, 74 | ], 75 | minimumLp: { tokenId: "4", volume: "100000" }, 76 | }, 77 | storageIds: [storageId_1.offchainId, storageId.offchainId], 78 | fee: "1000000000000000000", 79 | }; 80 | 81 | const patch: AmmPoolRequestPatch = { 82 | chainId: ChainId.GORLI, 83 | ammName: "LRCETH-Pool", 84 | poolAddress, 85 | eddsaKey: acc.eddsaKey, 86 | }; 87 | 88 | const response = await api.joinAmmPool(request2, patch, acc.apiKey); 89 | ``` 90 | 91 | ## exitAmmPool 92 | 93 | ```typescript 94 | const request2: ExitAmmPoolRequest = { 95 | owner: acc.address, 96 | poolAddress, 97 | exitTokens: { 98 | unPooled: [ 99 | { tokenId: "1", volume: "1000000000000000000000" }, 100 | { tokenId: "0", volume: "1000000000000000000" }, 101 | ], 102 | burned: { tokenId: "4", volume: "100000" }, 103 | }, 104 | storageId: storageId_1.offchainId, 105 | maxFee: "1000000000000000000", 106 | }; 107 | 108 | const patch: AmmPoolRequestPatch = { 109 | chainId: ChainId.GORLI, 110 | ammName: "LRCETH-Pool", 111 | poolAddress, 112 | eddsaKey: acc.eddsaKey, 113 | }; 114 | 115 | const response = await api.exitAmmPool(request2, patch, acc.apiKey); 116 | ``` 117 | -------------------------------------------------------------------------------- /docs/js_sdk/exchange/webSocket.md: -------------------------------------------------------------------------------- 1 | #WebSocket Command 2 | Definition: Loopring L2 websocket 3 | 4 | ### Loopring L2 websocket topic type: 5 | WsTopicType 6 | - `account` 7 | - `orderbook` 8 | - `mixorder` 9 | - `mixtrade` 10 | - `ticker` 11 | - `candlestick` 12 | - `ammpool` 13 | 14 | ## getWsKey (required by account related socket) 15 | ```ts 16 | const response = await LoopringAPI.wsAPI.getWsKey(); 17 | console.log(response); 18 | ``` 19 | ## getOrderBookArg 20 | ```ts 21 | const arg1 = sdk.getMixOrderArg({ market: "LRC-ETH", level: 50 }); 22 | console.log(arg1); 23 | 24 | const arg2 = sdk.getOrderBookArg({ 25 | market: "LRC-ETH", 26 | level: 50, 27 | count: 40, 28 | snapshot: false, 29 | }); 30 | console.log(arg2); 31 | ``` -------------------------------------------------------------------------------- /docs/js_sdk/transfer/transferERC20.md: -------------------------------------------------------------------------------- 1 | # Transfer ERC20 2 | Definition: Send ERC20 tokens to other account on Loopring L2, 3 | > trade value should with decimals `sdk.toBig(value).times("1e" + TOKEN_INFO.tokenMap.LRC.decimals)` 4 | 5 | *** 6 | ## Step 1. get account Info 7 | const { exchangeInfo } = await LoopringAPI.exchangeAPI.getExchangeInfo(); 8 | const LOOPRING_EXPORTED_ACCOUNT.exchangeAddress = exchangeInfo; 9 | 10 | ```ts 11 | const { accInfo } = await LoopringAPI.exchangeAPI.getAccount({ 12 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 13 | }); 14 | console.log("accInfo:", accInfo); 15 | 16 | ``` 17 | *** 18 | ## Step 2. get eddsaKey 19 | ```ts 20 | const eddsaKey = await signatureKeyPairMock(accInfo); 21 | console.log("eddsaKey:", eddsaKey.sk); 22 | ``` 23 | *** 24 | ## Step 3. get apikey 25 | ```ts 26 | const { apiKey } = await LoopringAPI.userAPI.getUserApiKey( 27 | { 28 | accountId: accInfo.accountId, 29 | }, 30 | eddsaKey.sk 31 | ); 32 | console.log("apiKey:", apiKey); 33 | const { userBalances } = await LoopringAPI.userAPI.getUserBalances( 34 | { accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, tokens: "" }, 35 | apiKey 36 | ); 37 | ``` 38 | 39 | *** 40 | ## Step 4. get storageId 41 | ```ts 42 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 43 | { 44 | accountId: accInfo.accountId, 45 | sellTokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 46 | }, 47 | apiKey 48 | ); 49 | console.log("storageId:", storageId); 50 | ``` 51 | 52 | *** 53 | ## Step 5. get fee 54 | ```ts 55 | const fee = await LoopringAPI.userAPI.getOffchainFeeAmt({ 56 | accountId: accInfo.accountId, 57 | requestType: sdk.OffchainFeeReqType.TRANSFER, 58 | }, apiKey); 59 | console.log("fee:", fee); 60 | ``` 61 | *** 62 | ## Step 6. transfer 63 | ```ts 64 | const transferResult = await LoopringAPI.userAPI.submitInternalTransfer({ 65 | request: { 66 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 67 | payerAddr: accInfo.owner, 68 | payerId: accInfo.accountId, 69 | payeeAddr: LOOPRING_EXPORTED_ACCOUNT.address2, 70 | payeeId: LOOPRING_EXPORTED_ACCOUNT.accountId2, 71 | storageId: storageId.offchainId, 72 | token: { 73 | tokenId: TOKEN_INFO.tokenMap.LRC.tokenId, 74 | volume: LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue.toString(), 75 | }, 76 | maxFee: { 77 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 78 | volume: fee.fees["LRC"].fee ?? "9400000000000000000", 79 | }, 80 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 81 | }, 82 | web3, 83 | chainId: sdk.ChainId.GOERLI, 84 | walletType: sdk.ConnectorNames.Trezor, 85 | eddsaKey: eddsaKey.sk, 86 | apiKey: apiKey, 87 | }); 88 | console.log("transferResult:", transferResult); 89 | ``` -------------------------------------------------------------------------------- /docs/js_sdk/transfer/transferNFT.md: -------------------------------------------------------------------------------- 1 | # Transfer NFT 2 | Definition: Send NFT to other account on Loopring L2 3 | 4 | *** 5 | ## Step 1. get account Info 6 | ```ts 7 | const { exchangeInfo } = await LoopringAPI.exchangeAPI.getExchangeInfo(); 8 | const LOOPRING_EXPORTED_ACCOUNT.exchangeAddress = exchangeInfo; 9 | const { accInfo } = await LoopringAPI.exchangeAPI.getAccount({ 10 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 11 | }); 12 | ``` 13 | 14 | *** 15 | ## Step 2. get eddsaKey 16 | ```ts 17 | const eddsaKey = await signatureKeyPairMock(accInfo); 18 | console.log("eddsaKey:", eddsaKey.sk); 19 | ``` 20 | 21 | *** 22 | ## Step 3. get apiKey 23 | ```ts 24 | const { apiKey } = await LoopringAPI.userAPI.getUserApiKey({ 25 | accountId: accInfo.accountId}, eddsaKey.sk 26 | ); 27 | console.log("apiKey:", apiKey); 28 | const { userNFTBalances } = await LoopringAPI.userAPI.getUserNFTBalances( 29 | { accountId: accInfo.accountId, limit: 20 }, 30 | apiKey 31 | ); 32 | ``` 33 | 34 | *** 35 | ##Step 4. get storageId 36 | ```ts 37 | const storageId = await LoopringAPI.userAPI.getNextStorageId({ 38 | accountId: accInfo.accountId, 39 | sellTokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 40 | }, apiKey); 41 | ``` 42 | 43 | *** 44 | ## Step 5. get fee 45 | ```ts 46 | const fee = await LoopringAPI.userAPI.getNFTOffchainFeeAmt({ 47 | accountId: accInfo.accountId, 48 | requestType: sdk.OffchainNFTFeeReqType.NFT_TRANSFER, 49 | amount: "0", 50 | }, apiKey); 51 | console.log("fee:", fee); 52 | ``` 53 | 54 | *** 55 | ## Step 6. Transfer NFT 56 | ```ts 57 | const transferResult = await LoopringAPI.userAPI.submitNFTInTransfer({ 58 | request: { 59 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 60 | fromAccountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 61 | fromAddress: LOOPRING_EXPORTED_ACCOUNT.address, 62 | toAccountId: 0, // toAccountId is not required, input 0 as default 63 | toAddress: LOOPRING_EXPORTED_ACCOUNT.address2, 64 | token: { 65 | tokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 66 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 67 | amount: "1", 68 | }, 69 | maxFee: { 70 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 71 | amount: fee.fees["LRC"].fee ?? "9400000000000000000", 72 | }, 73 | storageId: storageId.offchainId, 74 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 75 | }, 76 | web3, 77 | chainId: sdk.ChainId.GOERLI, 78 | walletType: sdk.ConnectorNames.Unknown, 79 | eddsaKey: eddsaKey.sk, 80 | apiKey, 81 | }); 82 | console.log("transfer Result:", transferResult); 83 | ``` -------------------------------------------------------------------------------- /docs/js_sdk/withdraw/withdrawERC20.md: -------------------------------------------------------------------------------- 1 | # Withdraw ERC20 2 | 3 | Definition: Loopring L2 withdraw ERC20 to Ethereum L1, 4 | > trade value should with decimals `sdk.toBig(value).times("1e" + TOKEN_INFO.tokenMap.LRC.decimals)` 5 | 6 | *** 7 | 8 | ## Step 1. getAccount 9 | 10 | ```ts 11 | const {accInfo} = await LoopringAPI.exchangeAPI.getAccount({ 12 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 13 | }); 14 | console.log("accInfo:", accInfo); 15 | ``` 16 | 17 | ##Step 2. eddsaKey 18 | 19 | ```ts 20 | const eddsaKey = await signatureKeyPairMock(accInfo); 21 | console.log("eddsaKey:", eddsaKey.sk); 22 | ``` 23 | 24 | *** 25 | 26 | ## Step 3. apiKey 27 | 28 | ```ts 29 | const {apiKey} = await LoopringAPI.userAPI.getUserApiKey({ 30 | accountId: accInfo.accountId, 31 | }, 32 | eddsaKey.sk 33 | ); 34 | console.log("apiKey:", apiKey); 35 | 36 | ``` 37 | 38 | *** 39 | 40 | ## Step 4. storageId 41 | 42 | ```ts 43 | const storageId = await LoopringAPI.userAPI.getNextStorageId({ 44 | accountId: accInfo.accountId, 45 | sellTokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 46 | }, 47 | apiKey 48 | ); 49 | console.log("storageId:", storageId); 50 | 51 | ``` 52 | 53 | *** 54 | 55 | ## Step 5. fee 56 | 57 | ```ts 58 | const fee = await LoopringAPI.userAPI.getOffchainFeeAmt({ 59 | accountId: accInfo.accountId, 60 | requestType: sdk.OffchainFeeReqType.OFFCHAIN_WITHDRAWAL, 61 | tokenSymbol: TOKEN_INFO.tokenMap["LRC"].symbol, 62 | }, 63 | apiKey 64 | ); 65 | console.log("fee:", fee); 66 | 67 | ``` 68 | 69 | *** 70 | 71 | ## Step 6. withdraw 72 | 73 | ```ts 74 | const response = await LoopringAPI.userAPI.submitOffchainWithdraw({ 75 | request: { 76 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 77 | accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 78 | counterFactualInfo: undefined, 79 | fastWithdrawalMode: false, 80 | hashApproved: "", 81 | maxFee: { 82 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 83 | volume: fee.fees["LRC"].fee ?? "9400000000000000000", 84 | }, 85 | minGas: 0, 86 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 87 | to: LOOPRING_EXPORTED_ACCOUNT.address, 88 | storageId: 0, 89 | token: { 90 | tokenId: TOKEN_INFO.tokenMap.LRC.tokenId, 91 | volume: LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue.toString(), 92 | }, 93 | validUntil: 0, 94 | }, 95 | web3, 96 | chainId: sdk.ChainId.GOERLI, 97 | walletType: sdk.ConnectorNames.MetaMask, 98 | eddsaKey: eddsaKey.sk, 99 | apiKey, 100 | }); 101 | console.log("response:", response); 102 | ``` -------------------------------------------------------------------------------- /docs/js_sdk/withdraw/withdrawNFT.md: -------------------------------------------------------------------------------- 1 | # Withdraw NFT 2 | 3 | Definition: Loopring L2 withdraw NFT to Ethereum L1 4 | 5 | *** 6 | 7 | ## Step 1. getAccount 8 | 9 | ```ts 10 | const {accInfo} = await LoopringAPI.exchangeAPI.getAccount({ 11 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 12 | }); 13 | console.log("accInfo:", accInfo); 14 | ``` 15 | 16 | *** 17 | 18 | ## Step 2. eddsaKey 19 | 20 | ```ts 21 | 22 | const eddsaKey = await signatureKeyPairMock(accInfo); 23 | console.log("eddsaKey:", eddsaKey.sk); 24 | 25 | ``` 26 | 27 | *** 28 | 29 | ## Step 3. apiKey 30 | 31 | ```ts 32 | const {apiKey} = await LoopringAPI.userAPI.getUserApiKey( 33 | { 34 | accountId: accInfo.accountId, 35 | }, 36 | eddsaKey.sk 37 | ); 38 | console.log("apiKey:", apiKey); 39 | ``` 40 | 41 | *** 42 | 43 | ## Step 4. storageId 44 | 45 | ```ts 46 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 47 | { 48 | accountId: accInfo.accountId, 49 | sellTokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 50 | }, 51 | apiKey 52 | ); 53 | console.log("storageId:", storageId); 54 | 55 | //Step 5. getUserNFTBalances 56 | const {userNFTBalances} = await LoopringAPI.userAPI.getUserNFTBalances( 57 | {accountId: LOOPRING_EXPORTED_ACCOUNT.accountId}, 58 | apiKey 59 | ); 60 | const tokenInfo = userNFTBalances.find( 61 | (item) => 62 | item.tokenAddress?.toLowerCase() === 63 | LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress.toLowerCase() && 64 | item.nftId && 65 | web3.utils.hexToNumberString(item.nftId) === 66 | LOOPRING_EXPORTED_ACCOUNT.nftTokenId.toString() 67 | ); 68 | ``` 69 | 70 | *** 71 | 72 | ## Step 5. fee 73 | 74 | ```ts 75 | const fee = await LoopringAPI.userAPI.getNFTOffchainFeeAmt( 76 | { 77 | accountId: accInfo.accountId, 78 | requestType: sdk.OffchainNFTFeeReqType.NFT_WITHDRAWAL, 79 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 80 | deployInWithdraw: 81 | tokenInfo?.deploymentStatus === DEPLOYMENT_STATUS.NOT_DEPLOYED, // when token is not deploy the fee is diff 82 | }, 83 | apiKey 84 | ); 85 | console.log("fee:", fee); 86 | ``` 87 | 88 | *** 89 | 90 | ## Step 6. withdraw 91 | 92 | ```ts 93 | const response = await LoopringAPI.userAPI.submitNFTWithdraw({ 94 | request: { 95 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 96 | accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 97 | counterFactualInfo: undefined, 98 | hashApproved: "", 99 | maxFee: { 100 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 101 | amount: fee.fees["LRC"].fee ?? "9400000000000000000", 102 | }, 103 | minGas: 0, 104 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 105 | to: LOOPRING_EXPORTED_ACCOUNT.address, 106 | storageId: 0, 107 | token: { 108 | tokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 109 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 110 | amount: "1", 111 | }, 112 | validUntil: 0, 113 | }, 114 | web3, 115 | chainId: sdk.ChainId.GOERLI, 116 | walletType: sdk.ConnectorNames.MetaMask, 117 | eddsaKey: eddsaKey.sk, 118 | apiKey, 119 | }); 120 | console.log("response:", response); 121 | ``` -------------------------------------------------------------------------------- /jest.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | verbose: true, 4 | transform: { 5 | '^.+\\.(js|jsx|ts|tsx)$': './node_modules/babel-jest', 6 | }, 7 | "moduleNameMapper": { 8 | "axios": "axios/dist/node/axios.cjs" 9 | }, 10 | "transformIgnorePatterns": ["node_modules\/(?!axios)"] 11 | } 12 | -------------------------------------------------------------------------------- /rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import commonjs from '@rollup/plugin-commonjs'; 2 | import babel from '@rollup/plugin-babel' 3 | import terser from '@rollup/plugin-terser' 4 | import json from '@rollup/plugin-json'; 5 | import { nodeResolve } from '@rollup/plugin-node-resolve'; 6 | import typescript from 'rollup-plugin-typescript2'; 7 | import { builtinModules } from 'module'; 8 | import pkg from './package.json' assert { type: "json" }; 9 | // console.log('pkg',pkg) 10 | module.exports = { 11 | input: pkg.source, 12 | output: [ 13 | { file:pkg.main , format: 'cjs', sourcemap: true, plugins: [terser()], }, 14 | { file: pkg.module , format: 'esm', sourcemap: true, plugins: [terser()], } 15 | ], 16 | external: [ 17 | ...builtinModules, 18 | ...(pkg.dependencies ? Object.keys(pkg.dependencies) : []), 19 | ...(pkg.devDependencies ? Object.keys(pkg.devDependencies) : []), 20 | ...(pkg.peerDependencies ? Object.keys(pkg.peerDependencies) : []) 21 | ], 22 | watch: { 23 | include: 'src/**', 24 | }, 25 | plugins: [ 26 | json(), 27 | typescript({ 28 | abortOnError: process.env.NODE_ENV === 'production', 29 | tsconfig:'./tsconfig.json', 30 | tsconfigDefaults: { 31 | exclude: [ 32 | // all TS test files, regardless whether co-located or in test/ etc 33 | '**/*.spec.ts', 34 | '**/*.test.ts', 35 | '**/*.spec.ts', 36 | '**/*.test.ts', 37 | // TS defaults below 38 | 'node_modules', 39 | 'bower_components', 40 | 'jspm_packages', 41 | ], 42 | compilerOptions: { 43 | sourceMap: true, 44 | declaration: true, 45 | jsx: 'react', 46 | }, 47 | }, 48 | tsconfigOverride: { 49 | compilerOptions: Object.assign({ 50 | // TS -> esnext, then leave the rest to babel-preset-env 51 | target: 'esnext' }, { declaration: true, declarationMap: true }), 52 | }, 53 | } 54 | ), 55 | commonjs() , 56 | nodeResolve({ 57 | exportConditions: ['import', 'default', 'require'], 58 | mainFields: ['module', 'main', 'browser'], 59 | modulesOnly: true, 60 | preferBuiltins: false, 61 | }), 62 | babel({ 63 | babelHelpers: 'bundled', 64 | include: ['src/**/*.ts'], 65 | exclude: './node_modules/**', 66 | }), 67 | ] 68 | }; 69 | -------------------------------------------------------------------------------- /src/api/config/abis/contractWallet.ts: -------------------------------------------------------------------------------- 1 | export const contractWallet = [ 2 | { 3 | inputs: [ 4 | { 5 | internalType: 'bytes', 6 | name: '_data', 7 | type: 'bytes', 8 | }, 9 | { 10 | internalType: 'bytes', 11 | name: '_signature', 12 | type: 'bytes', 13 | }, 14 | ], 15 | name: 'isValidSignature', 16 | outputs: [ 17 | { 18 | internalType: 'bytes4', 19 | name: 'magicValue', 20 | type: 'bytes4', 21 | }, 22 | ], 23 | stateMutability: 'view', 24 | type: 'function', 25 | }, 26 | { 27 | inputs: [ 28 | { 29 | internalType: 'bytes', 30 | name: '_data', 31 | type: 'bytes32', 32 | }, 33 | { 34 | internalType: 'bytes', 35 | name: '_signature', 36 | type: 'bytes', 37 | }, 38 | ], 39 | name: 'isValidSignature', 40 | outputs: [ 41 | { 42 | internalType: 'bytes4', 43 | name: 'magicValue', 44 | type: 'bytes4', 45 | }, 46 | ], 47 | stateMutability: 'view', 48 | type: 'function', 49 | }, 50 | { 51 | constant: true, 52 | inputs: [ 53 | { 54 | name: '_account', 55 | type: 'address', 56 | }, 57 | { 58 | name: '_index', 59 | type: 'uint256', 60 | }, 61 | ], 62 | name: 'getKeyData', 63 | outputs: [ 64 | { 65 | name: '', 66 | type: 'address', 67 | }, 68 | ], 69 | payable: false, 70 | stateMutability: 'view', 71 | type: 'function', 72 | }, 73 | ] 74 | -------------------------------------------------------------------------------- /src/api/config/abis/erc20.ts: -------------------------------------------------------------------------------- 1 | export const erc20 = [ 2 | { 3 | constant: true, 4 | inputs: [], 5 | name: 'name', 6 | outputs: [ 7 | { 8 | name: '', 9 | type: 'string', 10 | }, 11 | ], 12 | payable: false, 13 | stateMutability: 'view', 14 | type: 'function', 15 | }, 16 | { 17 | constant: false, 18 | inputs: [ 19 | { 20 | name: '_spender', 21 | type: 'address', 22 | }, 23 | { 24 | name: '_value', 25 | type: 'uint256', 26 | }, 27 | ], 28 | name: 'approve', 29 | outputs: [ 30 | { 31 | name: '', 32 | type: 'bool', 33 | }, 34 | ], 35 | payable: false, 36 | stateMutability: 'nonpayable', 37 | type: 'function', 38 | }, 39 | { 40 | constant: false, 41 | inputs: [ 42 | { 43 | name: '_from', 44 | type: 'address', 45 | }, 46 | { 47 | name: '_to', 48 | type: 'address', 49 | }, 50 | { 51 | name: '_value', 52 | type: 'uint256', 53 | }, 54 | ], 55 | name: 'transferFrom', 56 | outputs: [ 57 | { 58 | name: '', 59 | type: 'bool', 60 | }, 61 | ], 62 | payable: false, 63 | stateMutability: 'nonpayable', 64 | type: 'function', 65 | }, 66 | { 67 | constant: true, 68 | inputs: [], 69 | name: 'decimals', 70 | outputs: [ 71 | { 72 | name: '', 73 | type: 'uint8', 74 | }, 75 | ], 76 | payable: false, 77 | stateMutability: 'view', 78 | type: 'function', 79 | }, 80 | { 81 | constant: true, 82 | inputs: [ 83 | { 84 | name: '_owner', 85 | type: 'address', 86 | }, 87 | ], 88 | name: 'balanceOf', 89 | outputs: [ 90 | { 91 | name: 'balance', 92 | type: 'uint256', 93 | }, 94 | ], 95 | payable: false, 96 | stateMutability: 'view', 97 | type: 'function', 98 | }, 99 | { 100 | constant: true, 101 | inputs: [], 102 | name: 'symbol', 103 | outputs: [ 104 | { 105 | name: '', 106 | type: 'string', 107 | }, 108 | ], 109 | payable: false, 110 | stateMutability: 'view', 111 | type: 'function', 112 | }, 113 | { 114 | constant: false, 115 | inputs: [ 116 | { 117 | name: '_to', 118 | type: 'address', 119 | }, 120 | { 121 | name: '_value', 122 | type: 'uint256', 123 | }, 124 | ], 125 | name: 'transfer', 126 | outputs: [ 127 | { 128 | name: '', 129 | type: 'bool', 130 | }, 131 | ], 132 | payable: false, 133 | stateMutability: 'nonpayable', 134 | type: 'function', 135 | }, 136 | { 137 | constant: true, 138 | inputs: [ 139 | { 140 | name: '_owner', 141 | type: 'address', 142 | }, 143 | { 144 | name: '_spender', 145 | type: 'address', 146 | }, 147 | ], 148 | name: 'allowance', 149 | outputs: [ 150 | { 151 | name: '', 152 | type: 'uint256', 153 | }, 154 | ], 155 | payable: false, 156 | stateMutability: 'view', 157 | type: 'function', 158 | }, 159 | { 160 | payable: true, 161 | stateMutability: 'payable', 162 | type: 'fallback', 163 | }, 164 | { 165 | anonymous: false, 166 | inputs: [ 167 | { 168 | indexed: true, 169 | name: 'owner', 170 | type: 'address', 171 | }, 172 | { 173 | indexed: true, 174 | name: 'spender', 175 | type: 'address', 176 | }, 177 | { 178 | indexed: false, 179 | name: 'value', 180 | type: 'uint256', 181 | }, 182 | ], 183 | name: 'Approval', 184 | type: 'event', 185 | }, 186 | { 187 | anonymous: false, 188 | inputs: [ 189 | { 190 | indexed: true, 191 | name: 'from', 192 | type: 'address', 193 | }, 194 | { 195 | indexed: true, 196 | name: 'to', 197 | type: 'address', 198 | }, 199 | { 200 | indexed: false, 201 | name: 'value', 202 | type: 'uint256', 203 | }, 204 | ], 205 | name: 'Transfer', 206 | type: 'event', 207 | }, 208 | ] 209 | -------------------------------------------------------------------------------- /src/api/config/abis/exchange_3_6.ts: -------------------------------------------------------------------------------- 1 | export const exchange = [ 2 | { 3 | inputs: [ 4 | { 5 | internalType: "address", 6 | name: "owner", 7 | type: "address", 8 | }, 9 | { 10 | internalType: "address", 11 | name: "tokenAddress", 12 | type: "address", 13 | }, 14 | { 15 | internalType: "uint32", 16 | name: "accountID", 17 | type: "uint32", 18 | }, 19 | ], 20 | name: "forceWithdraw", 21 | outputs: [], 22 | stateMutability: "payable", 23 | type: "function", 24 | }, 25 | { 26 | inputs: [ 27 | { 28 | internalType: "address", 29 | name: "from", 30 | type: "address", 31 | }, 32 | { 33 | internalType: "address", 34 | name: "to", 35 | type: "address", 36 | }, 37 | { 38 | internalType: "address", 39 | name: "tokenAddress", 40 | type: "address", 41 | }, 42 | { 43 | internalType: "uint96", 44 | name: "amount", 45 | type: "uint96", 46 | }, 47 | { 48 | internalType: "bytes", 49 | name: "extraData", 50 | type: "bytes", 51 | }, 52 | ], 53 | name: "deposit", 54 | outputs: [], 55 | stateMutability: "payable", 56 | type: "function", 57 | }, 58 | { 59 | inputs: [ 60 | { 61 | internalType: "address", 62 | name: "from", 63 | type: "address", 64 | }, 65 | { 66 | internalType: "address", 67 | name: "to", 68 | type: "address", 69 | }, 70 | { 71 | internalType: "enum ExchangeData.NftType", 72 | name: "nftType", 73 | type: "uint8", 74 | }, 75 | { 76 | internalType: "address", 77 | name: "tokenAddress", 78 | type: "address", 79 | }, 80 | { 81 | internalType: "uint256", 82 | name: "nftId", 83 | type: "uint256", 84 | }, 85 | { 86 | internalType: "uint96", 87 | name: "amount", 88 | type: "uint96", 89 | }, 90 | { 91 | internalType: "bytes", 92 | name: "extraData", 93 | type: "bytes", 94 | }, 95 | ], 96 | name: "depositNFT", 97 | outputs: [], 98 | stateMutability: "nonpayable", 99 | type: "function", 100 | }, 101 | { 102 | inputs: [ 103 | { 104 | internalType: "address", 105 | name: "owner", 106 | type: "address", 107 | }, 108 | { 109 | internalType: "address", 110 | name: "token", 111 | type: "address", 112 | }, 113 | ], 114 | name: "withdrawFromDepositRequest", 115 | outputs: [], 116 | stateMutability: "nonpayable", 117 | type: "function", 118 | }, 119 | { 120 | inputs: [ 121 | { 122 | internalType: "address[]", 123 | name: "owners", 124 | type: "address[]", 125 | }, 126 | { 127 | internalType: "address[]", 128 | name: "tokens", 129 | type: "address[]", 130 | }, 131 | ], 132 | name: "withdrawFromApprovedWithdrawals", 133 | outputs: [], 134 | stateMutability: "nonpayable", 135 | type: "function", 136 | }, 137 | { 138 | inputs: [ 139 | { 140 | internalType: "address", 141 | name: "owner", 142 | type: "address", 143 | }, 144 | { 145 | internalType: "address", 146 | name: "token", 147 | type: "address", 148 | }, 149 | ], 150 | name: "getAmountWithdrawable", 151 | outputs: [ 152 | { 153 | internalType: "uint256", 154 | name: "", 155 | type: "uint256", 156 | }, 157 | ], 158 | stateMutability: "view", 159 | type: "function", 160 | }, 161 | { 162 | inputs: [ 163 | { 164 | internalType: "address", 165 | name: "owner", 166 | type: "address", 167 | }, 168 | { 169 | internalType: "bytes32", 170 | name: "txHash", 171 | type: "bytes32", 172 | }, 173 | ], 174 | name: "approveTransaction", 175 | outputs: [], 176 | stateMutability: "nonpayable", 177 | type: "function", 178 | }, 179 | ]; 180 | -------------------------------------------------------------------------------- /src/api/config/abis/hebao.ts: -------------------------------------------------------------------------------- 1 | export const hebao = [ 2 | { 3 | inputs: [ 4 | { 5 | internalType: 'address', 6 | name: 'wallet', 7 | type: 'address', 8 | }, 9 | ], 10 | name: 'lock', 11 | outputs: [], 12 | stateMutability: 'nonpayable', 13 | type: 'function', 14 | }, 15 | { 16 | inputs: [ 17 | { 18 | internalType: 'address', 19 | name: 'wallet', 20 | type: 'address', 21 | }, 22 | { 23 | internalType: 'address', 24 | name: 'guardian', 25 | type: 'address', 26 | }, 27 | ], 28 | name: 'unlock', 29 | outputs: [], 30 | stateMutability: 'nonpayable', 31 | type: 'function', 32 | }, 33 | ] 34 | -------------------------------------------------------------------------------- /src/api/config/abis/index.ts: -------------------------------------------------------------------------------- 1 | export * as contractWalletAbi from './contractWallet' 2 | export * as erc20Abi from './erc20' 3 | export * as erc721Abi from './erc721' 4 | export * as erc1155Abi from './erc1155' 5 | export * as exchange36Abi from './exchange_3_6' 6 | export * as hebao from './hebao' 7 | export * as smartWallet from './smartWallet' 8 | -------------------------------------------------------------------------------- /src/api/config/index.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | // @ts-nocheck 3 | import { toBig, toFixed } from '../../utils/formatter' 4 | import BigNumber from 'bignumber.js' 5 | 6 | function getTokenBySymbol(symbol, tokens) { 7 | if (typeof symbol === 'undefined') { 8 | return {} 9 | } 10 | return tokens.find((token) => token.symbol.toLowerCase() === symbol.toLowerCase()) || {} 11 | } 12 | 13 | function fromWEI(symbol, valueInWEI, tokens, { precision, ceil }: any = {}) { 14 | try { 15 | const token = getTokenBySymbol(symbol, tokens) 16 | const precisionToFixed = precision ? precision : token.precision 17 | const value = toBig(valueInWEI).div('1e' + token.decimals) 18 | return toFixed(value, precisionToFixed, ceil) 19 | } catch (err) { 20 | return undefined 21 | } 22 | } 23 | 24 | function toWEI(symbol, value, tokens, rm = BigNumber.ROUND_FLOOR) { 25 | const token = getTokenBySymbol(symbol, tokens) 26 | if (typeof token === 'undefined') { 27 | return 0 28 | } 29 | return toBig(value) 30 | .times('1e' + token.decimals) 31 | .toFixed(0, rm) 32 | } 33 | 34 | export { fromWEI, toWEI } 35 | export * from './guardianTypeData' 36 | -------------------------------------------------------------------------------- /src/api/contacts_api.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | import { BaseAPI } from './base_api' 3 | 4 | import * as loopring_defs from '../defs' 5 | 6 | export class ContactAPI extends BaseAPI { 7 | public async getContacts( 8 | request: loopring_defs.GetContactsRequest, 9 | apiKey: string, 10 | // url: string = loopring_defs.LOOPRING_URLs.GET_CONTACTS 11 | ) { 12 | const reqParams: loopring_defs.ReqParams = { 13 | url: loopring_defs.LOOPRING_URLs.GET_CONTACTS, 14 | queryParams: request, //request 15 | method: loopring_defs.ReqMethod.GET, 16 | sigFlag: loopring_defs.SIG_FLAG.NO_SIG, 17 | apiKey, 18 | } 19 | 20 | const raw_data = (await this.makeReq().request(reqParams)).data 21 | if (raw_data?.resultInfo && raw_data?.resultInfo.code) { 22 | return { 23 | ...raw_data.resultInfo, 24 | } 25 | } 26 | return { 27 | ...raw_data, 28 | raw_data, 29 | } as { 30 | raw_data: R 31 | } & R 32 | } 33 | 34 | public async createContact(request: loopring_defs.CreateContactRequest, apiKey: string) { 35 | const reqParams: loopring_defs.ReqParams = { 36 | url: loopring_defs.LOOPRING_URLs.CREATE_CONTACT, 37 | bodyParams: request, //request 38 | method: loopring_defs.ReqMethod.POST, 39 | sigFlag: loopring_defs.SIG_FLAG.NO_SIG, 40 | apiKey, 41 | } 42 | 43 | const raw_data = (await this.makeReq().request(reqParams)).data 44 | if (raw_data?.resultInfo && raw_data?.resultInfo.code) { 45 | return { 46 | ...raw_data.resultInfo, 47 | } 48 | } 49 | return { 50 | ...raw_data, 51 | raw_data, 52 | } 53 | } 54 | 55 | public async updateContact(request: loopring_defs.UpdateContactRequest, apiKey: string) { 56 | const reqParams: loopring_defs.ReqParams = { 57 | url: loopring_defs.LOOPRING_URLs.UPDATE_CONTACT, 58 | bodyParams: request, //request 59 | method: loopring_defs.ReqMethod.POST, 60 | sigFlag: loopring_defs.SIG_FLAG.NO_SIG, 61 | apiKey, 62 | } 63 | 64 | const raw_data = (await this.makeReq().request(reqParams)).data 65 | if (raw_data?.resultInfo && raw_data?.resultInfo.code) { 66 | return { 67 | ...raw_data.resultInfo, 68 | } 69 | } 70 | return { 71 | ...raw_data, 72 | raw_data, 73 | } 74 | } 75 | public async deleteContact( 76 | request: loopring_defs.DeleteContactRequest, 77 | apiKey: string, 78 | // url: string = loopring_defs.LOOPRING_URLs.GET_CONTACTS 79 | ) { 80 | const reqParams: loopring_defs.ReqParams = { 81 | url: loopring_defs.LOOPRING_URLs.DELETE_CONTACT, 82 | bodyParams: request, //request 83 | method: loopring_defs.ReqMethod.DELETE, 84 | sigFlag: loopring_defs.SIG_FLAG.NO_SIG, 85 | apiKey, 86 | } 87 | 88 | const raw_data = (await this.makeReq().request(reqParams)).data 89 | if (raw_data?.resultInfo && raw_data?.resultInfo.code) { 90 | return { 91 | ...raw_data.resultInfo, 92 | } 93 | } 94 | return { 95 | ...raw_data, 96 | raw_data, 97 | } 98 | } 99 | } 100 | 101 | // ContactAPI.get 102 | -------------------------------------------------------------------------------- /src/api/delegate_api.ts: -------------------------------------------------------------------------------- 1 | import { BaseAPI } from './base_api' 2 | 3 | import * as loopring_defs from '../defs' 4 | 5 | export class DelegateAPI extends BaseAPI { 6 | public async getCode(address: string): Promise { 7 | const reqParams: loopring_defs.ReqParams = { 8 | sigFlag: loopring_defs.SIG_FLAG.NO_SIG, 9 | url: loopring_defs.LOOPRING_URLs.GET_DELEGATE_GET_CODE, 10 | method: loopring_defs.ReqMethod.POST, 11 | bodyParams: { address }, 12 | } 13 | 14 | const raw_data = (await this.makeReq().request(reqParams)).data 15 | if (raw_data?.resultInfo) { 16 | return { 17 | ...raw_data?.resultInfo, 18 | } 19 | } 20 | return raw_data 21 | } 22 | 23 | public async getIPFS(path: string): Promise { 24 | const reqParams: loopring_defs.ReqParams = { 25 | sigFlag: loopring_defs.SIG_FLAG.NO_SIG, 26 | url: loopring_defs.LOOPRING_URLs.GET_DELEGATE_GET_IPFS, 27 | method: loopring_defs.ReqMethod.GET, 28 | queryParams: { path }, 29 | } 30 | 31 | const raw_data = (await this.makeReq().request(reqParams)).data 32 | if (raw_data?.resultInfo && raw_data?.resultInfo.code) { 33 | return { 34 | ...raw_data?.resultInfo, 35 | } 36 | } 37 | return raw_data 38 | } 39 | 40 | public getCollectionDomain() { 41 | return this.chainId === loopring_defs.ChainId.GOERLI 42 | ? 'https://uatnftinfos.loopring.io' 43 | : 'https://nftinfos.loopring.io' 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/api/ethereum/contracts/AbiFunction.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | // @ts-nocheck 3 | import { addHexPrefix, clearHexPrefix, toBuffer, toHex } from '../../../utils/formatter' 4 | import { methodID, rawDecode, rawEncode } from 'ethereumjs-abi' 5 | import BN from 'bn.js' 6 | 7 | export class AbiFunction { 8 | name 9 | inputTypes 10 | inputs 11 | outputTypes 12 | outputs 13 | constant 14 | methodAbiHash 15 | constructor({ inputs, name, outputs, constant }: any) { 16 | this.name = name 17 | this.inputTypes = inputs.map(({ type }) => type) 18 | this.inputs = inputs 19 | this.outputTypes = outputs.map(({ type }) => type) 20 | this.outputs = outputs 21 | this.constant = constant 22 | this.methodAbiHash = toHex(methodID(name, this.inputTypes)) 23 | } 24 | 25 | /** 26 | * @description Returns encoded methodId and inputs 27 | * @param inputs Object, examples {owner:'0x000...} 28 | * @returns {string} 29 | */ 30 | encodeInputs(inputs) { 31 | const abiInputs = this.parseInputs(inputs) 32 | return this.methodAbiHash + clearHexPrefix(toHex(rawEncode(this.inputTypes, abiInputs))) 33 | } 34 | 35 | /** 36 | * @description decode ethereum jsonrpc response result 37 | * @param outputs 38 | * @returns {*} 39 | */ 40 | decodeOutputs(outputs) { 41 | return this.parseOutputs(rawDecode(this.outputTypes, toBuffer(outputs))) 42 | } 43 | 44 | /** 45 | * @description decode encoded inputs 46 | * @param encoded 47 | * @returns {*} 48 | */ 49 | decodeEncodedInputs(encoded) { 50 | return this.parseOutputs(rawDecode(this.inputTypes, toBuffer(addHexPrefix(encoded)))) 51 | } 52 | 53 | parseInputs(inputs = {}) { 54 | return this.inputs.map(({ name, type }) => { 55 | if (inputs[name] === undefined) { 56 | throw new Error(`Parameter ${name} of type ${type} is required!`) 57 | } 58 | return inputs[name] 59 | }) 60 | } 61 | 62 | parseOutputs(outputs) { 63 | return outputs.map((output) => { 64 | if (output instanceof BN) { 65 | return toHex(output) 66 | } 67 | return output 68 | }) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/api/ethereum/contracts/Contract.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | // @ts-nocheck 3 | import { methodID } from 'ethereumjs-abi' 4 | import { toHex } from '../../../utils/formatter' 5 | import { AbiFunction } from './AbiFunction' 6 | 7 | export class Contract { 8 | abiFunctions 9 | constructor(abi) { 10 | const funAbi = abi.filter(({ type }) => type === 'function') 11 | this.abiFunctions = funAbi.reduce((acc, item) => { 12 | const inputTypes = item.inputs.map(({ type }) => type) 13 | const key = `${item.name}(${inputTypes.toString()})` 14 | const methodHash = methodID(item.name, inputTypes) 15 | return { 16 | ...acc, 17 | [item.name]: new AbiFunction(item), 18 | [key]: new AbiFunction(item), 19 | //@ts-ignore 20 | [methodHash]: new AbiFunction(item), 21 | } 22 | }, {}) 23 | } 24 | 25 | /** 26 | * @description Encodes inputs data according to ethereum abi 27 | * @param method string can be full method or just method name, examples: 'balanceOf' or balanceOf(address) 28 | * @param inputs array 29 | * @returns {*|string} 30 | */ 31 | encodeInputs(method, inputs) { 32 | const abiFunction = this.abiFunctions[method] 33 | if (abiFunction) { 34 | return abiFunction.encodeInputs(inputs) 35 | } else { 36 | throw new Error(`No ${method} method according to abi `) 37 | } 38 | } 39 | 40 | /** 41 | * @description Decodes outputs 42 | * @param method string can be full method or just method name, examples: 'balanceOf' or balanceOf(address) 43 | * @param outputs string 44 | * @returns {*} 45 | */ 46 | decodeOutputs(method, outputs) { 47 | const abiFunction = this.abiFunctions[method] 48 | if (abiFunction) { 49 | return abiFunction.decodeOutputs(outputs) 50 | } else { 51 | throw new Error(`No ${method} method according to abi `) 52 | } 53 | } 54 | 55 | /** 56 | * @description Decode encoded method and inputs 57 | * @param encode string | Buffer 58 | * @returns {*} 59 | */ 60 | decodeEncodeInputs(encode) { 61 | encode = toHex(encode) 62 | const methodId = encode.slice(0, 10) 63 | const abiFunction = this.abiFunctions[methodId] 64 | if (abiFunction) { 65 | return abiFunction.decodeEncodedInputs(encode.slice(10)) 66 | } else { 67 | throw new Error(`No corresponding method according to abi `) 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/api/ethereum/contracts/Contracts.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import { 3 | contractWalletAbi, 4 | erc20Abi, 5 | erc721Abi, 6 | erc1155Abi, 7 | exchange36Abi, 8 | hebao, 9 | } from '../../config/abis' 10 | import { Contract } from './Contract' 11 | 12 | const ERC20Token = new Contract(erc20Abi.erc20) 13 | const ExchangeContract = new Contract(exchange36Abi.exchange) 14 | const ContractWallet = new Contract(contractWalletAbi.contractWallet) 15 | const ERC1155 = new Contract(erc1155Abi.erc1155) 16 | const ERC721 = new Contract(erc721Abi.erc721) 17 | const HeBao = new Contract(hebao.hebao) 18 | 19 | export { 20 | ERC20Token, 21 | ERC1155, 22 | ERC721, 23 | ExchangeContract, 24 | ContractWallet, 25 | erc721Abi, 26 | erc1155Abi, 27 | HeBao, 28 | exchange36Abi 29 | } 30 | -------------------------------------------------------------------------------- /src/api/ethereum/contracts/index.ts: -------------------------------------------------------------------------------- 1 | import { AbiFunction } from './AbiFunction' 2 | import { Contract } from './Contract' 3 | import * as Contracts from './Contracts' 4 | const contracts = { Contracts } 5 | export { AbiFunction, Contract, contracts, Contracts } 6 | -------------------------------------------------------------------------------- /src/api/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ws_api' 2 | export * from './exchange_api' 3 | export * from './ammpool_api' 4 | export * from './user_api' 5 | export * from './wallet_api' 6 | export * from './whitelisted_user_api' 7 | export * from './contract_api' 8 | export * from './sign/sign_tools' 9 | export * from './nft_api' 10 | export * from './global_api' 11 | export * from './delegate_api' 12 | export * from './base_api' 13 | export * from './defi_api' 14 | export * from './luckToken_api' 15 | export * from './contacts_api' 16 | export * from './vault_api' 17 | export * from './ethereum/contracts' 18 | export { signHebaoApproveWrap } from './config' 19 | export { RabbitWithdrawAPI } from './rabbitWithdraw_api' 20 | -------------------------------------------------------------------------------- /src/api/sign/poseidon/EDDSAUtil.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber } from "ethers"; 2 | import { SignatureScheme } from "./eddsa"; 3 | import { FQ } from "./field"; 4 | import { jubjub } from "./jubjub"; 5 | import { babyJub } from "./babyJub"; 6 | 7 | export class EDDSAUtil { 8 | 9 | static sign(PrivateKey: string | undefined, hash: any) { 10 | const strKey = BigNumber.from(PrivateKey) 11 | const msg = BigNumber.from(hash) 12 | 13 | // console.log("strKey", strKey.toString()) 14 | // console.log("msg", msg.toString()) 15 | const copyKey = new FQ(strKey) 16 | const B = SignatureScheme.B() 17 | const signed = SignatureScheme.sign(msg, copyKey, B) 18 | // console.log("signed", signed.toStr()) 19 | const x = EDDSAUtil.formatted(signed.sig.R.x.n.toHexString().slice(2)) 20 | const y = EDDSAUtil.formatted(signed.sig.R.y.n.toHexString().slice(2)) 21 | const s = EDDSAUtil.formatted(signed.sig.s.n.toHexString().slice(2)) 22 | const result = `0x${x}${y}${s}` 23 | // console.log("result", result) 24 | return { 25 | "Rx": signed.sig.R.x.n.toString(), 26 | "Ry": signed.sig.R.y.n.toString(), 27 | "s": signed.sig.s.n.toString() 28 | } 29 | } 30 | 31 | static formatted(hexString: string) { 32 | const outputLength = 32 * 2 33 | const more = outputLength - hexString.length 34 | if (more > 0) { 35 | for (let i = 0; i < more; i++) { 36 | hexString = "0" + (hexString) 37 | } 38 | } else { 39 | hexString = hexString.slice(0, outputLength) 40 | } 41 | return hexString 42 | } 43 | 44 | static generateKeyPair(seed: any) { 45 | let bigInt = BigNumber.from(0) 46 | for (let i = 0; i < seed.length; i++) { 47 | const item = seed[i] 48 | const itemBigInt = BigNumber.from(item) 49 | const tmp = BigNumber.from("256").pow(BigNumber.from(i)) 50 | bigInt = bigInt.add(itemBigInt.mul(tmp)) 51 | } 52 | // console.log("sum", bigInt.toString()) 53 | const secretKey = bigInt.mod(jubjub.JUBJUB_L) 54 | // console.log("secretKey", secretKey.toString()) 55 | 56 | const copySecretKey = BigNumber.from(secretKey.toString()) 57 | // console.log("copySecretKey", copySecretKey.toString()) 58 | 59 | const B = SignatureScheme.B() 60 | // console.log("B", B.toString()) 61 | 62 | const publicKey = B.mul(copySecretKey) 63 | // console.log("publicKey", publicKey.x.n.toString(), publicKey.y.n.toString()) 64 | 65 | const keyPair = { 66 | "publicKeyX": publicKey.x.n.toString(), 67 | "publicKeyY": publicKey.y.n.toString(), 68 | "secretKey": secretKey.toString() 69 | } 70 | 71 | return keyPair 72 | } 73 | 74 | static pack(publicKeyX: string, publicKeyY: string) { 75 | const P0 = BigNumber.from(publicKeyX) 76 | const P1 = BigNumber.from(publicKeyY) 77 | const newPack = babyJub.packPoint(P0, P1) 78 | return newPack 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/api/sign/poseidon/TestsEDDSAUtil_test.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber } from "ethers"; 2 | import { EDDSAUtil } from "./EDDSAUtil"; 3 | import { bnToBuf, bnToBufWithFixedLength, SignatureScheme } from "./eddsa"; 4 | import { assert } from "console"; 5 | 6 | function testEddsaPack_1() { 7 | console.log("testEddsaPack") 8 | 9 | // Input 10 | const publicKeyX = "0x10440b6de1fc92536e20501e7513b5ca78d4c8c876450d97cfc2a4e24a4c67c7" 11 | const publicKeyY = "0x10dfbb7cd80bde2eeedbf9e0fad12819ca20be36b96a7f28c37c6a7550ed366c" 12 | 13 | // Output 14 | const eddsaPackOutput = "10dfbb7cd80bde2eeedbf9e0fad12819ca20be36b96a7f28c37c6a7550ed366c" 15 | 16 | const packed = EDDSAUtil.pack(publicKeyX, publicKeyY) 17 | assert(packed === eddsaPackOutput) 18 | console.log("testEddsaPack passed") 19 | } 20 | 21 | function testEddsaPack_2() { 22 | console.log("testEddsaPack") 23 | 24 | // Input 25 | const publicKeyX = "0x191f8455196d7c9116065b69a745edbe3f5b6193125f48d818e16101b0ebd13f" 26 | const publicKeyY = "0x0729569e74800ba4344767d608ec54f12b14cc4404a8726b5f73ebf8b58f9a09" 27 | 28 | // Output 29 | const eddsaPackOutput = "8729569e74800ba4344767d608ec54f12b14cc4404a8726b5f73ebf8b58f9a09" 30 | 31 | const packed = EDDSAUtil.pack(publicKeyX, publicKeyY) 32 | assert(packed === eddsaPackOutput) 33 | console.log("testEddsaPack passed") 34 | } 35 | 36 | function testEddsaPack_3() { 37 | console.log("testEddsaPack") 38 | 39 | // Input 40 | const publicKeyX = "0x1ae187c43a6b534be1ac60b335d5cc8c12a9d479339e5ce4134315e20c2940c4" 41 | const publicKeyY = "0x16fb785193a8657feb41b7944afde61fe05ea519621fa0f19d872a8fbba83463" 42 | 43 | // Output 44 | const eddsaPackOutput = "96fb785193a8657feb41b7944afde61fe05ea519621fa0f19d872a8fbba83463" 45 | 46 | const packed = EDDSAUtil.pack(publicKeyX, publicKeyY) 47 | assert(packed === eddsaPackOutput) 48 | console.log("testEddsaPack passed") 49 | } 50 | 51 | function testEddsaSign() { 52 | console.log("testEddsaSign") 53 | const strKey = "1965533437444427599736796973543479035828634172708055838572430750620147597402" 54 | const msg = "20823375595941673465102915960468301465677704522962441935281926279865178787657" 55 | const result = EDDSAUtil.sign(strKey, msg) 56 | // assert(result == "0x04ad08469a4a8622a661a793615ebddfa6ea2b72c8f1b02e33288ea2bd71cede0ed7f67939097ab95d3c9d8647e198f4ef523bf6cfb8da0ead89a57e27eff0d12ea6ac32cc118b1bc0aeb8f1be37f317f399197f9e41c8a90ecfe9e296be42e5") 57 | console.log(result.Rx) 58 | console.log(result.Ry) 59 | console.log(result.s) 60 | 61 | assert(result.Rx === "2114973053955517366033592592501464590076342821657201629830614924692550700766") 62 | assert(result.Ry === "6713953096854639492359183468711112854151280690992619923536842965423886430417") 63 | assert(result.s === "21100876117443371431735908718802018647851328087147897184613053393129281831653") 64 | 65 | console.log("testEddsaSign passed") 66 | } 67 | 68 | function test_generateKeyPair() { 69 | console.log("generateKeyPair") 70 | const seedHex = "0x" + "7f16a4c491d3494c3bc8ef097e7c123a9da6fa8167631efd5f82b89e803b0682" 71 | const seed = BigNumber.from(seedHex) 72 | console.log(`seed ${seed.toString()}`) 73 | const bitIntDataItems = bnToBufWithFixedLength(seed.toString(), 32); 74 | console.log(`bigIntData ${bitIntDataItems}`) 75 | 76 | const keyPair = EDDSAUtil.generateKeyPair(bitIntDataItems) 77 | 78 | assert(keyPair.publicKeyX === "18584920749226215196041463810216086509508234553287520526360090588893385486657") 79 | assert(keyPair.publicKeyY === "4521439321743413283487130903749053907482128013050103604539374548984130428531") 80 | 81 | console.log("generateKeyPair passed") 82 | } 83 | 84 | function main() { 85 | console.log("\n\TestsEDDSAUtil_test\n") 86 | // testEddsaPack_1() 87 | // testEddsaPack_2() 88 | // testEddsaPack_3() 89 | test_generateKeyPair() 90 | // testEddsaSign() 91 | } 92 | 93 | main(); -------------------------------------------------------------------------------- /src/api/sign/poseidon/babyJub.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber } from "ethers"; 2 | import { SignatureScheme, bytesToHexString } from "./eddsa"; 3 | import { field } from "./field"; 4 | 5 | 6 | export class babyJub { 7 | 8 | static packPoint(P0: BigNumber, P1: BigNumber) { 9 | const packed = SignatureScheme.to_bytes(P1).reverse() 10 | // console.log("packed", packed) 11 | if (babyJub.lt(P0, BigNumber.from("0"))) { 12 | // console.log("Update .... lt ") 13 | packed[0] = packed[0] | 0x80 14 | } 15 | const hexStr = bytesToHexString(packed) 16 | // console.log("hexStr", hexStr) 17 | return hexStr 18 | } 19 | 20 | static lt(a: BigNumber, b: BigNumber) { 21 | const half = field.SNARK_SCALAR_FIELD.div(BigNumber.from("2")) 22 | const p = field.SNARK_SCALAR_FIELD 23 | let aa: BigNumber 24 | let bb: BigNumber 25 | if (a.gt(half)) { 26 | aa = a.sub(p) 27 | } else { 28 | aa = a 29 | } 30 | if (b.gt(half)) { 31 | bb = b.sub(p) 32 | } else { 33 | bb = b 34 | } 35 | // console.log("lt", a.toString(), b.toString(), aa.toString(), bb.toString()); 36 | return aa.lt(bb) 37 | } 38 | 39 | static gt(a: BigNumber, b: BigNumber) { 40 | const half = field.SNARK_SCALAR_FIELD.div(BigNumber.from("2")) 41 | const p = field.SNARK_SCALAR_FIELD 42 | let aa: BigNumber 43 | let bb: BigNumber 44 | if (a.gt(half)) { 45 | aa = a.sub(p) 46 | } else { 47 | aa = a 48 | } 49 | if (b.gt(half)) { 50 | bb = b.sub(p) 51 | } else { 52 | bb = b 53 | } 54 | // console.log("gt", a.toString(), b.toString(), aa.toString(), bb.toString()); 55 | return aa.gt(bb) 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/api/sign/poseidon/eddsa_test.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "console" 2 | import { BigNumber } from "ethers" 3 | import { SignatureScheme } from "./eddsa" 4 | import { FQ } from "./field" 5 | import { Point } from "./jubjub" 6 | 7 | function test_sign_1() { 8 | // console.log("test_sign_1") 9 | const startTime: any = new Date(); 10 | const msgHash = BigNumber.from("20693456676802104653139582814194312788878632719314804297029697306071204881418") 11 | const private_key = new FQ(BigNumber.from("1")) 12 | const signed = SignatureScheme.sign(msgHash, private_key, SignatureScheme.B()) 13 | assert(signed.toStr() === "16540640123574156134436876038791482806971768689494387082833631921987005038935 20819045374670962167435360035096875258406992893633759881276124905556507972311 4991609103248925747358645194965349262579784734809679007552644294476920671344 423391641476660815714427268720766993055332927752794962916609674122318189741 4678160339597842896640121413028167917237396460457527040724180632868306529961 20693456676802104653139582814194312788878632719314804297029697306071204881418") 14 | const endTime: any = new Date(); 15 | let timeDiff = endTime - startTime; //in ms 16 | timeDiff /= 1000; 17 | // console.log(timeDiff + " seconds"); 18 | // console.log("test_sign_1 passed") 19 | } 20 | 21 | function test_prehash_message_1() { 22 | // console.log("test_prehash_message_1") 23 | const msg = BigNumber.from("20693456676802104653139582814194312788878632719314804297029697306071204881418") 24 | const result = SignatureScheme.prehash_message(msg) 25 | assert(result.eq(BigNumber.from("20693456676802104653139582814194312788878632719314804297029697306071204881418"))) 26 | // console.log("test_prehash_message_1 passed") 27 | } 28 | 29 | function test_to_bytes_1() { 30 | // console.log("test_to_bytes_1") 31 | const arg = BigNumber.from("20693456676802104653139582814194312788878632719314804297029697306071204881418") 32 | const resutls = SignatureScheme.to_bytes(arg) 33 | assert(JSON.stringify(resutls) === JSON.stringify([10, 228, 215, 147, 146, 102, 9, 42, 66, 160, 26, 94, 171, 73, 235, 194, 245, 106, 249, 114, 50, 52, 155, 182, 188, 18, 133, 216, 215, 20, 192, 45])) 34 | // console.log("test_to_bytes_1 passed") 35 | } 36 | 37 | function test_hash_secret_1() { 38 | // console.log("test_hash_secret_1") 39 | const startTime: any = new Date(); 40 | const arg = BigNumber.from("20693456676802104653139582814194312788878632719314804297029697306071204881418") 41 | const result = SignatureScheme.hash_secret_python(new FQ(BigNumber.from("1")), arg) 42 | assert(result.eq(BigNumber.from("456425617452149303537516185998917840598824274191970480768523181450944242406"))) 43 | const endTime: any = new Date(); 44 | let timeDiff = endTime - startTime; //in ms 45 | timeDiff /= 1000; 46 | // console.log(timeDiff + " seconds"); 47 | // strip the ms 48 | // console.log("test_hash_secret_1 passed") 49 | } 50 | 51 | function test_hash_public_1() { 52 | // console.log("test_hash_public_1") 53 | const R = new Point(new FQ(BigNumber.from("4991609103248925747358645194965349262579784734809679007552644294476920671344")), new FQ(BigNumber.from("423391641476660815714427268720766993055332927752794962916609674122318189741"))) 54 | const A = new Point(new FQ(BigNumber.from("16540640123574156134436876038791482806971768689494387082833631921987005038935")), new FQ(BigNumber.from("20819045374670962167435360035096875258406992893633759881276124905556507972311"))) 55 | const M = BigNumber.from("20693456676802104653139582814194312788878632719314804297029697306071204881418") 56 | const result = SignatureScheme.hash_public(R, A, M) 57 | assert(result.eq(BigNumber.from("4221734722145693593102605227029250076638572186265556559955657451417362287555"))) 58 | // console.log("test_hash_public_1 passed") 59 | } 60 | 61 | function main() { 62 | // console.log("\n\neddsa_test\n") 63 | test_sign_1() 64 | test_prehash_message_1() 65 | test_to_bytes_1() 66 | test_hash_secret_1() 67 | test_hash_public_1() 68 | } 69 | 70 | main(); 71 | -------------------------------------------------------------------------------- /src/api/sign/poseidon/field.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber } from "ethers"; 2 | import { BigInteger } from "jsbn"; 3 | 4 | export class field { 5 | // Fq is the base field of Jubjub 6 | static SNARK_SCALAR_FIELD = BigNumber.from("21888242871839275222246405745257275088548364400416034343698204186575808495617") 7 | 8 | // Fr is the scalar field of Jubjub 9 | static FR_ORDER = BigNumber.from("21888242871839275222246405745257275088614511777268538073601725287587578984328") 10 | } 11 | 12 | // A class for field elements in FQ. Wrap a number in this class, 13 | // and it becomes a field element. 14 | export class FQ { 15 | public m: BigNumber; 16 | public n: BigNumber; 17 | 18 | constructor(n: BigNumber, field_modulus = field.SNARK_SCALAR_FIELD) { 19 | this.m = field_modulus; 20 | this.n = n.mod(this.m); 21 | } 22 | 23 | // 24 | // Use this.n as other 25 | // 26 | 27 | add(other: BigNumber) { 28 | const on = other 29 | const n = (this.n.add(on)).mod(this.m) 30 | return new FQ(n, this.m) 31 | } 32 | 33 | mul(other: BigNumber) { 34 | const on = other 35 | const n = this.n.mul(on).mod(this.m) 36 | return new FQ(n, this.m) 37 | } 38 | 39 | sub(other: BigNumber) { 40 | const on = other 41 | let new_n: BigNumber; 42 | if (this.n.gte(on)) { 43 | new_n = (this.n.sub(on)).mod(this.m) 44 | } else { 45 | new_n = (this.n.sub(on).add(this.m)).mod(this.m) 46 | } 47 | return new FQ(new_n, this.m) 48 | } 49 | 50 | div(other: BigNumber) { 51 | const on_c = other 52 | const m_c = this.m 53 | const two_c = BigNumber.from("2") 54 | const on_power_c = modulo(on_c, m_c.sub(two_c), m_c) 55 | const n_on_power_remainder = this.n.mul(on_power_c).mod(this.m) 56 | 57 | return new FQ(n_on_power_remainder, this.m) 58 | } 59 | 60 | static one(modulus: BigNumber = field.SNARK_SCALAR_FIELD) { 61 | return new FQ(BigNumber.from("1"), modulus) 62 | } 63 | 64 | static zero(modulus: BigNumber = field.SNARK_SCALAR_FIELD) { 65 | return new FQ(BigNumber.from("0"), modulus) 66 | } 67 | 68 | } 69 | 70 | export function modulo(n: BigNumber, p: BigNumber, m: BigNumber) { 71 | const n_ = new BigInteger(n.toString()) 72 | const p_ = new BigInteger(p.toString()) 73 | const m_ = new BigInteger(m.toString()) 74 | 75 | // console.log("modulo", n_.toString(), p_.toString(), m_.toString()); 76 | const result = n_.modPow(p_, m_) 77 | // console.log(n_.toString(), p_.toString(), m_.toString(), result.toString()) 78 | return BigNumber.from(result.toString()) 79 | } -------------------------------------------------------------------------------- /src/api/sign/poseidon/jubjub.ts: -------------------------------------------------------------------------------- 1 | /* 2 | This module implements the extended twisted edwards and extended affine coordinates 3 | described in the paper "Twisted Edwards Curves Revisited": 4 | 5 | - https://iacr.org/archive/asiacrypt2008/53500329/53500329.pdf 6 | Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson 7 | 8 | Information Security Institute, 9 | Queensland University of Technology, QLD, 4000, Australia 10 | {h.hisil, kk.wong, g.carter, e.dawson}@qut.edu.au 11 | 12 | By using the extended coordinate system we can avoid expensive modular exponentiation 13 | calls, for example - a scalar multiplication call (or multiple...) may perform only 14 | one 3d->2d projection at the point where affine coordinates are necessary, and every 15 | intermediate uses a much faster form. 16 | 17 | # XXX: none of these functions are constant time, they should not be used interactively! 18 | */ 19 | import { BigNumber } from "ethers"; 20 | import { field, FQ } from "./field"; 21 | 22 | export class jubjub { 23 | static JUBJUB_Q = field.SNARK_SCALAR_FIELD 24 | static JUBJUB_E = BigNumber.from("21888242871839275222246405745257275088614511777268538073601725287587578984328") 25 | static JUBJUB_C = BigNumber.from("8") // Cofactor 26 | 27 | static JUBJUB_L = jubjub.JUBJUB_E.div(jubjub.JUBJUB_C) // L*B = 0, and (2^C)*L == #E 28 | static JUBJUB_A = BigNumber.from("168700") // Coefficient A 29 | static JUBJUB_D = BigNumber.from("168696") // Coefficient D 30 | } 31 | 32 | export class Point { 33 | public x: FQ 34 | public y: FQ 35 | 36 | constructor(x: FQ, y: FQ) { 37 | this.x = x 38 | this.y = y 39 | } 40 | 41 | static generate() { 42 | const xBigInt = BigNumber.from("16540640123574156134436876038791482806971768689494387082833631921987005038935") 43 | const yBigInt = BigNumber.from("20819045374670962167435360035096875258406992893633759881276124905556507972311") 44 | const point = new Point(new FQ(xBigInt), new FQ(yBigInt)) 45 | return point 46 | } 47 | 48 | mul(scaler: BigNumber) { 49 | let p = new Point(this.x, this.y) 50 | let a = Point.infinity() 51 | let i = 0 52 | 53 | while (!scaler.eq(BigNumber.from("0"))) { 54 | const bitwiseAnd = scaler.and(BigNumber.from("1")) 55 | if (!bitwiseAnd.eq(BigNumber.from("0"))) { 56 | a = a.add(p) 57 | } 58 | let copyP1 = new Point(p.x, p.y) 59 | let copyP2 = new Point(p.x, p.y) 60 | p = copyP1.add(copyP2) 61 | scaler = scaler.div(BigNumber.from("2")) 62 | // console.log(i + " scaler", scaler.toString()) 63 | i = i + 1 64 | } 65 | return a 66 | } 67 | 68 | add(other: Point) { 69 | if (this.x.n.eq(BigNumber.from("0")) && this.y.n.eq(BigNumber.from("0"))) { 70 | return other 71 | } 72 | const u1 = this.x 73 | const v1 = this.y 74 | const u2 = other.x 75 | const v2 = other.y 76 | 77 | const u3_tmp0 = (u1.mul(v2.n)).add(v1.mul(u2.n).n) 78 | const u3_tmp1 = u1.mul(u2.n).mul(v1.n).mul(v2.n).mul(jubjub.JUBJUB_D) 79 | const u3_tmp2 = FQ.one().add(u3_tmp1.n) 80 | 81 | const u3 = u3_tmp0.div(u3_tmp2.n) 82 | 83 | const v3_tmp0 = v1.mul(v2.n) 84 | const v3_tmp1 = u1.mul(u2.n).mul(jubjub.JUBJUB_A) 85 | const v3_tmp3 = v3_tmp0.sub(v3_tmp1.n) 86 | const v3_tmp5 = FQ.one().sub(u3_tmp1.n) 87 | 88 | const v3 = v3_tmp3.div(v3_tmp5.n) 89 | 90 | return new Point(u3, v3) 91 | } 92 | 93 | static infinity() { 94 | return new Point(new FQ(BigNumber.from("0")), new FQ(BigNumber.from("1"))) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/api/whitelisted_user_api.ts: -------------------------------------------------------------------------------- 1 | import { BaseAPI } from './base_api' 2 | 3 | import * as loopring_defs from '../defs' 4 | 5 | import * as sign_tools from './sign/sign_tools' 6 | 7 | export class WhitelistedUserAPI extends BaseAPI { 8 | /* 9 | * Submit offchain withdraw request 10 | * not supported for now. 11 | */ 12 | private async submitOffchainWithdraw( 13 | request: loopring_defs.OffChainWithdrawalRequestV3, 14 | eddsaKey: string, 15 | apiKey: string, 16 | ) { 17 | request.eddsaSignature = sign_tools.get_EddsaSig_OffChainWithdraw(request, eddsaKey).result 18 | 19 | const reqParams: loopring_defs.ReqParams = { 20 | url: loopring_defs.LOOPRING_URLs.WITHDRAWALS_ACTION, 21 | bodyParams: request, 22 | apiKey, 23 | method: loopring_defs.ReqMethod.POST, 24 | sigFlag: loopring_defs.SIG_FLAG.NO_SIG, 25 | } 26 | 27 | const raw_data = (await this.makeReq().request(reqParams)).data 28 | if (raw_data?.resultInfo && raw_data?.resultInfo.code) { 29 | return { 30 | ...raw_data?.resultInfo, 31 | } 32 | } 33 | return { 34 | raw_data, 35 | } 36 | } 37 | 38 | /* 39 | * Submit offchain withdraw request 40 | */ 41 | public async submitInternalTransfer( 42 | request: loopring_defs.OriginTransferRequestV3, 43 | eddsaKey: string, 44 | apiKey: string, 45 | ) { 46 | request.eddsaSignature = sign_tools.get_EddsaSig_Transfer(request, eddsaKey).result 47 | 48 | const reqParams: loopring_defs.ReqParams = { 49 | url: loopring_defs.LOOPRING_URLs.POST_INTERNAL_TRANSFER, 50 | bodyParams: request, 51 | apiKey, 52 | method: loopring_defs.ReqMethod.POST, 53 | sigFlag: loopring_defs.SIG_FLAG.NO_SIG, 54 | } 55 | 56 | const raw_data = (await this.makeReq().request(reqParams)).data 57 | if (raw_data?.resultInfo && raw_data?.resultInfo.code) { 58 | return { 59 | ...raw_data?.resultInfo, 60 | } 61 | } 62 | return { 63 | raw_data, 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/api/ws_api.ts: -------------------------------------------------------------------------------- 1 | import { BaseAPI } from './base_api' 2 | 3 | import * as loopring_defs from '../defs' 4 | 5 | export class WsAPI extends BaseAPI { 6 | /* 7 | * Get wsApiKey by access REST path "/v3/ws/key" 8 | */ 9 | public async getWsKey() { 10 | const reqParams: loopring_defs.ReqParams = { 11 | url: loopring_defs.LOOPRING_URLs.GET_WS_KEY, 12 | method: loopring_defs.ReqMethod.GET, 13 | sigFlag: loopring_defs.SIG_FLAG.NO_SIG, 14 | } 15 | 16 | const raw_data = (await this.makeReq().request(reqParams)).data 17 | if (raw_data?.resultInfo) { 18 | return { 19 | ...raw_data?.resultInfo, 20 | } 21 | } 22 | const wsKey = raw_data.key 23 | return { 24 | wsKey, 25 | raw_data, 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/defs/account_defs.ts: -------------------------------------------------------------------------------- 1 | import { PublicKey } from './loopring_enums' 2 | 3 | /** 4 | * AccountInfo 5 | * @property accountId number Account ID 6 | * @property owner string Ethereum address 7 | * @property frozen boolean The frozen state of the account, true stands for frozen, if the account is frozen, the user cant submit order. 8 | * @property publicKey PublicKey The user's public key 9 | * @property tags? string Comma separated list of tags such as VIP levels, etc 10 | * @property nonce number field.DexAccountV3.nonce 11 | * @property keyNonce number Nonce of users key change request, for backward compatible 12 | * @property keySeed string KeySeed of users L2 eddsaKey, the L2 key should be generated from this seed, i.e., L2_EDDSA_KEY=eth.sign(keySeed). Otherwise, user may meet error in login loopring DEX 13 | */ 14 | export interface AccountInfo { 15 | accountId: number 16 | owner: string 17 | frozen: boolean 18 | publicKey: PublicKey 19 | tags?: string 20 | nonce: number 21 | keyNonce: number 22 | keySeed: string 23 | } 24 | 25 | /** 26 | * 27 | */ 28 | export interface CounterFactualInfo { 29 | accountId: number 30 | owner: string 31 | walletFactory: string 32 | walletSalt: string 33 | walletOwner: string 34 | } 35 | 36 | export interface NFTCounterFactualInfo { 37 | nftFactory: string 38 | nftOwner: string 39 | nftBaseUri: string 40 | } 41 | -------------------------------------------------------------------------------- /src/defs/error_codes.ts: -------------------------------------------------------------------------------- 1 | import { AxiosResponse } from "axios"; 2 | 3 | export enum LoopringErrorCode { 4 | Unknown_Error = 100000, 5 | Invalid_Args = 100001, 6 | 7 | Address_Not_Found = 101001, 8 | User_Not_Found = 101002, 9 | 10 | ExchangeId_Incorrect = 102001, 11 | Unsupported_TokenId = 102002, 12 | Invalid_AccountId = 102003, //dup 13 | Invalid_OrderId = 102004, 14 | Market_Not_Supported = 102005, //dup 15 | Illegal_Rate = 102006, 16 | Order_Already_Existed = 102007, 17 | Order_Already_Expired = 102008, 18 | Order_Missing_Sig = 102010, 19 | Invalid_User_Balance = 102011, 20 | Order_Amount_Too_Small = 102012, 21 | Failed_To_Freeze_Amt = 102014, 22 | Exceed_Max_Order_Amt = 102020, 23 | Invalid_Nonce = 102021, 24 | Invalid_Transfer_Sender = 102022, 25 | Invalid_Transfer_Receiver = 102023, 26 | Unsuported_Fee_Token = 102024, 27 | Transfer_Token_Is_Not_Consistent_With_Fee_Token = 102025, 28 | 29 | Sumbit_Order_Failed = 102027, 30 | No_Order_To_Cancel = 102117, 31 | Fail_To_Cancel_Order = 102118, 32 | Order_Is_Not_Valid = 102120, 33 | 34 | Empty_Apikey = 104001, 35 | Invalid_Apikey = 104002, 36 | Invalid_AccountID = 104003, //dup 37 | No_Sig_Provided = 104004, 38 | Wrong_Sig = 104005, 39 | 40 | User_Cannot_Be_Empty = 107001, 41 | Orderhash_Cannot_Be_Empty = 107002, 42 | Order_Not_Exist = 107003, 43 | 44 | Unsupported_Market = 108000, //dup 45 | Unsupported_Depth_Level = 108001, 46 | SKD_UNKNOW = 500000, 47 | CONTRACTNFT_URI = 500001, 48 | CONTRACTNFT_BALANCE = 500002, 49 | CONTRACTNFT_IS_APPROVE = 500003, 50 | CONTRACTNFT_SET_APPROVE = 500004, 51 | NOT_SUPPORT_ERROR = 500005, 52 | USER_DENIED = 500006, 53 | USER_DENIED_2 = 500007, 54 | NO_EDDSA_KEY = 500008, 55 | HTTP_ERROR = 500009, 56 | BTRADE_NO_DEPTH_ERROR = 500010, 57 | BTRADE_NO_PRODUCT = 500011, 58 | } 59 | 60 | export enum ConnectorError { 61 | NOT_SUPPORT_ERROR = "Not supported on this device", 62 | USER_DENIED = "User denied message signature", 63 | USER_DENIED_2 = "personalSign err before Validate", 64 | CONTRACTNFT_URI = "contract nft uri Error", 65 | CONTRACTNFT_BALANCE = "contract nft balance error", 66 | CONTRACTNFT_IS_APPROVE = "ContractNFT is Approve error", 67 | CONTRACTNFT_SET_APPROVE = "ContractNFT set Approve error", 68 | NO_EDDSA_KEY = "No EDDSA KEY", 69 | HTTP_ERROR = "HTTP Request Failed!", 70 | BTRADE_NO_DEPTH_ERROR = "NO Depth for BTRADE", 71 | BTRADE_NO_PRODUCT = "NO Market for BTRADE", 72 | } 73 | 74 | export interface RESULT_INFO { 75 | code?: number; 76 | msg?: string; 77 | message?: string; 78 | } 79 | export type ERROR_INFO = { 80 | resultInfo: RESULT_INFO; 81 | }; 82 | 83 | export const checkErrorInfo = ( 84 | errorInfo: RESULT_INFO, 85 | isFirstTime?: boolean 86 | ) => { 87 | const message = errorInfo.message; 88 | if (isFirstTime && message === "NOT_SUPPORT_ERROR") { 89 | return ConnectorError.NOT_SUPPORT_ERROR; 90 | } else if (message === "USER_DENIED" || message === "USER_DENIED_2") { 91 | return ConnectorError.USER_DENIED; 92 | } else if ( 93 | message && 94 | (message.startsWith("personalSign last") || 95 | message.indexOf("User denied transaction") > 0) 96 | ) { 97 | return ConnectorError.USER_DENIED; 98 | } 99 | return message; 100 | }; 101 | -------------------------------------------------------------------------------- /src/defs/index.ts: -------------------------------------------------------------------------------- 1 | import { getNavigatorSafely, getWindowSafely } from 'utils/window_utils' 2 | 3 | export * from './loopring_enums' 4 | export * from './url_defs' 5 | export * from './account_defs' 6 | export * from './web3_defs' 7 | export * from './ws_defs' 8 | export * from './loopring_constants' 9 | export * from './loopring_defs' 10 | export * from './error_codes' 11 | export * from './nft_defs' 12 | 13 | export const IsMobile = { 14 | Android: function () { 15 | return getNavigatorSafely()?.userAgent.match(/Android/i) 16 | }, 17 | BlackBerry: function () { 18 | return getNavigatorSafely()?.userAgent.match(/BlackBerry/i) 19 | }, 20 | iOS: function () { 21 | return getNavigatorSafely()?.userAgent.match(/iPhone|iPad|iPod/i) 22 | }, 23 | Opera: function () { 24 | return getNavigatorSafely()?.userAgent.match(/Opera Mini/i) 25 | }, 26 | Windows: function () { 27 | return getNavigatorSafely()?.userAgent.match(/IEMobile/i) || getNavigatorSafely()?.userAgent.match(/WPDesktop/i) 28 | }, 29 | Ethereum: function () { 30 | return getWindowSafely()?.ethereum && getWindowSafely()?.ethereum.isImToken 31 | }, 32 | 33 | any: function () { 34 | if (typeof global.navigator === 'undefined' || typeof navigator === 'undefined') { 35 | console.log('IsMobile any navigator is undefined') 36 | return false 37 | } 38 | return ( 39 | IsMobile.Android() || 40 | IsMobile.BlackBerry() || 41 | IsMobile.iOS() || 42 | IsMobile.Opera() || 43 | IsMobile.Windows() || 44 | IsMobile.Ethereum() 45 | ) 46 | }, 47 | } 48 | 49 | type Ethereum = any 50 | declare global { 51 | interface Window { 52 | ethereum?: Ethereum & { [key: string]: boolean; isLoopring: boolean } 53 | 54 | // socketEventMap: {[key:string]:any 55 | // imageConfig:{[key:string]:any}|undefined 56 | } 57 | interface Global { 58 | ethereum?: Ethereum & { [key: string]: boolean; isLoopring: boolean } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/defs/loopring_constants.ts: -------------------------------------------------------------------------------- 1 | export enum HEBAO_LOCK_STATUS { 2 | LOCK_FAILED = 'LOCK_FAILED', 3 | CREATED = 'CREATED', 4 | LOCK_WAITING = 'LOCK_WAITING', 5 | UNLOCK_FAILED = 'UNLOCK_FAILED', 6 | LOCKED = 'LOCKED', 7 | UNLOCK_WAITING = 'UNLOCK_WAITING', 8 | } 9 | 10 | export enum HEBAO_META_TYPE { 11 | recovery = 16, 12 | transfer = 18, 13 | // add_guardian = 34, 14 | approve_token = 23, 15 | remove_guardian = 35, 16 | unlock_wallet = 37, 17 | upgrade_contract = 201, 18 | deposit_wallet = 202, 19 | } 20 | 21 | export const SoursURL = 'https://static.loopring.io/assets/' 22 | -------------------------------------------------------------------------------- /src/defs/nft_defs.ts: -------------------------------------------------------------------------------- 1 | import Web3 from "web3"; 2 | import { ChainId } from "./web3_defs"; 3 | import { NFT_TYPE_STRING, NFTType } from "../api"; 4 | 5 | /** 6 | * @interface DepositNFTParam 7 | * @description an NFTAction to the specified account. 8 | * @property web3 9 | * @property DepositParam 10 | * @property from The address that deposits the funds to the exchange 11 | * @property to The account owner's address receiving the funds 12 | * @property nftType The type of NFTAction contract address (ERC721/ERC1155/...) 13 | * @property tokenAddress The address of the token 14 | * @property nftId The token type 'id`. 15 | * @property amount The amount of tokens to deposit. 16 | * @property nonce: number, 17 | * @property gasPrice: number, 18 | * @property gasLimit: number, 19 | * @property extraData Optional extra data used by the deposit contract. 20 | * @property chainId 0|5 21 | * @property sendByMetaMask boolean 22 | */ 23 | export interface DepositNFTParam { 24 | web3: Web3; 25 | from: string; 26 | exchangeAddress: string; 27 | nftType?: NFTType; 28 | tokenAddress: string; 29 | nftId: string; 30 | amount: number; 31 | gasPrice: number; 32 | gasLimit: number | undefined; 33 | chainId?: ChainId; 34 | nonce: number; 35 | extraData?: any; 36 | sendByMetaMask?: boolean; 37 | } 38 | 39 | /** 40 | * isApprovedForAll 41 | * @property web3 42 | * @property from The address that deposits the funds to the exchange 43 | * @property exchangeAddress loopring exchange address 44 | * @property nftType NFTType 45 | * @property tokenAddress The address of NFTAction token 46 | */ 47 | export interface IsApproveParam { 48 | web3: Web3; 49 | from: string; 50 | exchangeAddress: string; 51 | nftType: NFTType; 52 | tokenAddress: string; 53 | } 54 | 55 | /** 56 | * approveNFT 57 | * @property web3 58 | * @property from string address that deposits the funds to the exchange 59 | * @property to string address deposits to 60 | * @property loopringAddress string loopring exchange Address 61 | * @property nftId ntId 62 | * @property chainId number 63 | * @property nftType number The type of NFTAction contract address (ERC721/ERC1155) 64 | * @property nonce number 65 | * @property gasPrice 66 | * @property gasLimit 67 | * @property sendByMetaMask 68 | */ 69 | export interface ApproveParam { 70 | web3: Web3; 71 | from: string; 72 | depositAddress: string; 73 | tokenAddress: string; 74 | nftId?: string; 75 | nftType: NFTType; 76 | gasPrice: number; 77 | gasLimit: number | undefined; 78 | chainId: ChainId; 79 | nonce: number; 80 | approved?: boolean; 81 | sendByMetaMask?: boolean; 82 | } 83 | 84 | export type ContractNFTParam = { 85 | web3: any; 86 | tokenAddress: string; 87 | nftId: string; 88 | nftType?: NFTType; 89 | }; 90 | export type ContractNFTMetaParam = ContractNFTParam & { _id?: string }; 91 | 92 | export type UserNFTBalanceParam = ContractNFTParam & { account: string }; 93 | 94 | 95 | export type CallRefreshNFT = { 96 | network: "ETHEREUM", 97 | tokenAddress: string, 98 | nftId: string, 99 | nftType: NFT_TYPE_STRING 100 | }; 101 | 102 | -------------------------------------------------------------------------------- /src/defs/web3_defs.ts: -------------------------------------------------------------------------------- 1 | export enum ChainId { 2 | MAINNET = 1, 3 | GOERLI = 5, 4 | SEPOLIA = 11155111, 5 | TAIKO = 167000, 6 | TAIKOHEKLA = 167009, 7 | BASE = 8453, 8 | BASESEPOLIA = 84532, 9 | } 10 | 11 | export const NetworkContextName = 'NETWORK' 12 | 13 | export enum ConnectorNames { 14 | Unknown = 'Unknown', 15 | MetaMask = 'MetaMask', 16 | Network = 'Network', 17 | WalletConnect = 'WalletConnect', 18 | Gamestop = 'Gamestop', 19 | OtherExtension = 'OtherExtension', 20 | Coinbase = 'Coinbase', 21 | Ledger = 'Ledger', 22 | Trezor = 'Trezor', 23 | Authereum = 'Authereum', 24 | } 25 | 26 | export enum SigSuffix { 27 | Suffix02 = '02', 28 | Suffix03 = '03', 29 | } 30 | 31 | export const NFTFactory = { 32 | [ChainId.MAINNET]: '0xc852aC7aAe4b0f0a0Deb9e8A391ebA2047d80026', 33 | [ChainId.GOERLI]: '0x355E9941C5e301033ecfD37184E78443c5241035', 34 | [ChainId.SEPOLIA]: '0x8cC68c28c7E3d8Eeb1D74434164a1e91aCdA088D', 35 | [ChainId.TAIKOHEKLA]: '', 36 | [ChainId.TAIKO]: '', 37 | [ChainId.BASE]: '', 38 | [ChainId.BASESEPOLIA]: '', 39 | } 40 | 41 | export const NFTFactory_Collection = { 42 | [ChainId.MAINNET]: '0x97BE94250AEF1Df307749aFAeD27f9bc8aB911db', 43 | [ChainId.GOERLI]: '0x355E9941C5e301033ecfD37184E78443c5241035', 44 | [ChainId.SEPOLIA]: '0x8cC68c28c7E3d8Eeb1D74434164a1e91aCdA088D', 45 | [ChainId.BASE]: '', 46 | [ChainId.BASESEPOLIA]: '', 47 | } 48 | -------------------------------------------------------------------------------- /src/defs/ws_defs.ts: -------------------------------------------------------------------------------- 1 | import { OrderStatus, Side, NetworkWallet } from './' 2 | 3 | export interface WsProps { 4 | topics: any[] 5 | needApiKey: boolean 6 | apikey?: string 7 | } 8 | 9 | export enum WsOps { 10 | Sub = 'sub', 11 | Unsub = 'unSub', 12 | } 13 | 14 | export enum WsTopicType { 15 | account = 'account', 16 | order = 'order', 17 | trade = 'trade', 18 | mixtrade = 'mixtrade', 19 | ticker = 'ticker', 20 | candlestick = 'candlestick', 21 | ammpool = 'ammpool', 22 | orderbook = 'orderbook', 23 | mixorder = 'mixorder', 24 | btradedepth = 'btradedepth', 25 | crawlTokenPrices = 'crawltokenprices', 26 | notification = 'notification', 27 | vaultAccount = 'vaultAccount', 28 | l2Common = 'l2Common', 29 | } 30 | 31 | export const getCrawlTokenPrices = ({ 32 | topic = WsTopicType.crawlTokenPrices, 33 | currency = 'USD', 34 | }: { 35 | topic?: WsTopicType.crawlTokenPrices 36 | } & Omit<{ currency?: 'USD' }, 'topic'>) => { 37 | return { topic, currency } 38 | } 39 | 40 | export const getAccountArg = () => { 41 | return { 42 | topic: WsTopicType.account, 43 | } 44 | } 45 | 46 | export interface WsAccount { 47 | accountId: number 48 | totalAmount: string 49 | tokenId: number 50 | amountLocked: string 51 | } 52 | 53 | export const getOrderArg = (market: string) => { 54 | return { 55 | topic: WsTopicType.order, 56 | market, 57 | } 58 | } 59 | 60 | export interface WsOrder { 61 | hash: string 62 | clientOrderId: string 63 | size: string 64 | volume: string 65 | price: string 66 | filledSize: string 67 | filledVolume: string 68 | filledFee: string 69 | status: OrderStatus 70 | createdAt: string 71 | validSince: string 72 | validUntil: string 73 | side: Side 74 | market: string 75 | } 76 | 77 | export type OrderWsRequest = { 78 | topic?: WsTopicType.orderbook | WsTopicType.mixorder | WsTopicType.btradedepth 79 | market: string 80 | level: number 81 | count?: number 82 | snapshot?: boolean 83 | showOverlap?: boolean 84 | } 85 | export const getOrderBookArg = ({ 86 | topic = WsTopicType.orderbook, 87 | market, 88 | level, 89 | count, 90 | snapshot, 91 | showOverlap, 92 | }: OrderWsRequest) => { 93 | const obj: any = { 94 | topic, 95 | market, 96 | level, 97 | count, 98 | snapshot, 99 | showOverlap, 100 | } 101 | Object.keys(obj).forEach((key) => (obj[key] === undefined ? delete obj[key] : {})) 102 | return obj 103 | } 104 | 105 | export const getMixOrderArg = ({ 106 | topic = WsTopicType.mixorder, 107 | ...orderWsRequest 108 | }: { topic?: WsTopicType.mixorder } & Omit) => { 109 | return getOrderBookArg({ 110 | topic, 111 | ...orderWsRequest, 112 | }) 113 | } 114 | 115 | export const getBtradeOrderBook = ({ 116 | topic = WsTopicType.btradedepth, 117 | ...orderWsRequest 118 | }: { topic?: WsTopicType.btradedepth } & Omit) => { 119 | return getOrderBookArg({ 120 | topic, 121 | ...orderWsRequest, 122 | }) 123 | } 124 | 125 | export const getTradeArg = (market: string) => { 126 | return { 127 | topic: WsTopicType.trade, 128 | market, 129 | } 130 | } 131 | 132 | export const getMixTradeArg = (market: string) => { 133 | return { 134 | topic: WsTopicType.mixtrade, 135 | market, 136 | } 137 | } 138 | 139 | export const getTickerArg = (market: string) => { 140 | return { 141 | topic: WsTopicType.ticker, 142 | market, 143 | } 144 | } 145 | 146 | export const getCandlestickArg = (market: string) => { 147 | return { 148 | topic: WsTopicType.candlestick, 149 | market, 150 | } 151 | } 152 | 153 | export const getAmmpoolArg = (poolAddress: string) => { 154 | return { 155 | topic: WsTopicType.ammpool, 156 | snapshot: true, 157 | poolAddress, 158 | } 159 | } 160 | 161 | export const getNotificationArg = ({ 162 | address, 163 | network, 164 | }: { 165 | address: string 166 | network: NetworkWallet 167 | }) => { 168 | return { 169 | topic: WsTopicType.notification, 170 | address, 171 | network, 172 | } 173 | } 174 | 175 | export const getL2Common = ({ address, network }: { address: string; network: NetworkWallet }) => { 176 | return { 177 | topic: WsTopicType.l2Common, 178 | address, 179 | network, 180 | } 181 | } 182 | 183 | export enum WS_ACTIONT_YPE { 184 | VAULT_ACCOUNT_UPDATE = 'VAULT_ACCOUNT_UPDATE', 185 | } 186 | export interface WsL2Common { 187 | accountId: number 188 | address: string 189 | isUpdated: true 190 | } 191 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './utils' 2 | export * from './defs' 3 | export * from './api' 4 | -------------------------------------------------------------------------------- /src/tests/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "plugins": [ 5 | "@typescript-eslint" 6 | ], 7 | "extends": [ 8 | "plugin:@typescript-eslint/eslint-recommended", 9 | "plugin:@typescript-eslint/recommended" 10 | ], 11 | "rules": { 12 | "no-console": 1 , 13 | // Remember, this means error! 14 | "camelcase": ["warn"], 15 | "@typescript-eslint/no-var-requires": "off", 16 | "no-case-declarations": "warn" 17 | } 18 | } -------------------------------------------------------------------------------- /src/tests/.gitignore: -------------------------------------------------------------------------------- 1 | output 2 | -------------------------------------------------------------------------------- /src/tests/UTC--2021-02-04T02-55-36.490219109Z--ef439044717c3af35f4f46e52aa99280217a7114: -------------------------------------------------------------------------------- 1 | {'address':'ef439044717c3af35f4f46e52aa99280217a7114','crypto':{'cipher':'aes-128-ctr','ciphertext':'143482fb2ed65e3abc9cc13fcaeb6ba74c4d756c8214df71ac976aec8252ed09','cipherparams':{'iv':'5a968f30a2345ab47f17b27b903dc211'},'kdf':'scrypt','kdfparams':{'dklen':32,'n':262144,'p':1,'r':8,'salt':'da706a1d49a37f901393ea20604587f70a04bbfecec861f8d5188dc5477410c8'},'mac':'983f9b60b7bfd030f14d1445001f2375c654a8a1a116ac6321e0e58d9a1f63f8'},'id':'13090125-668c-4935-9bcd-77512c377afd','version':3} -------------------------------------------------------------------------------- /src/tests/demo/NFTAction/collectionNFT.md: -------------------------------------------------------------------------------- 1 | # Collection NFT 2 | 3 | Definition: allow user create a NFT Collection with different Contract(token) address. 4 | 5 | - allow user mint the NFTs with collection 6 | - when collection deployed, NFTs will have different Contract(token) address in layer1 7 | - Loopring own collection on L2, allow user to view/edit their Collection information. 8 | - will soon enable the "Import Collection" to manage legacy NFTs 9 | 10 | *** 11 | 12 | ##Create Collection 13 | ```ts 14 | const eddsaKey = await signatureKeyPairMock(accInfo); 15 | const {apiKey} = await LoopringAPI.userAPI.getUserApiKey( 16 | { accountId: accInfo.accountId,}, 17 | eddsaKey.sk 18 | ); 19 | const response = await LoopringAPI.userAPI.submitNFTCollection({ 20 | name: 'XXX' + Date.now(), //required, one account is not able to multiple 21 | tileUri: 'ipfs://QmaNZ2FCgvBPqnxtkbToVVbK2Nes6xk5K4Ns6BsmkPucAM', //required 22 | description: 'test', 23 | owner: mockData.accInfo.owner, 24 | avatar: 'ipfs://QmaNZ2FCgvBPqnxtkbToVVbK2Nes6xk5K4Ns6BsmkPucAM', 25 | banner: 'ipfs://QmaNZ2FCgvBPqnxtkbToVVbK2Nes6xk5K4Ns6BsmkPucAM', 26 | nftFactory: NFTFactory_Collection[LOOPRING_EXPORTED_ACCOUNT.chainId as ChainId ]}, 27 | LOOPRING_EXPORTED_ACCOUNT.chainId as ChainId, 28 | mockData.apiKey, 29 | mockData.eddsaKey.sk) 30 | console.log('createCollection', response) 31 | 32 | ``` 33 | 34 | ## getUserNFFByCollection 35 | ```ts 36 | const response = await LoopringAPI.userAPI 37 | .getUserNFTCollection( 38 | { 39 | accountId: mockData.accInfo.accountId.toString(), 40 | limit: 24, 41 | offset: 0, 42 | }, 43 | mockData.apiKey 44 | ) 45 | .catch((_error) => { 46 | throw _error; 47 | }); 48 | console.log("getUserNFFByCollection", response); 49 | 50 | ``` 51 | 52 | ## getUserOwnCollection (User own create Collection) 53 | ```ts 54 | const response = await LoopringAPI.userAPI 55 | .getUserOwenCollection( 56 | { 57 | owner: mockData.accInfo.owner, 58 | limit: 24, 59 | offset: 0, 60 | tokenAddress: undefined, 61 | isMintable: false, //false 62 | }, 63 | mockData.apiKey 64 | ) 65 | .catch((_error) => { 66 | throw _error; 67 | }); 68 | console.log("getUserNFFByCollection", response); 69 | 70 | ``` 71 | 72 | ## getUserNFTCollection (User asset NFT's Collections) 73 | ```ts 74 | const response = await LoopringAPI.userAPI 75 | .getUserNFTCollection({ 76 | tokenAddress: contract, // option 77 | collectionId: id, // option 78 | accountId: mockData.accInfo.accountId, 79 | limit: 20, 80 | offset:10, 81 | }, mockData.apiKey) 82 | 83 | ``` 84 | 85 | ## getCollectionWholeNFTs 86 | ```ts 87 | const response = await LoopringAPI.nftAPI.getCollectionWholeNFTs({ 88 | id: 279, 89 | offset: 0, 90 | limit: 24, 91 | metadata: true, 92 | }); 93 | console.log("getCollectionWholeNFTs", response); 94 | ``` -------------------------------------------------------------------------------- /src/tests/demo/NFTAction/collectionNFT.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_TIMEOUT, 3 | LOOPRING_EXPORTED_ACCOUNT, 4 | LoopringAPI, 5 | signatureKeyPairMock, 6 | } from "../../MockData"; 7 | import { AccountInfo, ChainId, NFTFactory_Collection } from "../../../index"; 8 | 9 | let mockData: 10 | | { 11 | accInfo: AccountInfo; 12 | apiKey: string; 13 | eddsaKey: any; 14 | } 15 | | undefined = undefined; 16 | describe("metaNFT", function () { 17 | beforeEach(async () => { 18 | // Step 1. getAccount 19 | const accInfo = ( 20 | await LoopringAPI.exchangeAPI.getAccount({ 21 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 22 | }) 23 | ).accInfo; 24 | const eddsaKey = await signatureKeyPairMock(accInfo); 25 | 26 | // Step 3. apiKey 27 | const apiKey = ( 28 | await LoopringAPI.userAPI.getUserApiKey( 29 | { 30 | accountId: accInfo.accountId, 31 | }, 32 | eddsaKey.sk 33 | ) 34 | ).apiKey; 35 | 36 | mockData = { 37 | apiKey, 38 | accInfo, 39 | eddsaKey, 40 | }; 41 | }, DEFAULT_TIMEOUT * 3); 42 | it( 43 | "getUserOwnCollection", 44 | async () => { 45 | if (mockData) { 46 | const response = await LoopringAPI.userAPI 47 | .getUserOwenCollection( 48 | { 49 | owner: mockData.accInfo.owner, 50 | limit: 24, 51 | offset: 0, 52 | tokenAddress: undefined, 53 | isMintable: false, //false 54 | }, 55 | mockData.apiKey 56 | ) 57 | .catch((_error) => { 58 | throw _error; 59 | }); 60 | console.log("getUserNFFByCollection", response); 61 | } 62 | }, 63 | DEFAULT_TIMEOUT 64 | ); 65 | it( 66 | "getUserNFFByCollection", 67 | async () => { 68 | if (mockData) { 69 | const response = await LoopringAPI.userAPI 70 | .getUserNFTCollection( 71 | { 72 | accountId: mockData.accInfo.accountId.toString(), 73 | limit: 24, 74 | offset: 0, 75 | }, 76 | mockData.apiKey 77 | ) 78 | .catch((_error) => { 79 | throw _error; 80 | }); 81 | console.log("getUserNFFByCollection", response); 82 | } 83 | }, 84 | DEFAULT_TIMEOUT 85 | ); 86 | it( 87 | "getCollectionWholeNFTs", 88 | async () => { 89 | const response = await LoopringAPI.nftAPI.getCollectionWholeNFTs({ 90 | id: 279, 91 | offset: 0, 92 | limit: 24, 93 | metadata: true, 94 | }); 95 | console.log("getCollectionWholeNFTs", response); 96 | }, 97 | DEFAULT_TIMEOUT 98 | ); 99 | 100 | it( 101 | "createCollection", 102 | async () => { 103 | if (mockData) { 104 | const response = await LoopringAPI.userAPI.submitNFTCollection( 105 | { 106 | name: "XXX" + Date.now(), //required, one account is not able to multiple 107 | tileUri: "ipfs://QmaNZ2FCgvBPqnxtkbToVVbK2Nes6xk5K4Ns6BsmkPucAM", //required 108 | description: "test", 109 | owner: mockData.accInfo.owner, 110 | avatar: "ipfs://QmaNZ2FCgvBPqnxtkbToVVbK2Nes6xk5K4Ns6BsmkPucAM", 111 | banner: "ipfs://QmaNZ2FCgvBPqnxtkbToVVbK2Nes6xk5K4Ns6BsmkPucAM", 112 | nftFactory: 113 | NFTFactory_Collection[ 114 | LOOPRING_EXPORTED_ACCOUNT.chainId as ChainId 115 | ], 116 | }, 117 | LOOPRING_EXPORTED_ACCOUNT.chainId as ChainId, 118 | mockData.apiKey, 119 | mockData.eddsaKey.sk 120 | ); 121 | console.log("createCollection", response); 122 | } 123 | }, 124 | DEFAULT_TIMEOUT 125 | ); 126 | }); 127 | -------------------------------------------------------------------------------- /src/tests/demo/NFTAction/deployNFT.md: -------------------------------------------------------------------------------- 1 | # Deploy NFT 2 | 3 | Definition: Only nft minter can deploy NFT 4 | 5 | *** 6 | 7 | ## Step 1. get Account 8 | 9 | ```ts 10 | const {accInfo} = await LoopringAPI.exchangeAPI.getAccount({ 11 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 12 | }); 13 | console.log("accInfo:", accInfo); 14 | ``` 15 | 16 | *** 17 | 18 | ## Step 2. get eddsaKey 19 | 20 | ```ts 21 | const eddsaKey = await signatureKeyPairMock(accInfo); 22 | console.log("eddsaKey:", eddsaKey.sk); 23 | ``` 24 | 25 | *** 26 | 27 | ## Step 3. get apiKey 28 | 29 | ```ts 30 | const {apiKey} = await LoopringAPI.userAPI.getUserApiKey( 31 | { 32 | accountId: accInfo.accountId, 33 | }, 34 | eddsaKey.sk 35 | ); 36 | console.log("apiKey:", apiKey); 37 | ``` 38 | 39 | *** 40 | 41 | 42 | ## Step 4. get fee 43 | 44 | ```ts 45 | const fee = await LoopringAPI.userAPI.getNFTOffchainFeeAmt( 46 | { 47 | accountId: accInfo.accountId, 48 | requestType: sdk.OffchainNFTFeeReqType.NFT_DEPLOY, 49 | amount: "0", 50 | }, 51 | apiKey 52 | ); 53 | console.log(fee); 54 | ``` 55 | *** 56 | ## Step 5. get storageId 57 | 58 | ```ts 59 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 60 | { 61 | accountId: accInfo.accountId, 62 | sellTokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, // same as Step 7. transfer->token->tokenId 63 | }, 64 | apiKey 65 | ); 66 | ``` 67 | 68 | *** 69 | 70 | ## Step 6. broker 71 | 72 | ```ts 73 | const {broker} = await LoopringAPI.exchangeAPI.getAvailableBroker(); 74 | ``` 75 | 76 | *** 77 | ## Step 7. Build transfer & Deploy 78 | 79 | ```ts 80 | const transfer = { 81 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 82 | payerAddr: LOOPRING_EXPORTED_ACCOUNT.address, 83 | payerId: LOOPRING_EXPORTED_ACCOUNT.accountId, 84 | payeeAddr: broker, 85 | // payeeAddr: LOOPRING_EXPORTED_ACCOUNT.address2, 86 | storageId: storageId.offchainId, 87 | token: { 88 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 89 | volume: fee.fees["LRC"].fee ?? "9400000000000000000", 90 | }, 91 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 92 | }; 93 | const response = await LoopringAPI.userAPI.submitDeployNFT({ 94 | request: { 95 | transfer, 96 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 97 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 98 | }, 99 | web3, 100 | chainId: sdk.ChainId.GOERLI, 101 | walletType: sdk.ConnectorNames.Unknown, 102 | eddsaKey: eddsaKey.sk, 103 | apiKey: apiKey, 104 | }); 105 | 106 | console.log(response); 107 | ``` 108 | 109 | 110 | -------------------------------------------------------------------------------- /src/tests/demo/NFTAction/deployNFT.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_TIMEOUT, 3 | LOOPRING_EXPORTED_ACCOUNT, 4 | LoopringAPI, 5 | web3, 6 | TOKEN_INFO, 7 | signatureKeyPairMock, 8 | } from "../../MockData"; 9 | import * as sdk from "../../../index"; 10 | describe("deployNFT", function () { 11 | it( 12 | "submitDeployNFT", 13 | async () => { 14 | // Step 1. getAccount 15 | const { accInfo } = await LoopringAPI.exchangeAPI.getAccount({ 16 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 17 | }); 18 | console.log("accInfo:", accInfo); 19 | 20 | // Step 2. eddsaKey 21 | const eddsaKey = await signatureKeyPairMock(accInfo); 22 | console.log("eddsaKey:", eddsaKey.sk); 23 | 24 | // Step 3. apiKey 25 | const { apiKey } = await LoopringAPI.userAPI.getUserApiKey( 26 | { 27 | accountId: accInfo.accountId, 28 | }, 29 | eddsaKey.sk 30 | ); 31 | console.log("apiKey:", apiKey); 32 | 33 | // Step 4. fee 34 | const fee = await LoopringAPI.userAPI.getNFTOffchainFeeAmt( 35 | { 36 | accountId: accInfo.accountId, 37 | requestType: sdk.OffchainNFTFeeReqType.NFT_DEPLOY, 38 | amount: "0", 39 | }, 40 | apiKey 41 | ); 42 | console.log(fee); 43 | 44 | // Step 5. storageId 45 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 46 | { 47 | accountId: accInfo.accountId, 48 | sellTokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, // same as Step 7. transfer->token->tokenId 49 | }, 50 | apiKey 51 | ); 52 | 53 | // Step 6. broker 54 | const { broker } = await LoopringAPI.exchangeAPI.getAvailableBroker({ 55 | type: 0, 56 | }); 57 | 58 | // Step 7. Build transfer & Deploy 59 | const transfer = { 60 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 61 | payerAddr: LOOPRING_EXPORTED_ACCOUNT.address, 62 | payerId: LOOPRING_EXPORTED_ACCOUNT.accountId, 63 | payeeAddr: broker, 64 | // payeeAddr: LOOPRING_EXPORTED_ACCOUNT.address2, 65 | storageId: storageId.offchainId, 66 | token: { 67 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 68 | volume: fee.fees["LRC"].fee ?? "9400000000000000000", 69 | }, 70 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 71 | }; 72 | 73 | const response = await LoopringAPI.userAPI.submitDeployNFT({ 74 | request: { 75 | transfer, 76 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 77 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 78 | }, 79 | web3, 80 | chainId: sdk.ChainId.GOERLI, 81 | walletType: sdk.ConnectorNames.Unknown, 82 | eddsaKey: eddsaKey.sk, 83 | apiKey: apiKey, 84 | }); 85 | 86 | console.log(response); 87 | }, 88 | DEFAULT_TIMEOUT 89 | ); 90 | }); 91 | -------------------------------------------------------------------------------- /src/tests/demo/NFTAction/metaNFT.md: -------------------------------------------------------------------------------- 1 | # NFT META METHODS 2 | 3 | *** 4 | 5 | ## getContractNFTMeta 6 | 7 | ```ts 8 | const result = await LoopringAPI.nftAPI.getContractNFTMeta({ 9 | web3, 10 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 11 | nftId: LOOPRING_EXPORTED_ACCOUNT.nftId, 12 | nftType: sdk.NFTType.ERC1155, 13 | }); 14 | console.log(result); 15 | ``` 16 | 17 | *** 18 | 19 | ## getInfoForNFTTokens 20 | 21 | ```ts 22 | const response = await LoopringAPI.nftAPI.getInfoForNFTTokens({ 23 | nftDatas: [LOOPRING_EXPORTED_ACCOUNT.nftData], 24 | }); 25 | console.log(`getInfoForNFTTokens: response: `, JSON.stringify(response)); 26 | ``` 27 | 28 | *** 29 | 30 | ## computeNFTAddress 31 | 32 | ```ts 33 | const response = LoopringAPI.nftAPI.computeNFTAddress({ 34 | nftOwner: "0xE20cF871f1646d8651ee9dC95AAB1d93160b3467", 35 | nftFactory: "0x40F2C1770E11c5bbA3A26aEeF89616D209705C5D", 36 | }); 37 | console.log( 38 | `computeNFTAddress:`, 39 | response, 40 | "0xee354d81778a4c5a08fd9dbeb5cfd01a840a746d" 41 | ); 42 | ``` 43 | 44 | *** 45 | 46 | ## ipfsCid0ToNftID 47 | 48 | ```ts 49 | const ipfs = "QmNuqdeWUJ9iEiw5qZfJ2pJ9onqAS45ZffvV8JQSUzp7DQ"; 50 | const nftID = 51 | "0x0880847b7587968f32ba6c741f9d797d9dc64971979922a80c4e590453b8dc2f"; 52 | console.log( 53 | `ipfsCid0ToNftID: ipfs: `, 54 | ipfs, 55 | LoopringAPI.nftAPI.ipfsCid0ToNftID(ipfs) 56 | ); 57 | ``` 58 | 59 | *** 60 | 61 | ## ipfsNftIDToCid 62 | 63 | ```ts 64 | const ipfs = "QmNuqdeWUJ9iEiw5qZfJ2pJ9onqAS45ZffvV8JQSUzp7DQ"; 65 | const nftID = 66 | "0x0880847b7587968f32ba6c741f9d797d9dc64971979922a80c4e590453b8dc2f"; 67 | 68 | console.log( 69 | `ipfsCid0ToNftID: nftID: `, 70 | nftID, 71 | LoopringAPI.nftAPI.ipfsNftIDToCid(nftID) 72 | ); 73 | ``` 74 | -------------------------------------------------------------------------------- /src/tests/demo/NFTAction/metaNFT.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_TIMEOUT, 3 | LOOPRING_EXPORTED_ACCOUNT, 4 | LoopringAPI, 5 | web3, 6 | } from "../../MockData"; 7 | import * as sdk from "../../../index"; 8 | describe("metaNFT", function () { 9 | it( 10 | "getContractNFTMeta", 11 | async () => { 12 | const result = await LoopringAPI.nftAPI.getContractNFTMeta({ 13 | web3, 14 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 15 | nftId: LOOPRING_EXPORTED_ACCOUNT.nftId, 16 | nftType: sdk.NFTType.ERC1155, 17 | }); 18 | console.log(result); 19 | }, 20 | DEFAULT_TIMEOUT 21 | ); 22 | 23 | it( 24 | "getInfoForNFTTokens", 25 | async () => { 26 | const response = await LoopringAPI.nftAPI.getInfoForNFTTokens({ 27 | nftDatas: [LOOPRING_EXPORTED_ACCOUNT.nftData], 28 | }); 29 | console.log(`getInfoForNFTTokens: response: `, JSON.stringify(response)); 30 | }, 31 | DEFAULT_TIMEOUT 32 | ); 33 | it("computeNFTAddress", async () => { 34 | const response = LoopringAPI.nftAPI.computeNFTAddress({ 35 | nftOwner: "0xE20cF871f1646d8651ee9dC95AAB1d93160b3467", 36 | nftFactory: "0x40F2C1770E11c5bbA3A26aEeF89616D209705C5D", 37 | }); 38 | console.log( 39 | `computeNFTAddress:`, 40 | response, 41 | "0xee354d81778a4c5a08fd9dbeb5cfd01a840a746d" 42 | ); 43 | }); 44 | it("ipfsCid0ToNftID", () => { 45 | const ipfs = "QmNuqdeWUJ9iEiw5qZfJ2pJ9onqAS45ZffvV8JQSUzp7DQ"; 46 | const nftID = 47 | "0x0880847b7587968f32ba6c741f9d797d9dc64971979922a80c4e590453b8dc2f"; 48 | console.log( 49 | `ipfsCid0ToNftID: ipfs: `, 50 | ipfs, 51 | LoopringAPI.nftAPI.ipfsCid0ToNftID(ipfs) 52 | ); 53 | expect(LoopringAPI.nftAPI.ipfsCid0ToNftID(ipfs)).toBe(nftID); 54 | }); 55 | it("ipfsNftIDToCid", () => { 56 | const ipfs = "QmNuqdeWUJ9iEiw5qZfJ2pJ9onqAS45ZffvV8JQSUzp7DQ"; 57 | const nftID = 58 | "0x0880847b7587968f32ba6c741f9d797d9dc64971979922a80c4e590453b8dc2f"; 59 | 60 | console.log( 61 | `ipfsCid0ToNftID: nftID: `, 62 | nftID, 63 | LoopringAPI.nftAPI.ipfsNftIDToCid(nftID) 64 | ); 65 | expect(LoopringAPI.nftAPI.ipfsNftIDToCid(nftID)).toBe(ipfs); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /src/tests/demo/NFTAction/tradeNFT.md: -------------------------------------------------------------------------------- 1 | # Trade NFT 2 | 3 | Definition: This method is help for understand how to match a maker with a taker order 4 | 5 | *** 6 | 7 | ## tradeNFT 8 | > Private or third account can signature and approve this order 9 | 10 | [mock order](#MockOrder) 11 | ```ts 12 | // Step 1. getAccount 13 | const accInfoC = ( 14 | await LoopringAPI.exchangeAPI.getAccount({ 15 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 16 | }) 17 | ).accInfo; 18 | 19 | // Step 1. eddsaKeyC 20 | const eddsaKeyC = await signatureKeyPairMock(accInfoC); 21 | 22 | // Step 3. apiKey 23 | const apiKeyC = ( 24 | await LoopringAPI.userAPI.getUserApiKey( 25 | { 26 | accountId: accInfoC.accountId, 27 | }, 28 | eddsaKeyC.sk 29 | ) 30 | ).apiKey; 31 | // NFT Trade 32 | const response = await LoopringAPI.userAPI.submitNFTTrade({ 33 | request: { 34 | maker: { 35 | ...mockData.makerOrder, 36 | eddsaSignature: mockData.makerOrderEddsaSignature, 37 | }, 38 | makerFeeBips: 1000, 39 | taker: { 40 | ...mockData.takerOrder, 41 | eddsaSignature: mockData.takerOrderEddsaSignature, 42 | }, 43 | takerFeeBips: 100, 44 | }, 45 | web3, 46 | chainId: sdk.ChainId.GOERLI, 47 | walletType: sdk.ConnectorNames.Unknown, 48 | apiKey: apiKeyC, 49 | eddsaKey: eddsaKeyC.sk, 50 | }); 51 | 52 | console.log(response); 53 | ``` 54 | 55 | *** 56 | 57 | ## MockOrder 58 | 59 | > Validate NFT Order please reader @Validate NFT Order 60 | 61 | ```ts 62 | // Step 1. getAccount 63 | const accInfo = ( 64 | await LoopringAPI.exchangeAPI.getAccount({ 65 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 66 | }) 67 | ).accInfo; 68 | const accInfo2 = ( 69 | await LoopringAPI.exchangeAPI.getAccount({ 70 | owner: LOOPRING_EXPORTED_ACCOUNT.address2, 71 | }) 72 | ).accInfo; 73 | // Step 2. eddsaKey 74 | const eddsaKey = await signatureKeyPairMock(accInfo); 75 | const eddsaKey2 = await signatureKeyPairMock(accInfo2, web3_2); 76 | // Step 3. apiKey 77 | const apiKey = ( 78 | await LoopringAPI.userAPI.getUserApiKey( 79 | { 80 | accountId: accInfo.accountId, 81 | }, 82 | eddsaKey.sk 83 | ) 84 | ).apiKey; 85 | const apiKey2 = ( 86 | await LoopringAPI.userAPI.getUserApiKey( 87 | { 88 | accountId: accInfo2.accountId, 89 | }, 90 | eddsaKey2.sk 91 | ) 92 | ).apiKey; 93 | 94 | // Step 4. storageId 95 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 96 | { 97 | accountId: accInfo.accountId, 98 | sellTokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 99 | }, 100 | apiKey 101 | ); 102 | const storageId2 = await LoopringAPI.userAPI.getNextStorageId( 103 | { 104 | accountId: accInfo2.accountId, 105 | sellTokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 106 | }, 107 | apiKey2 108 | ); 109 | // Step 5. generate Order, please read validateNFTOrder 110 | const makerOrder: sdk.NFTOrderRequestV3 = { 111 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 112 | accountId: accInfo.accountId, 113 | storageId: storageId.orderId, 114 | sellToken: { 115 | tokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 116 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 117 | amount: "1", 118 | }, 119 | buyToken: { 120 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 121 | amount: LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue.toString(), 122 | }, 123 | allOrNone: false, 124 | fillAmountBOrS: false, 125 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 126 | maxFeeBips: 1000, 127 | }; 128 | const makerOrderEddsaSignature = sdk.get_EddsaSig_NFT_Order( 129 | makerOrder, 130 | eddsaKey.sk 131 | ); 132 | 133 | const takerOrder: sdk.NFTOrderRequestV3 = { 134 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 135 | accountId: accInfo2.accountId, 136 | storageId: storageId2.orderId, 137 | sellToken: { 138 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 139 | amount: LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue.toString(), 140 | }, 141 | buyToken: { 142 | tokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 143 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 144 | amount: "1", 145 | }, 146 | allOrNone: false, 147 | fillAmountBOrS: true, 148 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 149 | maxFeeBips: 100, 150 | }; 151 | const takerOrderEddsaSignature = sdk.get_EddsaSig_NFT_Order( 152 | takerOrder, 153 | eddsaKey2.sk 154 | ); 155 | 156 | mockData = { 157 | takerOrder, 158 | takerOrderEddsaSignature, 159 | makerOrder, 160 | makerOrderEddsaSignature, 161 | makerFeeBips: 1000, 162 | maxFeeBips: 100, 163 | }; 164 | 165 | ``` 166 | -------------------------------------------------------------------------------- /src/tests/demo/NFTAction/validateNFTOrder.md: -------------------------------------------------------------------------------- 1 | # Validate NFT Order 2 | 3 | Definition: Loopring L2 support a method help for Validate NFT one side Order, validate NFT Order is not required for 4 | Loopring, but when make NFT Trade, it should pass this validation 5 | 6 | ## SellNFTByERC20 7 | 8 | ```ts 9 | // Step 1. getAccount 10 | const {accInfo} = await LoopringAPI.exchangeAPI.getAccount({ 11 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 12 | }); 13 | console.log("accInfo:", accInfo); 14 | 15 | // Step 2. eddsaKey 16 | const eddsaKey = await signatureKeyPairMock(accInfo); 17 | console.log("eddsaKey:", eddsaKey.sk); 18 | 19 | // Step 3. apiKey 20 | const {apiKey} = await LoopringAPI.userAPI.getUserApiKey( 21 | { 22 | accountId: accInfo.accountId, 23 | }, 24 | eddsaKey.sk 25 | ); 26 | console.log("apiKey:", apiKey); 27 | 28 | // Step 4. storageId 29 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 30 | { 31 | accountId: accInfo.accountId, 32 | sellTokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 33 | }, 34 | apiKey 35 | ); 36 | console.log("storageId:", storageId); 37 | // let hash: any = new BN(nftId,'hex') 38 | // hash = toHex(hash);//new BigInteger(sha256(nftId.toString()).toString(), 16) 39 | 40 | // Step 5. submitNFTValidateOrder 41 | const response = await LoopringAPI.userAPI.submitNFTValidateOrder({ 42 | request: { 43 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 44 | accountId: accInfo.accountId, 45 | storageId: storageId.orderId, 46 | sellToken: { 47 | tokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 48 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 49 | amount: "1", 50 | }, 51 | buyToken: { 52 | tokenId: 1, 53 | amount: "10000000000000", 54 | }, 55 | allOrNone: false, 56 | fillAmountBOrS: false, 57 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 58 | maxFeeBips: 1000, 59 | }, 60 | web3, 61 | chainId: sdk.ChainId.GOERLI, 62 | walletType: sdk.ConnectorNames.Unknown, 63 | eddsaKey: eddsaKey.sk, 64 | apiKey: apiKey, 65 | }); 66 | 67 | console.log("sellNFT NFTOrderRequestV3:", response); 68 | ``` 69 | 70 | *** 71 | 72 | ## BuyNFTByERC20 73 | 74 | ```ts 75 | // Step 1. getAccount 76 | const {accInfo} = await LoopringAPI.exchangeAPI.getAccount({ 77 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 78 | }); 79 | console.log("accInfo:", accInfo); 80 | 81 | // Step 2. eddsaKey 82 | const eddsaKey = await signatureKeyPairMock(accInfo); 83 | console.log("eddsaKey:", eddsaKey.sk); 84 | 85 | // Step 3. apiKey 86 | const {apiKey} = await LoopringAPI.userAPI.getUserApiKey( 87 | { 88 | accountId: accInfo.accountId, 89 | }, 90 | eddsaKey.sk 91 | ); 92 | console.log("apiKey:", apiKey); 93 | 94 | // Step 5. submitNFTValidateOrder 95 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 96 | { 97 | accountId: accInfo.accountId, 98 | sellTokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 99 | }, 100 | apiKey 101 | ); 102 | console.log("storageId:", storageId); 103 | 104 | const response = await LoopringAPI.userAPI.submitNFTValidateOrder({ 105 | request: { 106 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 107 | accountId: accInfo.accountId, 108 | storageId: storageId.orderId, 109 | sellToken: { 110 | tokenId: 1, 111 | amount: "10000000000000", 112 | }, 113 | buyToken: { 114 | tokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 115 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 116 | amount: "1", 117 | }, 118 | fillAmountBOrS: true, 119 | allOrNone: false, 120 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 121 | maxFeeBips: 100, 122 | }, 123 | web3, 124 | chainId: sdk.ChainId.GOERLI, 125 | walletType: sdk.ConnectorNames.Unknown, 126 | eddsaKey: eddsaKey.sk, 127 | apiKey: apiKey, 128 | }); 129 | ``` 130 | 131 | -------------------------------------------------------------------------------- /src/tests/demo/NFTAction/validateNFTOrder.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_TIMEOUT, 3 | LOOPRING_EXPORTED_ACCOUNT, 4 | LoopringAPI, 5 | web3, 6 | signatureKeyPairMock, 7 | } from "../../MockData"; 8 | import * as sdk from "../../../index"; 9 | 10 | describe("validateNFTOrder", function () { 11 | it( 12 | "sellNFTByERC20", 13 | async () => { 14 | // Step 1. getAccount 15 | const { accInfo } = await LoopringAPI.exchangeAPI.getAccount({ 16 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 17 | }); 18 | console.log("accInfo:", accInfo); 19 | 20 | // Step 2. eddsaKey 21 | const eddsaKey = await signatureKeyPairMock(accInfo); 22 | console.log("eddsaKey:", eddsaKey.sk); 23 | 24 | // Step 3. apiKey 25 | const { apiKey } = await LoopringAPI.userAPI.getUserApiKey( 26 | { 27 | accountId: accInfo.accountId, 28 | }, 29 | eddsaKey.sk 30 | ); 31 | console.log("apiKey:", apiKey); 32 | 33 | // Step 4. storageId 34 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 35 | { 36 | accountId: accInfo.accountId, 37 | sellTokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 38 | }, 39 | apiKey 40 | ); 41 | console.log("storageId:", storageId); 42 | // let hash: any = new BN(nftId,'hex') 43 | // hash = toHex(hash);//new BigInteger(sha256(nftId.toString()).toString(), 16) 44 | 45 | // Step 5. submitNFTValidateOrder 46 | const response = await LoopringAPI.userAPI.submitNFTValidateOrder({ 47 | request: { 48 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 49 | accountId: accInfo.accountId, 50 | storageId: storageId.orderId, 51 | sellToken: { 52 | tokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 53 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 54 | amount: "1", 55 | }, 56 | buyToken: { 57 | tokenId: 1, 58 | amount: "10000000000000", 59 | }, 60 | allOrNone: false, 61 | fillAmountBOrS: false, 62 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 63 | maxFeeBips: 1000, 64 | }, 65 | web3, 66 | chainId: sdk.ChainId.GOERLI, 67 | walletType: sdk.ConnectorNames.Unknown, 68 | eddsaKey: eddsaKey.sk, 69 | apiKey: apiKey, 70 | }); 71 | 72 | console.log("sellNFT NFTOrderRequestV3:", response); 73 | }, 74 | DEFAULT_TIMEOUT 75 | ); 76 | it( 77 | "buyNFTByERC20", 78 | async () => { 79 | // Step 1. getAccount 80 | const { accInfo } = await LoopringAPI.exchangeAPI.getAccount({ 81 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 82 | }); 83 | console.log("accInfo:", accInfo); 84 | 85 | // Step 2. eddsaKey 86 | const eddsaKey = await signatureKeyPairMock(accInfo); 87 | console.log("eddsaKey:", eddsaKey.sk); 88 | 89 | // Step 3. apiKey 90 | const { apiKey } = await LoopringAPI.userAPI.getUserApiKey( 91 | { 92 | accountId: accInfo.accountId, 93 | }, 94 | eddsaKey.sk 95 | ); 96 | console.log("apiKey:", apiKey); 97 | 98 | // Step 5. submitNFTValidateOrder 99 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 100 | { 101 | accountId: accInfo.accountId, 102 | sellTokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 103 | }, 104 | apiKey 105 | ); 106 | console.log("storageId:", storageId); 107 | 108 | const response = await LoopringAPI.userAPI.submitNFTValidateOrder({ 109 | request: { 110 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 111 | accountId: accInfo.accountId, 112 | storageId: storageId.orderId, 113 | sellToken: { 114 | tokenId: 1, 115 | amount: "10000000000000", 116 | }, 117 | buyToken: { 118 | tokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 119 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 120 | amount: "1", 121 | }, 122 | fillAmountBOrS: true, 123 | allOrNone: false, 124 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 125 | maxFeeBips: 100, 126 | }, 127 | web3, 128 | chainId: sdk.ChainId.GOERLI, 129 | walletType: sdk.ConnectorNames.Unknown, 130 | eddsaKey: eddsaKey.sk, 131 | apiKey: apiKey, 132 | }); 133 | console.log("buyNFT NFTOrderRequestV3:", response); 134 | }, 135 | DEFAULT_TIMEOUT 136 | ); 137 | }); 138 | -------------------------------------------------------------------------------- /src/tests/demo/account/activeAccount.md: -------------------------------------------------------------------------------- 1 | # Active Account 2 | 3 | Definition: After user Deposit or (Third-Part Transfer), how to active Loopring L2 account. 4 | 5 | *** 6 | 7 | ## Step 1. get account info 8 | 9 | ```ts 10 | const {accInfo} = await LoopringAPI.exchangeAPI.getAccount({ 11 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 12 | }); 13 | ``` 14 | 15 | *** 16 | 17 | ## Step 2. use keySeed or CUSTOMER_KEY_SEED generateKeyPair 18 | 19 | ```ts 20 | const keySeed = sdk.BaseAPI.KEY_MESSAGE.replace( 21 | "${exchangeAddress}", 22 | LOOPRING_EXPORTED_ACCOUNT.exchangeAddress 23 | ).replace("${nonce}", accInfo.nonce.toString()); 24 | const eddsaKey = await sdk.generateKeyPair({ 25 | web3, 26 | address: accInfo.owner, 27 | keySeed, 28 | walletType: sdk.ConnectorNames.MetaMask, 29 | chainId: sdk.ChainId.GOERLI, 30 | }); 31 | console.log("eddsakey:", eddsaKey.sk); 32 | ``` 33 | 34 | Or 35 | 36 | ```ts 37 | // CUSTOMER_KEY_SEED = "XXXXXX" + " with key nonce: " + "${nonce}"; 38 | const keySeed = CUSTOMER_KEY_SEED.replace( 39 | "${nonce}", 40 | accInfo.nonce.toString() 41 | const eddsaKey = await sdk.generateKeyPair({ 42 | web3, 43 | address: accInfo.owner, 44 | keySeed, 45 | walletType: sdk.ConnectorNames.MetaMask, 46 | chainId: sdk.ChainId.GOERLI, 47 | }); 48 | console.log("eddsakey:", eddsaKey.sk); 49 | ``` 50 | 51 | *** 52 | 53 | ## Step 3. get fee 54 | 55 | ```ts 56 | const fee = await LoopringAPI.globalAPI.getActiveFeeInfo({ 57 | accountId: accInfo.accountId, 58 | }); 59 | console.log("fee:", fee); 60 | ``` 61 | 62 | *** 63 | 64 | ## Step 4. updateAccount (active or rest) 65 | 66 | ```ts 67 | const result = await LoopringAPI.userAPI.updateAccount({ 68 | request: { 69 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 70 | owner: accInfo.owner, 71 | accountId: accInfo.accountId, 72 | publicKey: {x: eddsaKey.formatedPx, y: eddsaKey.formatedPy}, 73 | maxFee: { 74 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 75 | volume: fee.fees["LRC"].fee ?? "9400000000000000000", 76 | }, 77 | keySeed, 78 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 79 | nonce: accInfo.nonce as number, 80 | }, 81 | web3, 82 | chainId: sdk.ChainId.GOERLI, 83 | walletType: sdk.ConnectorNames.Unknown, 84 | isHWAddr: false, 85 | }); 86 | 87 | const {accInfo: updateAccountInfo} = 88 | await LoopringAPI.exchangeAPI.getAccount({ 89 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 90 | }); 91 | console.log( 92 | "updateAccount Result: ", 93 | result, 94 | "updateAccountInfo:", 95 | updateAccountInfo 96 | ); 97 | ``` -------------------------------------------------------------------------------- /src/tests/demo/account/historyRecord.md: -------------------------------------------------------------------------------- 1 | # User Actions History 2 | For check account Actions, more detail such as filters please read SDK interface or API . 3 | 4 | *** 5 | 6 | ## getUserTrades 7 | 8 | ```ts 9 | async () => { 10 | const result = await LoopringAPI.userAPI.getUserTrades( 11 | { 12 | accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 13 | offset: 0, 14 | limit: 20, 15 | fillTypes: sdk.TradesFillTypes.dex, 16 | }, 17 | apiKey 18 | ); 19 | console.log("getUserTrades:", result); 20 | ``` 21 | 22 | *** 23 | 24 | ## getUserTxs 25 | 26 | ```ts 27 | async () => { 28 | const result = await LoopringAPI.userAPI.getUserTxs( 29 | { 30 | accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 31 | types: [ 32 | sdk.UserTxTypes.DEPOSIT, 33 | sdk.UserTxTypes.TRANSFER, 34 | sdk.UserTxTypes.ONCHAIN_WITHDRAWAL, 35 | ], 36 | }, 37 | apiKey 38 | ); 39 | console.log("getUserTxs:", result); 40 | ``` 41 | 42 | *** 43 | 44 | ## getUserNFTTransactionHistory 45 | 46 | ```ts 47 | async () => { 48 | const result = await LoopringAPI.userAPI.getUserNFTTransactionHistory( 49 | { 50 | accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 51 | types: [ 52 | sdk.UserNFTTxTypes.DEPOSIT, 53 | sdk.UserNFTTxTypes.TRANSFER, 54 | sdk.UserNFTTxTypes.WITHDRAW, 55 | sdk.UserNFTTxTypes.MINT, 56 | ], 57 | }, 58 | apiKey 59 | ); 60 | console.log("getUserNFTTransactionHistory:", result); 61 | ``` 62 | 63 | *** 64 | 65 | ## getOrders 66 | 67 | ```ts 68 | async () => { 69 | const result = await LoopringAPI.userAPI.getOrders( 70 | { 71 | accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 72 | orderTypes: sdk.OrderType.LimitOrder, 73 | }, 74 | apiKey 75 | ); 76 | 77 | console.log("getOrders:", result); 78 | ``` 79 | -------------------------------------------------------------------------------- /src/tests/demo/account/historyRecord.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_TIMEOUT, 3 | LOOPRING_EXPORTED_ACCOUNT, 4 | LoopringAPI, 5 | signatureKeyPairMock, 6 | } from "../../MockData"; 7 | import * as sdk from "../../../index"; 8 | let apiKey = ""; 9 | describe("historyRecord", function () { 10 | beforeEach(async () => { 11 | // Step 1. getAccount 12 | const { accInfo } = await LoopringAPI.exchangeAPI.getAccount({ 13 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 14 | }); 15 | console.log("accInfo:", accInfo); 16 | 17 | // Step 2. eddsaKey 18 | const eddsaKey = await signatureKeyPairMock(accInfo); 19 | console.log("eddsaKey:", eddsaKey.sk); 20 | 21 | // Step 3. apiKey 22 | apiKey = ( 23 | await LoopringAPI.userAPI.getUserApiKey( 24 | { 25 | accountId: accInfo.accountId, 26 | }, 27 | eddsaKey.sk 28 | ) 29 | ).apiKey; 30 | console.log("apiKey:", apiKey); 31 | }, DEFAULT_TIMEOUT); 32 | 33 | it( 34 | "getUserTrades", 35 | async () => { 36 | const result = await LoopringAPI.userAPI.getUserTrades( 37 | { 38 | accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 39 | offset: 0, 40 | limit: 20, 41 | fillTypes: sdk.TradesFillTypes.dex, 42 | }, 43 | apiKey 44 | ); 45 | console.log("getUserTrades:", result); 46 | }, 47 | DEFAULT_TIMEOUT 48 | ); 49 | it( 50 | "getUserTxs", 51 | async () => { 52 | const result = await LoopringAPI.userAPI.getUserTxs( 53 | { 54 | accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 55 | types: [ 56 | sdk.UserTxTypes.DEPOSIT, 57 | sdk.UserTxTypes.TRANSFER, 58 | sdk.UserTxTypes.OFFCHAIN_WITHDRAWAL, 59 | ], 60 | }, 61 | apiKey 62 | ); 63 | console.log("getUserTxs:", result); 64 | }, 65 | DEFAULT_TIMEOUT 66 | ); 67 | it( 68 | "getUserNFTTransactionHistory", 69 | async () => { 70 | const result = await LoopringAPI.userAPI.getUserNFTTransactionHistory( 71 | { 72 | accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 73 | types: [ 74 | sdk.UserNFTTxTypes.DEPOSIT, 75 | sdk.UserNFTTxTypes.TRANSFER, 76 | sdk.UserNFTTxTypes.WITHDRAW, 77 | sdk.UserNFTTxTypes.MINT, 78 | ], 79 | }, 80 | apiKey 81 | ); 82 | console.log("getUserNFTTransactionHistory:", result); 83 | }, 84 | DEFAULT_TIMEOUT 85 | ); 86 | it( 87 | "getOrders", 88 | async () => { 89 | const result = await LoopringAPI.userAPI.getOrders( 90 | { 91 | accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 92 | orderTypes: sdk.OrderType.LimitOrder, 93 | }, 94 | apiKey 95 | ); 96 | 97 | console.log("getOrders:", result); 98 | }, 99 | DEFAULT_TIMEOUT 100 | ); 101 | }); 102 | -------------------------------------------------------------------------------- /src/tests/demo/account/signature.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_TIMEOUT, 3 | LOOPRING_EXPORTED_ACCOUNT, 4 | LoopringAPI, 5 | signatureKeyPairMock, 6 | testTypedData, 7 | web3, 8 | } from '../../MockData' 9 | import * as sdk from '../../../index' 10 | 11 | describe('signature', function () { 12 | it( 13 | 'generateKeyPair', 14 | async () => { 15 | const { accInfo } = await LoopringAPI.exchangeAPI.getAccount({ 16 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 17 | }) 18 | const result = await signatureKeyPairMock(accInfo) 19 | console.log(result.sk) 20 | }, 21 | DEFAULT_TIMEOUT, 22 | ) 23 | /** 24 | * test case is not allow brock by Mock provider 25 | */ 26 | // it( 27 | // "getEcDSASig:eth_signTypedData_v4", 28 | // async () => { 29 | // // test case is not allow brock by Mock provider 30 | // const result = await sdk.getEcDSASig( 31 | // web3, 32 | // testTypedData, 33 | // LOOPRING_EXPORTED_ACCOUNT.address, 34 | // sdk.GetEcDSASigType.HasDataStruct, 35 | // sdk.ChainId.GOERLI, 36 | // LOOPRING_EXPORTED_ACCOUNT.accountId, 37 | // "", 38 | // sdk.ConnectorNames.Unknown 39 | // ); 40 | // console.log( 41 | // "getEcDSASig:eth_signTypedData_v4", 42 | // result, 43 | // "ecdsaSig+sdk.SigSuffix.Suffix02", 44 | // result.ecdsaSig + sdk.SigSuffix.Suffix02 45 | // ); 46 | // }, 47 | // DEFAULT_TIMEOUT 48 | // ); 49 | 50 | it('getEcDSASig:WithoutDataStruct(personalSign)', async () => { 51 | const result = await sdk.getEcDSASig( 52 | web3, 53 | testTypedData, 54 | LOOPRING_EXPORTED_ACCOUNT.address, 55 | sdk.GetEcDSASigType.WithoutDataStruct, 56 | sdk.ChainId.GOERLI, 57 | LOOPRING_EXPORTED_ACCOUNT.accountId, 58 | '', 59 | sdk.ConnectorNames.Unknown, 60 | ) 61 | console.log('getEcDSASig:WithoutDataStruct(personalSign)', result) 62 | }) 63 | /** 64 | * test case is not allow brock by Mock provider 65 | */ 66 | // it("personalSign Contract", async () => { 67 | // await sdk.getEcDSASig( 68 | // web3, 69 | // testTypedData, 70 | // LOOPRING_EXPORTED_ACCOUNT.address, 71 | // sdk.GetEcDSASigType.Contract, 72 | // sdk.ChainId.GOERLI, 73 | // LOOPRING_EXPORTED_ACCOUNT.accountId, 74 | // "", 75 | // sdk.ConnectorNames.Unknown 76 | // ); 77 | // }); 78 | }) 79 | 80 | export default {} 81 | -------------------------------------------------------------------------------- /src/tests/demo/deposit/deposit.md: -------------------------------------------------------------------------------- 1 | # Deposit ERC20 2 | 3 | Definition: Move user L1 ERC20 assets to Loopring L2 4 | > **All Deposit Method, User should have enough `ETH` pay for the Ethereum Gas (Loopring have no charge, no fee for Deposit).** 5 | 6 | Provider will give the Gas Price & Limit, sdk also have a method get gasPrice: 7 | `const gasPrice = (await LoopringAPI.exchangeAPI.getGasPrice() ).gasPrice;` 8 | 9 | # ETH 10 | 11 | *** 12 | 13 | ## Step 1. getNonce 14 | 15 | ```ts 16 | const nonce = await sdk.getNonce(web3, LOOPRING_EXPORTED_ACCOUNT.address); 17 | console.log( 18 | `deposit: ${TOKEN_INFO.tokenMap.ETH.symbol}-${LOOPRING_EXPORTED_ACCOUNT.tradeETHValue}, gasPrice: ${LOOPRING_EXPORTED_ACCOUNT.gasPrice}, ` 19 | ); 20 | ``` 21 | 22 | *** 23 | 24 | ## Step 2. deposit 25 | 26 | ```ts 27 | const response = await sdk.deposit( 28 | web3, 29 | LOOPRING_EXPORTED_ACCOUNT.address, 30 | LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 31 | TOKEN_INFO.tokenMap.ETH, 32 | LOOPRING_EXPORTED_ACCOUNT.tradeETHValue, 33 | 0, 34 | LOOPRING_EXPORTED_ACCOUNT.gasPrice, 35 | LOOPRING_EXPORTED_ACCOUNT.gasLimit, 36 | sdk.ChainId.GOERLI, 37 | nonce, 38 | true 39 | ); 40 | 41 | console.log(`nonce: ${nonce} deposit_ETH: `, response); 42 | ``` 43 | 44 | # ERC20 45 | 46 | *** 47 | 48 | ## Step 1. getAllowances 49 | 50 | ```ts 51 | const {tokenAllowances} = await LoopringAPI.exchangeAPI.getAllowances({ 52 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 53 | token: [TOKEN_INFO.tokenMap.LRC.address], 54 | }); 55 | if ( 56 | tokenAllowances.has(TOKEN_INFO.tokenMap.LRC.address) && 57 | Number(tokenAllowances.get(TOKEN_INFO.tokenMap.LRC.address)) < 58 | LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue 59 | ) { 60 | const nonce = await web3.eth.getTransactionCount( 61 | LOOPRING_EXPORTED_ACCOUNT.address 62 | ); 63 | await sdk.approveMax( 64 | web3, 65 | LOOPRING_EXPORTED_ACCOUNT.address, 66 | TOKEN_INFO.tokenMap.LRC.address, // LRC address {tokenIdMap} = getTokens(); tokenIdMap['LRC'] 67 | LOOPRING_EXPORTED_ACCOUNT.depositAddress, //{exchangeInfo} = getExchangeInfo() exchangeInfo.depositAddress 68 | LOOPRING_EXPORTED_ACCOUNT.gasPrice, 69 | LOOPRING_EXPORTED_ACCOUNT.gasLimit, 70 | sdk.ChainId.GOERLI, 71 | nonce, 72 | true 73 | ); 74 | } 75 | ``` 76 | 77 | *** 78 | 79 | ## Step 2. getNonce 80 | 81 | ```ts 82 | const nonce = await sdk.getNonce(web3, LOOPRING_EXPORTED_ACCOUNT.address); 83 | console.log( 84 | `deposit: ${TOKEN_INFO.tokenMap.LRC.symbol}-${LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue}, gasPrice: ${LOOPRING_EXPORTED_ACCOUNT.gasPrice}, ` 85 | ); 86 | ``` 87 | 88 | *** 89 | 90 | ## Step 3. deposit 91 | 92 | ```ts 93 | const response = await sdk.deposit( 94 | web3, 95 | LOOPRING_EXPORTED_ACCOUNT.address, 96 | LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 97 | TOKEN_INFO.tokenMap.LRC, 98 | sdk 99 | .toBig(LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue) 100 | .div("1e" + TOKEN_INFO.tokenMap.LRC.decimals) 101 | .toNumber(), 102 | 0, 103 | LOOPRING_EXPORTED_ACCOUNT.gasPrice, 104 | LOOPRING_EXPORTED_ACCOUNT.gasLimit, 105 | sdk.ChainId.GOERLI, 106 | nonce, 107 | true 108 | ); 109 | 110 | console.log(`nonce: ${nonce} deposit_LRC: `, response); 111 | ``` 112 | 113 | -------------------------------------------------------------------------------- /src/tests/demo/deposit/deposit.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_TIMEOUT, 3 | LOOPRING_EXPORTED_ACCOUNT, 4 | LoopringAPI, 5 | web3, 6 | TOKEN_INFO, 7 | } from "../../MockData"; 8 | import * as sdk from "../../../index"; 9 | 10 | describe("deposit", function () { 11 | beforeEach(async () => { 12 | jest.setTimeout(DEFAULT_TIMEOUT * 3); 13 | 14 | LOOPRING_EXPORTED_ACCOUNT.gasPrice = ( 15 | await LoopringAPI.exchangeAPI.getGasPrice() 16 | ).gasPrice; 17 | }, DEFAULT_TIMEOUT); 18 | it( 19 | "deposit_LRC", 20 | async () => { 21 | // step1: getAllowances 22 | const { tokenAllowances } = await LoopringAPI.exchangeAPI.getAllowances({ 23 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 24 | token: [TOKEN_INFO.tokenMap.LRC.address], 25 | }); 26 | if ( 27 | tokenAllowances.has(TOKEN_INFO.tokenMap.LRC.address) && 28 | Number(tokenAllowances.get(TOKEN_INFO.tokenMap.LRC.address)) < 29 | LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue 30 | ) { 31 | const nonce = await web3.eth.getTransactionCount( 32 | LOOPRING_EXPORTED_ACCOUNT.address 33 | ); 34 | await sdk.approveMax( 35 | web3, 36 | LOOPRING_EXPORTED_ACCOUNT.address, 37 | TOKEN_INFO.tokenMap.LRC.address, // LRC address {tokenIdMap} = getTokens(); tokenIdMap['LRC'] 38 | LOOPRING_EXPORTED_ACCOUNT.depositAddress, //{exchangeInfo} = getExchangeInfo() exchangeInfo.depositAddress 39 | LOOPRING_EXPORTED_ACCOUNT.gasPrice, 40 | LOOPRING_EXPORTED_ACCOUNT.gasLimit, 41 | sdk.ChainId.GOERLI, 42 | nonce, 43 | true 44 | ); 45 | } 46 | 47 | const nonce = await sdk.getNonce(web3, LOOPRING_EXPORTED_ACCOUNT.address); 48 | console.log( 49 | `deposit: ${TOKEN_INFO.tokenMap.LRC.symbol}-${LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue}, gasPrice: ${LOOPRING_EXPORTED_ACCOUNT.gasPrice}, ` 50 | ); 51 | const response = await sdk.deposit( 52 | web3, 53 | LOOPRING_EXPORTED_ACCOUNT.address, 54 | LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 55 | TOKEN_INFO.tokenMap.LRC, 56 | sdk 57 | .toBig(LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue) 58 | .div("1e" + TOKEN_INFO.tokenMap.LRC.decimals) 59 | .toNumber(), 60 | 0, 61 | LOOPRING_EXPORTED_ACCOUNT.gasPrice, 62 | LOOPRING_EXPORTED_ACCOUNT.gasLimit, 63 | sdk.ChainId.GOERLI, 64 | nonce, 65 | true 66 | ); 67 | 68 | console.log(`nonce: ${nonce} deposit_LRC: `, response); 69 | }, 70 | DEFAULT_TIMEOUT * 3 71 | ); 72 | 73 | it( 74 | "deposit_ETH", 75 | async () => { 76 | const nonce = await sdk.getNonce(web3, LOOPRING_EXPORTED_ACCOUNT.address); 77 | console.log( 78 | `deposit: ${TOKEN_INFO.tokenMap.ETH.symbol}-${LOOPRING_EXPORTED_ACCOUNT.tradeETHValue}, gasPrice: ${LOOPRING_EXPORTED_ACCOUNT.gasPrice}, ` 79 | ); 80 | const response = await sdk.deposit( 81 | web3, 82 | LOOPRING_EXPORTED_ACCOUNT.address, 83 | LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 84 | TOKEN_INFO.tokenMap.ETH, 85 | LOOPRING_EXPORTED_ACCOUNT.tradeETHValue, 86 | 0, 87 | LOOPRING_EXPORTED_ACCOUNT.gasPrice, 88 | LOOPRING_EXPORTED_ACCOUNT.gasLimit, 89 | sdk.ChainId.GOERLI, 90 | nonce, 91 | true 92 | ); 93 | 94 | console.log(`nonce: ${nonce} deposit_ETH: `, response); 95 | }, 96 | DEFAULT_TIMEOUT * 3 97 | ); 98 | }); 99 | -------------------------------------------------------------------------------- /src/tests/demo/deposit/depositNFT.md: -------------------------------------------------------------------------------- 1 | # Deposit NFT 2 | 3 | Definition: Move user L1 NFT assets to Loopring L2 4 | 5 | > **All Deposit Method, User should have enough `ETH` pay for the Ethereum Gas (Loopring have no charge, no fee for Deposit).** 6 | 7 | 8 | *** 9 | 10 | ## Step 1. getNFTBalance & getEthBalances 11 | 12 | ```ts 13 | const {ethBalance} = await LoopringAPI.exchangeAPI.getEthBalances({ 14 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 15 | }); 16 | const nftBalance = await LoopringAPI.nftAPI.getNFTBalance({ 17 | web3, 18 | account: LOOPRING_EXPORTED_ACCOUNT.address, 19 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 20 | nftId: LOOPRING_EXPORTED_ACCOUNT.nftId, 21 | nftType: sdk.NFTType.ERC1155, 22 | }); 23 | ``` 24 | 25 | *** 26 | 27 | ## Step 2. isApprovedForAll 28 | 29 | ```ts 30 | const isApprovedForAll = await LoopringAPI.nftAPI.isApprovedForAll({ 31 | web3, 32 | from: LOOPRING_EXPORTED_ACCOUNT.address, 33 | exchangeAddress: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 34 | nftType: sdk.NFTType.ERC1155, // todo: sdk.NFTType.ERC721 35 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 36 | }); 37 | console.log(`check is approveNFT`, isApprovedForAll); 38 | 39 | ``` 40 | 41 | *** 42 | 43 | ## Step 3. approveNFT All 44 | 45 | ```ts 46 | if (!isApprovedForAll) { 47 | const nonce = await sdk.getNonce( 48 | web3, 49 | LOOPRING_EXPORTED_ACCOUNT.address 50 | ); 51 | const approveNFT = await LoopringAPI.nftAPI.approveNFT({ 52 | web3, 53 | from: LOOPRING_EXPORTED_ACCOUNT.address, 54 | depositAddress: LOOPRING_EXPORTED_ACCOUNT.depositAddress, 55 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 56 | nftType: sdk.NFTType.ERC1155, // todo: sdk.NFTType.ERC721 57 | gasPrice: LOOPRING_EXPORTED_ACCOUNT.gasPrice, 58 | gasLimit: LOOPRING_EXPORTED_ACCOUNT.gasLimit, 59 | chainId: sdk.ChainId.GOERLI, 60 | nonce, 61 | sendByMetaMask: true, 62 | }); 63 | console.log(`nonce: ${nonce} approveNFT: ${approveNFT?.result}`); 64 | } 65 | ``` 66 | 67 | *** 68 | 69 | ## Step 3. nonce 70 | 71 | ```ts 72 | const nonce = await sdk.getNonce(web3, LOOPRING_EXPORTED_ACCOUNT.address); 73 | 74 | console.log( 75 | `deposit: NFT, gasPrice: ${LOOPRING_EXPORTED_ACCOUNT.gasPrice}, ` 76 | ); 77 | ``` 78 | 79 | *** 80 | 81 | ## Step 4. depositNFT 82 | 83 | ```ts 84 | const response = await LoopringAPI.nftAPI.depositNFT({ 85 | web3, 86 | from: LOOPRING_EXPORTED_ACCOUNT.address, 87 | exchangeAddress: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 88 | nftType: sdk.NFTType.ERC1155, // todo: sdk.NFTType.ERC721 89 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 90 | nftId: LOOPRING_EXPORTED_ACCOUNT.nftId, 91 | amount: 2, // todo:when sdk.NFTType.ERC721 amount: 1, 92 | gasPrice: LOOPRING_EXPORTED_ACCOUNT.gasPrice, 93 | gasLimit: LOOPRING_EXPORTED_ACCOUNT.gasLimit + 100000, 94 | chainId: sdk.ChainId.GOERLI, 95 | nonce, 96 | sendByMetaMask: true, 97 | }); 98 | console.log(`nonce: ${nonce} deposit NFT ERC1155: `, response); 99 | 100 | ``` 101 | -------------------------------------------------------------------------------- /src/tests/demo/deposit/depositNFT.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_TIMEOUT, 3 | LOOPRING_EXPORTED_ACCOUNT, 4 | LoopringAPI, 5 | TOKEN_INFO, 6 | web3, 7 | } from "../../MockData"; 8 | import * as sdk from "../../../index"; 9 | describe("depositNFT", function () { 10 | beforeEach(async () => { 11 | jest.setTimeout(DEFAULT_TIMEOUT * 3); 12 | LOOPRING_EXPORTED_ACCOUNT.gasPrice = ( 13 | await LoopringAPI.exchangeAPI.getGasPrice() 14 | ).gasPrice; 15 | }, DEFAULT_TIMEOUT); 16 | it( 17 | "deposit NFTAction ERC1155", 18 | async () => { 19 | // Step 1. getNFTBalance & getEthBalances 20 | const { ethBalance } = await LoopringAPI.exchangeAPI.getEthBalances({ 21 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 22 | }); 23 | const nftBalance = await LoopringAPI.nftAPI.getNFTBalance({ 24 | web3, 25 | account: LOOPRING_EXPORTED_ACCOUNT.address, 26 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 27 | nftId: LOOPRING_EXPORTED_ACCOUNT.nftId, 28 | nftType: sdk.NFTType.ERC1155, 29 | }); 30 | 31 | // Step 2. isApprovedForAll 32 | const isApprovedForAll = await LoopringAPI.nftAPI.isApprovedForAll({ 33 | web3, 34 | from: LOOPRING_EXPORTED_ACCOUNT.address, 35 | exchangeAddress: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 36 | nftType: sdk.NFTType.ERC1155, 37 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 38 | }); 39 | console.log(`check is approveNFT`, isApprovedForAll); 40 | 41 | // Step 3. approveNFT All 42 | if (!isApprovedForAll) { 43 | const nonce = await sdk.getNonce( 44 | web3, 45 | LOOPRING_EXPORTED_ACCOUNT.address 46 | ); 47 | const approveNFT = await LoopringAPI.nftAPI.approveNFT({ 48 | web3, 49 | from: LOOPRING_EXPORTED_ACCOUNT.address, 50 | depositAddress: LOOPRING_EXPORTED_ACCOUNT.depositAddress, 51 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 52 | nftType: sdk.NFTType.ERC1155, 53 | gasPrice: LOOPRING_EXPORTED_ACCOUNT.gasPrice, 54 | gasLimit: LOOPRING_EXPORTED_ACCOUNT.gasLimit, 55 | chainId: sdk.ChainId.GOERLI, 56 | nonce, 57 | sendByMetaMask: true, 58 | }); 59 | console.log(`nonce: ${nonce} approveNFT: ${approveNFT?.result}`); 60 | } 61 | 62 | // Step 4. nonce 63 | const nonce = await sdk.getNonce(web3, LOOPRING_EXPORTED_ACCOUNT.address); 64 | 65 | console.log( 66 | `deposit: NFT, gasPrice: ${LOOPRING_EXPORTED_ACCOUNT.gasPrice}, ` 67 | ); 68 | // Step 5. depositNFT 69 | const response = await LoopringAPI.nftAPI.depositNFT({ 70 | web3, 71 | from: LOOPRING_EXPORTED_ACCOUNT.address, 72 | exchangeAddress: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 73 | nftType: sdk.NFTType.ERC1155, 74 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 75 | nftId: LOOPRING_EXPORTED_ACCOUNT.nftId, 76 | amount: 1, 77 | gasPrice: LOOPRING_EXPORTED_ACCOUNT.gasPrice, 78 | gasLimit: LOOPRING_EXPORTED_ACCOUNT.gasLimit + 100000, 79 | chainId: sdk.ChainId.GOERLI, 80 | nonce, 81 | sendByMetaMask: true, 82 | }); 83 | 84 | console.log(`nonce: ${nonce} deposit NFT ERC1155: `, response); 85 | }, 86 | DEFAULT_TIMEOUT 87 | ); 88 | 89 | // it( 90 | // "deposit NFTAction ERC721", 91 | // async () => { 92 | // const nonce = await sdk.getNonce( 93 | // web3, 94 | // LOOPRING_EXPORTED_ACCOUNT.address 95 | // ); 96 | // const response = await LoopringAPI.nftAPI.depositNFT({ 97 | // web3, 98 | // from: LOOPRING_EXPORTED_ACCOUNT.address, 99 | // exchangeAddress: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 100 | // nftType: NFTType.ERC721, 101 | // tokenAddress: '// TODO:', 102 | // nftId: '// TODO:', 103 | // amount: 1, 104 | // gasPrice: LOOPRING_EXPORTED_ACCOUNT.gasPrice, 105 | // gasLimit: LOOPRING_EXPORTED_ACCOUNT.gasLimit, 106 | // chainId: ChainId.GOERLI, 107 | // nonce, 108 | // sendByMetaMask: true, 109 | // }); 110 | // 111 | // console.log(`nonce: ${nonce} deposit NFT ERC1155: `, response); 112 | // }, 113 | // DEFAULT_TIMEOUT 114 | // ); 115 | }); 116 | -------------------------------------------------------------------------------- /src/tests/demo/exchange/webSocket.md: -------------------------------------------------------------------------------- 1 | #WebSocket Command 2 | Definition: Loopring L2 websocket 3 | 4 | ### Loopring L2 websocket topic type: 5 | WsTopicType 6 | - `account` 7 | - `orderbook` 8 | - `mixorder` 9 | - `mixtrade` 10 | - `ticker` 11 | - `candlestick` 12 | - `ammpool` 13 | 14 | ## getWsKey (required by account related socket) 15 | ```ts 16 | const response = await LoopringAPI.wsAPI.getWsKey(); 17 | console.log(response); 18 | ``` 19 | ## getOrderBookArg 20 | ```ts 21 | const arg1 = sdk.getMixOrderArg({ market: "LRC-ETH", level: 50 }); 22 | console.log(arg1); 23 | 24 | const arg2 = sdk.getOrderBookArg({ 25 | market: "LRC-ETH", 26 | level: 50, 27 | count: 40, 28 | snapshot: false, 29 | }); 30 | console.log(arg2); 31 | ``` -------------------------------------------------------------------------------- /src/tests/demo/exchange/webSocket.test.ts: -------------------------------------------------------------------------------- 1 | import * as sdk from "../../../index"; 2 | import { DEFAULT_TIMEOUT, LoopringAPI } from "../../MockData"; 3 | 4 | /** 5 | * @define WsTopicType 6 | * `account`, 7 | * `order`, 8 | * `orderbook`, 9 | * `mixorder`, 10 | * `trade`, 11 | * `ticker`, 12 | * `candlestick`, 13 | * `ammpool`, 14 | * 15 | */ 16 | describe("websocket", function () { 17 | it( 18 | "getWsKey", 19 | async () => { 20 | const response = await LoopringAPI.wsAPI.getWsKey(); 21 | console.log(response); 22 | }, 23 | DEFAULT_TIMEOUT 24 | ); 25 | 26 | it( 27 | "getOrderBookArg", 28 | async () => { 29 | const arg1 = sdk.getMixOrderArg({ market: "LRC-ETH", level: 50 }); 30 | console.log(arg1); 31 | 32 | const arg2 = sdk.getOrderBookArg({ 33 | market: "LRC-ETH", 34 | level: 50, 35 | count: 40, 36 | snapshot: false, 37 | }); 38 | console.log(arg2); 39 | }, 40 | DEFAULT_TIMEOUT 41 | ); 42 | }); 43 | -------------------------------------------------------------------------------- /src/tests/demo/transfer/transferERC20.md: -------------------------------------------------------------------------------- 1 | # Transfer ERC20 2 | Definition: Send ERC20 tokens to other account on Loopring L2, 3 | > trade value should with decimals `sdk.toBig(value).times("1e" + TOKEN_INFO.tokenMap.LRC.decimals)` 4 | 5 | *** 6 | ## Step 1. get account Info 7 | const { exchangeInfo } = await LoopringAPI.exchangeAPI.getExchangeInfo(); 8 | const LOOPRING_EXPORTED_ACCOUNT.exchangeAddress = exchangeInfo; 9 | 10 | ```ts 11 | const { accInfo } = await LoopringAPI.exchangeAPI.getAccount({ 12 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 13 | }); 14 | console.log("accInfo:", accInfo); 15 | 16 | ``` 17 | *** 18 | ## Step 2. get eddsaKey 19 | ```ts 20 | const eddsaKey = await signatureKeyPairMock(accInfo); 21 | console.log("eddsaKey:", eddsaKey.sk); 22 | ``` 23 | *** 24 | ## Step 3. get apikey 25 | ```ts 26 | const { apiKey } = await LoopringAPI.userAPI.getUserApiKey( 27 | { 28 | accountId: accInfo.accountId, 29 | }, 30 | eddsaKey.sk 31 | ); 32 | console.log("apiKey:", apiKey); 33 | const { userBalances } = await LoopringAPI.userAPI.getUserBalances( 34 | { accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, tokens: "" }, 35 | apiKey 36 | ); 37 | ``` 38 | 39 | *** 40 | ## Step 4. get storageId 41 | ```ts 42 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 43 | { 44 | accountId: accInfo.accountId, 45 | sellTokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 46 | }, 47 | apiKey 48 | ); 49 | console.log("storageId:", storageId); 50 | ``` 51 | 52 | *** 53 | ## Step 5. get fee 54 | ```ts 55 | const fee = await LoopringAPI.userAPI.getOffchainFeeAmt({ 56 | accountId: accInfo.accountId, 57 | requestType: sdk.OffchainFeeReqType.TRANSFER, 58 | }, apiKey); 59 | console.log("fee:", fee); 60 | ``` 61 | *** 62 | ## Step 6. transfer 63 | ```ts 64 | const transferResult = await LoopringAPI.userAPI.submitInternalTransfer({ 65 | request: { 66 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 67 | payerAddr: accInfo.owner, 68 | payerId: accInfo.accountId, 69 | payeeAddr: LOOPRING_EXPORTED_ACCOUNT.address2, 70 | payeeId: LOOPRING_EXPORTED_ACCOUNT.accountId2, 71 | storageId: storageId.offchainId, 72 | token: { 73 | tokenId: TOKEN_INFO.tokenMap.LRC.tokenId, 74 | volume: LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue.toString(), 75 | }, 76 | maxFee: { 77 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 78 | volume: fee.fees["LRC"].fee ?? "9400000000000000000", 79 | }, 80 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 81 | /* 82 | * when payPayeeUpdateAccount = ture, will help payee active account, 83 | * maxFee from should: 84 | * const fee = await LoopringAPI.userAPI.getOffchainFeeAmt( 85 | * { 86 | * accountId: accInfo.accountId, 87 | * requestType: sdk.OffchainFeeReqType.TRANSFER_AND_UPDATE_ACCOUNT, 88 | * }, 89 | * apiKey 90 | * ); 91 | */ 92 | payPayeeUpdateAccount: false, 93 | }, 94 | web3, 95 | chainId: sdk.ChainId.GOERLI, 96 | walletType: sdk.ConnectorNames.Trezor, 97 | eddsaKey: eddsaKey.sk, 98 | apiKey: apiKey, 99 | }); 100 | console.log("transferResult:", transferResult); 101 | ``` -------------------------------------------------------------------------------- /src/tests/demo/transfer/transferERC20.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_TIMEOUT, 3 | LOOPRING_EXPORTED_ACCOUNT, 4 | LoopringAPI, 5 | TOKEN_INFO, 6 | signatureKeyPairMock, 7 | web3, 8 | } from "../../MockData"; 9 | import * as sdk from "../../../index"; 10 | import * as sign_tools from "../../../api/sign/sign_tools"; 11 | import { myLog } from "../../../utils/log_tools"; 12 | describe("Transfer", function () { 13 | it( 14 | "submitInternalTransfer", 15 | async () => { 16 | /* 17 | * @replace LOOPRING_EXPORTED_ACCOUNT.exchangeAddress = exchangeInfo.exchangeAddress 18 | * const { exchangeInfo } = await LoopringAPI.exchangeAPI.getExchangeInfo(); 19 | */ 20 | // Step 1. get account info 21 | const { accInfo } = await LoopringAPI.exchangeAPI.getAccount({ 22 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 23 | }); 24 | console.log("accInfo:", accInfo); 25 | 26 | // Step 2. eddsaKey 27 | const eddsaKey = await signatureKeyPairMock(accInfo); 28 | console.log("eddsaKey:", eddsaKey.sk); 29 | 30 | // Step 3. get apikey 31 | const { apiKey } = await LoopringAPI.userAPI.getUserApiKey( 32 | { 33 | accountId: accInfo.accountId, 34 | }, 35 | eddsaKey.sk 36 | ); 37 | console.log("apiKey:", apiKey); 38 | 39 | // Step 4. get storageId 40 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 41 | { 42 | accountId: accInfo.accountId, 43 | sellTokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 44 | }, 45 | apiKey 46 | ); 47 | console.log("storageId:", storageId); 48 | 49 | // Step 5. get fee 50 | const fee = await LoopringAPI.userAPI.getOffchainFeeAmt( 51 | { 52 | accountId: accInfo.accountId, 53 | requestType: sdk.OffchainFeeReqType.TRANSFER, 54 | }, 55 | apiKey 56 | ); 57 | console.log("fee:", fee); 58 | const request = { 59 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 60 | payerAddr: accInfo.owner, 61 | payerId: accInfo.accountId, 62 | payeeAddr: LOOPRING_EXPORTED_ACCOUNT.address2, 63 | payeeId: LOOPRING_EXPORTED_ACCOUNT.accountId2, 64 | storageId: storageId.offchainId, 65 | token: { 66 | tokenId: TOKEN_INFO.tokenMap.LRC.tokenId, 67 | volume: LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue.toString(), 68 | }, 69 | maxFee: { 70 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 71 | volume: fee.fees["LRC"].fee ?? "9400000000000000000", 72 | }, 73 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 74 | /* 75 | * when payPayeeUpdateAccount = ture, will help payee active account, 76 | * maxFee from should: 77 | * const fee = await LoopringAPI.userAPI.getOffchainFeeAmt( 78 | * { 79 | * accountId: accInfo.accountId, 80 | * requestType: sdk.OffchainFeeReqType.TRANSFER_AND_UPDATE_ACCOUNT, 81 | * }, 82 | * apiKey 83 | * ); 84 | */ 85 | payPayeeUpdateAccount: false, 86 | }; 87 | const hash = sign_tools.get_EddsaSig_Transfer(request, "").hash; 88 | myLog("hash", hash); 89 | // Step 6. transfer 90 | const transferResult = await LoopringAPI.userAPI.submitInternalTransfer({ 91 | request, 92 | web3, 93 | chainId: sdk.ChainId.GOERLI, 94 | walletType: sdk.ConnectorNames.Unknown, 95 | eddsaKey: eddsaKey.sk, 96 | apiKey: apiKey, 97 | }); 98 | console.log("transferResult:", transferResult); 99 | }, 100 | DEFAULT_TIMEOUT 101 | ); 102 | }); 103 | -------------------------------------------------------------------------------- /src/tests/demo/transfer/transferNFT.md: -------------------------------------------------------------------------------- 1 | # Transfer NFT 2 | Definition: Send NFT to other account on Loopring L2 3 | 4 | *** 5 | ## Step 1. get account Info 6 | ```ts 7 | const { exchangeInfo } = await LoopringAPI.exchangeAPI.getExchangeInfo(); 8 | const LOOPRING_EXPORTED_ACCOUNT.exchangeAddress = exchangeInfo; 9 | const { accInfo } = await LoopringAPI.exchangeAPI.getAccount({ 10 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 11 | }); 12 | ``` 13 | 14 | *** 15 | ## Step 2. get eddsaKey 16 | ```ts 17 | const eddsaKey = await signatureKeyPairMock(accInfo); 18 | console.log("eddsaKey:", eddsaKey.sk); 19 | ``` 20 | 21 | *** 22 | ## Step 3. get apiKey 23 | ```ts 24 | const { apiKey } = await LoopringAPI.userAPI.getUserApiKey({ 25 | accountId: accInfo.accountId}, eddsaKey.sk 26 | ); 27 | console.log("apiKey:", apiKey); 28 | const { userNFTBalances } = await LoopringAPI.userAPI.getUserNFTBalances( 29 | { accountId: accInfo.accountId, limit: 20 }, 30 | apiKey 31 | ); 32 | ``` 33 | 34 | *** 35 | ##Step 4. get storageId 36 | ```ts 37 | const storageId = await LoopringAPI.userAPI.getNextStorageId({ 38 | accountId: accInfo.accountId, 39 | sellTokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 40 | }, apiKey); 41 | ``` 42 | 43 | *** 44 | ## Step 5. get fee 45 | ```ts 46 | const transferResult = await LoopringAPI.userAPI.submitNFTInTransfer({ 47 | request: { 48 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 49 | fromAccountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 50 | fromAddress: LOOPRING_EXPORTED_ACCOUNT.address, 51 | toAccountId: 0, // toAccountId is not required, input 0 as default 52 | toAddress: LOOPRING_EXPORTED_ACCOUNT.address2, 53 | token: { 54 | tokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 55 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 56 | amount: "1", 57 | }, 58 | maxFee: { 59 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 60 | amount: fee.fees["LRC"].fee ?? "9400000000000000000", 61 | }, 62 | storageId: storageId.offchainId, 63 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 64 | /* 65 | * when payPayeeUpdateAccount = ture, will help payee active account, 66 | * maxFee from: 67 | * const fee = await LoopringAPI.userAPI.getNFTOffchainFeeAmt( 68 | * { 69 | * accountId: accInfo.accountId, 70 | * requestType: sdk.OffchainFeeReqType.NFT_TRANSFER_AND_UPDATE_ACCOUNT, 71 | * }, 72 | * apiKey 73 | * ); 74 | */ 75 | payPayeeUpdateAccount: false, 76 | }, 77 | web3, 78 | chainId: sdk.ChainId.GOERLI, 79 | walletType: sdk.ConnectorNames.Unknown, 80 | eddsaKey: eddsaKey.sk, 81 | apiKey, 82 | }); 83 | console.log("fee:", fee); 84 | ``` 85 | 86 | *** 87 | ## Step 6. Transfer NFT 88 | ```ts 89 | const transferResult = await LoopringAPI.userAPI.submitNFTInTransfer({ 90 | request: { 91 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 92 | fromAccountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 93 | fromAddress: LOOPRING_EXPORTED_ACCOUNT.address, 94 | toAccountId: 0, // toAccountId is not required, input 0 as default 95 | toAddress: LOOPRING_EXPORTED_ACCOUNT.address2, 96 | token: { 97 | tokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 98 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 99 | amount: "1", 100 | }, 101 | maxFee: { 102 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 103 | amount: fee.fees["LRC"].fee ?? "9400000000000000000", 104 | }, 105 | storageId: storageId.offchainId, 106 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 107 | }, 108 | web3, 109 | chainId: sdk.ChainId.GOERLI, 110 | walletType: sdk.ConnectorNames.Unknown, 111 | eddsaKey: eddsaKey.sk, 112 | apiKey, 113 | }); 114 | console.log("transfer Result:", transferResult); 115 | ``` -------------------------------------------------------------------------------- /src/tests/demo/transfer/transferNFT.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_TIMEOUT, 3 | LOOPRING_EXPORTED_ACCOUNT, 4 | LoopringAPI, 5 | web3, 6 | TOKEN_INFO, 7 | signatureKeyPairMock, 8 | } from "../../MockData"; 9 | import * as sdk from "../../../index"; 10 | 11 | describe("TransferNFT", function () { 12 | it( 13 | "submitNFTInTransfer", 14 | async () => { 15 | /* 16 | * @replace LOOPRING_EXPORTED_ACCOUNT.exchangeAddress = exchangeInfo.exchangeAddress 17 | * const { exchangeInfo } = await LoopringAPI.exchangeAPI.getExchangeInfo(); 18 | */ 19 | // Step 1. getAccount 20 | const { accInfo } = await LoopringAPI.exchangeAPI.getAccount({ 21 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 22 | }); 23 | console.log("accInfo:", accInfo); 24 | 25 | // Step 2. eddsaKey 26 | const eddsaKey = await signatureKeyPairMock(accInfo); 27 | console.log("eddsaKey:", eddsaKey.sk); 28 | 29 | // Step 3. apiKey 30 | const { apiKey } = await LoopringAPI.userAPI.getUserApiKey( 31 | { 32 | accountId: accInfo.accountId, 33 | }, 34 | eddsaKey.sk 35 | ); 36 | console.log("apiKey:", apiKey); 37 | 38 | // Step 4. storageId 39 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 40 | { 41 | accountId: accInfo.accountId, 42 | sellTokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 43 | }, 44 | apiKey 45 | ); 46 | console.log("storageId:", storageId); 47 | 48 | // Step 5. fee 49 | const fee = await LoopringAPI.userAPI.getNFTOffchainFeeAmt( 50 | { 51 | accountId: accInfo.accountId, 52 | requestType: sdk.OffchainNFTFeeReqType.NFT_TRANSFER, 53 | amount: "0", 54 | }, 55 | apiKey 56 | ); 57 | console.log("fee:", fee); 58 | 59 | const transferResult = await LoopringAPI.userAPI.submitNFTInTransfer({ 60 | request: { 61 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 62 | fromAccountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 63 | fromAddress: LOOPRING_EXPORTED_ACCOUNT.address, 64 | toAccountId: 0, // toAccountId is not required, input 0 as default 65 | toAddress: LOOPRING_EXPORTED_ACCOUNT.address2, 66 | token: { 67 | tokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 68 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 69 | amount: "1", 70 | }, 71 | maxFee: { 72 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 73 | amount: fee.fees["LRC"].fee ?? "9400000000000000000", 74 | }, 75 | storageId: storageId.offchainId, 76 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 77 | /* 78 | * when payPayeeUpdateAccount = ture, will help payee active account, 79 | * maxFee from: 80 | * const fee = await LoopringAPI.userAPI.getNFTOffchainFeeAmt( 81 | * { 82 | * accountId: accInfo.accountId, 83 | * requestType: sdk.OffchainFeeReqType.NFT_TRANSFER_AND_UPDATE_ACCOUNT, 84 | * }, 85 | * apiKey 86 | * ); 87 | */ 88 | payPayeeUpdateAccount: false, 89 | }, 90 | web3, 91 | chainId: sdk.ChainId.GOERLI, 92 | walletType: sdk.ConnectorNames.Unknown, 93 | eddsaKey: eddsaKey.sk, 94 | apiKey, 95 | }); 96 | console.log("transfer Result:", transferResult); 97 | }, 98 | DEFAULT_TIMEOUT 99 | ); 100 | }); 101 | -------------------------------------------------------------------------------- /src/tests/demo/withdraw/withdrawERC20.md: -------------------------------------------------------------------------------- 1 | # Withdraw ERC20 2 | 3 | Definition: Loopring L2 withdraw ERC20 to Ethereum L1, 4 | > trade value should with decimals `sdk.toBig(value).times("1e" + TOKEN_INFO.tokenMap.LRC.decimals)` 5 | 6 | *** 7 | 8 | ## Step 1. getAccount 9 | 10 | ```ts 11 | const {accInfo} = await LoopringAPI.exchangeAPI.getAccount({ 12 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 13 | }); 14 | console.log("accInfo:", accInfo); 15 | ``` 16 | 17 | ##Step 2. eddsaKey 18 | 19 | ```ts 20 | const eddsaKey = await signatureKeyPairMock(accInfo); 21 | console.log("eddsaKey:", eddsaKey.sk); 22 | ``` 23 | 24 | *** 25 | 26 | ## Step 3. apiKey 27 | 28 | ```ts 29 | const {apiKey} = await LoopringAPI.userAPI.getUserApiKey({ 30 | accountId: accInfo.accountId, 31 | }, 32 | eddsaKey.sk 33 | ); 34 | console.log("apiKey:", apiKey); 35 | 36 | ``` 37 | 38 | *** 39 | 40 | ## Step 4. storageId 41 | 42 | ```ts 43 | const storageId = await LoopringAPI.userAPI.getNextStorageId({ 44 | accountId: accInfo.accountId, 45 | sellTokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 46 | }, 47 | apiKey 48 | ); 49 | console.log("storageId:", storageId); 50 | 51 | ``` 52 | 53 | *** 54 | 55 | ## Step 5. fee 56 | 57 | ```ts 58 | const fee = await LoopringAPI.userAPI.getOffchainFeeAmt({ 59 | accountId: accInfo.accountId, 60 | requestType: sdk.OffchainFeeReqType.OFFCHAIN_WITHDRAWAL, 61 | tokenSymbol: TOKEN_INFO.tokenMap["LRC"].symbol, 62 | }, 63 | apiKey 64 | ); 65 | console.log("fee:", fee); 66 | 67 | ``` 68 | 69 | *** 70 | 71 | ## Step 6. withdraw 72 | 73 | ```ts 74 | const response = await LoopringAPI.userAPI.submitOffchainWithdraw({ 75 | request: { 76 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 77 | accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 78 | counterFactualInfo: undefined, 79 | fastWithdrawalMode: false, 80 | hashApproved: "", 81 | maxFee: { 82 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 83 | volume: fee.fees["LRC"].fee ?? "9400000000000000000", 84 | }, 85 | minGas: 0, 86 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 87 | to: LOOPRING_EXPORTED_ACCOUNT.address, 88 | storageId: 0, 89 | token: { 90 | tokenId: TOKEN_INFO.tokenMap.LRC.tokenId, 91 | volume: LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue.toString(), 92 | }, 93 | validUntil: 0, 94 | }, 95 | web3, 96 | chainId: sdk.ChainId.GOERLI, 97 | walletType: sdk.ConnectorNames.MetaMask, 98 | eddsaKey: eddsaKey.sk, 99 | apiKey, 100 | }); 101 | console.log("response:", response); 102 | ``` -------------------------------------------------------------------------------- /src/tests/demo/withdraw/withdrawERC20.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_TIMEOUT, 3 | LOOPRING_EXPORTED_ACCOUNT, 4 | LoopringAPI, 5 | web3, 6 | TOKEN_INFO, 7 | signatureKeyPairMock, 8 | } from "../../MockData"; 9 | import * as sdk from "../../../index"; 10 | 11 | describe("Withdraw", function () { 12 | beforeEach(async () => { 13 | jest.setTimeout(DEFAULT_TIMEOUT * 3); 14 | }, DEFAULT_TIMEOUT); 15 | 16 | it( 17 | "submitWithdraw", 18 | async () => { 19 | /* 20 | * @replace LOOPRING_EXPORTED_ACCOUNT.exchangeAddress = exchangeInfo.exchangeAddress 21 | * const { exchangeInfo } = await LoopringAPI.exchangeAPI.getExchangeInfo(); 22 | */ 23 | // Step 1. getAccount 24 | const { accInfo } = await LoopringAPI.exchangeAPI.getAccount({ 25 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 26 | }); 27 | console.log("accInfo:", accInfo); 28 | 29 | // Step 2. eddsaKey 30 | const eddsaKey = await signatureKeyPairMock(accInfo); 31 | console.log("eddsaKey:", eddsaKey.sk); 32 | 33 | // Step 3. apiKey 34 | const { apiKey } = await LoopringAPI.userAPI.getUserApiKey( 35 | { 36 | accountId: accInfo.accountId, 37 | }, 38 | eddsaKey.sk 39 | ); 40 | console.log("apiKey:", apiKey); 41 | 42 | // Step 4. storageId 43 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 44 | { 45 | accountId: accInfo.accountId, 46 | sellTokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 47 | }, 48 | apiKey 49 | ); 50 | console.log("storageId:", storageId); 51 | 52 | // Step 5. fee 53 | const fee = await LoopringAPI.userAPI.getOffchainFeeAmt( 54 | { 55 | accountId: accInfo.accountId, 56 | requestType: sdk.OffchainFeeReqType.OFFCHAIN_WITHDRAWAL, 57 | tokenSymbol: TOKEN_INFO.tokenMap["LRC"].symbol, 58 | }, 59 | apiKey 60 | ); 61 | console.log("fee:", fee); 62 | 63 | // Step 6. withdraw 64 | const response = await LoopringAPI.userAPI.submitOffchainWithdraw({ 65 | request: { 66 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 67 | accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 68 | counterFactualInfo: undefined, 69 | fastWithdrawalMode: false, 70 | hashApproved: "", 71 | maxFee: { 72 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 73 | volume: fee.fees["LRC"].fee ?? "9400000000000000000", 74 | }, 75 | minGas: 0, 76 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 77 | to: LOOPRING_EXPORTED_ACCOUNT.address, 78 | storageId: storageId.offchainId, 79 | token: { 80 | tokenId: TOKEN_INFO.tokenMap.LRC.tokenId, 81 | volume: LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue.toString(), 82 | }, 83 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 84 | }, 85 | web3, 86 | chainId: sdk.ChainId.GOERLI, 87 | walletType: sdk.ConnectorNames.Unknown, //sdk.ConnectorNames.MetaMask UT only support perosonal sign, no V4 88 | eddsaKey: eddsaKey.sk, 89 | apiKey, 90 | }); 91 | console.log("response:", response); 92 | }, 93 | DEFAULT_TIMEOUT * 3 94 | ); 95 | }); 96 | -------------------------------------------------------------------------------- /src/tests/demo/withdraw/withdrawNFT.md: -------------------------------------------------------------------------------- 1 | # Withdraw NFT 2 | 3 | Definition: Loopring L2 withdraw NFT to Ethereum L1 4 | 5 | *** 6 | 7 | ## Step 1. getAccount 8 | 9 | ```ts 10 | const {accInfo} = await LoopringAPI.exchangeAPI.getAccount({ 11 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 12 | }); 13 | console.log("accInfo:", accInfo); 14 | ``` 15 | 16 | *** 17 | 18 | ## Step 2. eddsaKey 19 | 20 | ```ts 21 | 22 | const eddsaKey = await signatureKeyPairMock(accInfo); 23 | console.log("eddsaKey:", eddsaKey.sk); 24 | 25 | ``` 26 | 27 | *** 28 | 29 | ## Step 3. apiKey 30 | 31 | ```ts 32 | const {apiKey} = await LoopringAPI.userAPI.getUserApiKey( 33 | { 34 | accountId: accInfo.accountId, 35 | }, 36 | eddsaKey.sk 37 | ); 38 | console.log("apiKey:", apiKey); 39 | ``` 40 | 41 | *** 42 | 43 | ## Step 4. storageId 44 | 45 | ```ts 46 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 47 | { 48 | accountId: accInfo.accountId, 49 | sellTokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 50 | }, 51 | apiKey 52 | ); 53 | console.log("storageId:", storageId); 54 | 55 | //Step 5. getUserNFTBalances 56 | const {userNFTBalances} = await LoopringAPI.userAPI.getUserNFTBalances( 57 | {accountId: LOOPRING_EXPORTED_ACCOUNT.accountId}, 58 | apiKey 59 | ); 60 | const tokenInfo = userNFTBalances.find( 61 | (item) => 62 | item.tokenAddress?.toLowerCase() === 63 | LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress.toLowerCase() && 64 | item.nftId && 65 | web3.utils.hexToNumberString(item.nftId) === 66 | LOOPRING_EXPORTED_ACCOUNT.nftTokenId.toString() 67 | ); 68 | ``` 69 | 70 | *** 71 | 72 | ## Step 5. fee 73 | 74 | ```ts 75 | const fee = await LoopringAPI.userAPI.getNFTOffchainFeeAmt( 76 | { 77 | accountId: accInfo.accountId, 78 | requestType: sdk.OffchainNFTFeeReqType.NFT_WITHDRAWAL, 79 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 80 | deployInWithdraw: 81 | tokenInfo?.deploymentStatus === DEPLOYMENT_STATUS.NOT_DEPLOYED, // when token is not deploy the fee is diff 82 | }, 83 | apiKey 84 | ); 85 | console.log("fee:", fee); 86 | ``` 87 | 88 | *** 89 | 90 | ## Step 6. withdraw 91 | 92 | ```ts 93 | const response = await LoopringAPI.userAPI.submitNFTWithdraw({ 94 | request: { 95 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 96 | accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 97 | counterFactualInfo: undefined, 98 | hashApproved: "", 99 | maxFee: { 100 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 101 | amount: fee.fees["LRC"].fee ?? "9400000000000000000", 102 | }, 103 | minGas: 0, 104 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 105 | to: LOOPRING_EXPORTED_ACCOUNT.address, 106 | storageId: 0, 107 | token: { 108 | tokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 109 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 110 | amount: "1", 111 | }, 112 | validUntil: 0, 113 | }, 114 | web3, 115 | chainId: sdk.ChainId.GOERLI, 116 | walletType: sdk.ConnectorNames.MetaMask, 117 | eddsaKey: eddsaKey.sk, 118 | apiKey, 119 | }); 120 | console.log("response:", response); 121 | ``` -------------------------------------------------------------------------------- /src/tests/demo/withdraw/withdrawNFT.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_TIMEOUT, 3 | LOOPRING_EXPORTED_ACCOUNT, 4 | LoopringAPI, 5 | web3, 6 | TOKEN_INFO, 7 | signatureKeyPairMock, 8 | } from "../../MockData"; 9 | import * as sdk from "../../../index"; 10 | import { DEPLOYMENT_STATUS } from "../../../index"; 11 | 12 | describe("WithdrawNFT", function () { 13 | it( 14 | "submitNFTWithdraw", 15 | async () => { 16 | /* 17 | * @replace LOOPRING_EXPORTED_ACCOUNT.exchangeAddress = exchangeInfo.exchangeAddress 18 | * const { exchangeInfo } = await LoopringAPI.exchangeAPI.getExchangeInfo(); 19 | */ 20 | // Step 1. getAccount 21 | const { accInfo } = await LoopringAPI.exchangeAPI.getAccount({ 22 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 23 | }); 24 | console.log("accInfo:", accInfo); 25 | 26 | // Step 2. eddsaKey 27 | const eddsaKey = await signatureKeyPairMock(accInfo); 28 | console.log("eddsaKey:", eddsaKey.sk); 29 | 30 | // Step 3. apiKey 31 | const { apiKey } = await LoopringAPI.userAPI.getUserApiKey( 32 | { 33 | accountId: accInfo.accountId, 34 | }, 35 | eddsaKey.sk 36 | ); 37 | console.log("apiKey:", apiKey); 38 | 39 | // Step 4. storageId 40 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 41 | { 42 | accountId: accInfo.accountId, 43 | sellTokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 44 | }, 45 | apiKey 46 | ); 47 | console.log("storageId:", storageId); 48 | 49 | //Step 5. getUserNFTBalances 50 | const { userNFTBalances } = await LoopringAPI.userAPI.getUserNFTBalances( 51 | { accountId: LOOPRING_EXPORTED_ACCOUNT.accountId }, 52 | apiKey 53 | ); 54 | const tokenInfo = userNFTBalances.find( 55 | (item) => 56 | item.tokenAddress?.toLowerCase() === 57 | LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress.toLowerCase() && 58 | item.nftId && 59 | web3.utils.hexToNumberString(item.nftId) === 60 | LOOPRING_EXPORTED_ACCOUNT.nftTokenId.toString() 61 | ); 62 | 63 | // Step 6. fee 64 | const fee = await LoopringAPI.userAPI.getNFTOffchainFeeAmt( 65 | { 66 | accountId: accInfo.accountId, 67 | requestType: sdk.OffchainNFTFeeReqType.NFT_WITHDRAWAL, 68 | tokenAddress: LOOPRING_EXPORTED_ACCOUNT.nftTokenAddress, 69 | deployInWithdraw: 70 | tokenInfo?.deploymentStatus === DEPLOYMENT_STATUS.NOT_DEPLOYED, // when token is not deploy the fee is diff 71 | }, 72 | apiKey 73 | ); 74 | console.log("fee:", fee); 75 | 76 | // Step 6. withdraw 77 | const response = await LoopringAPI.userAPI.submitNFTWithdraw({ 78 | request: { 79 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 80 | accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 81 | counterFactualInfo: undefined, 82 | hashApproved: "", 83 | maxFee: { 84 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 85 | amount: fee.fees["LRC"].fee ?? "9400000000000000000", 86 | }, 87 | minGas: 0, 88 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 89 | to: LOOPRING_EXPORTED_ACCOUNT.address, 90 | storageId: 0, 91 | token: { 92 | tokenId: LOOPRING_EXPORTED_ACCOUNT.nftTokenId, 93 | nftData: LOOPRING_EXPORTED_ACCOUNT.nftData, 94 | amount: "1", 95 | }, 96 | validUntil: 0, 97 | }, 98 | web3, 99 | chainId: sdk.ChainId.GOERLI, 100 | walletType: sdk.ConnectorNames.MetaMask, 101 | eddsaKey: eddsaKey.sk, 102 | apiKey, 103 | }); 104 | console.log("response:", response); 105 | }, 106 | DEFAULT_TIMEOUT * 3 107 | ); 108 | }); 109 | -------------------------------------------------------------------------------- /src/tests/unitTest/withdraw/forceWithdrawls.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_TIMEOUT, 3 | LOOPRING_EXPORTED_ACCOUNT, 4 | LoopringAPI, 5 | signatureKeyPairMock, 6 | TOKEN_INFO, 7 | web3, 8 | } from "../../MockData"; 9 | import * as sdk from "../../../index"; 10 | 11 | it( 12 | "submitForceWithdrawals", 13 | async () => { 14 | // Step 1. getAccount 15 | const { accInfo } = await LoopringAPI.exchangeAPI.getAccount({ 16 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 17 | }); 18 | console.log("accInfo:", accInfo); 19 | 20 | // Step 2. eddsaKey 21 | const eddsaKey = await signatureKeyPairMock(accInfo); 22 | console.log("eddsaKey:", eddsaKey.sk); 23 | 24 | // Step 3. apiKey 25 | const { apiKey } = await LoopringAPI.userAPI.getUserApiKey( 26 | { 27 | accountId: accInfo.accountId, 28 | }, 29 | eddsaKey.sk 30 | ); 31 | console.log("apiKey:", apiKey); 32 | 33 | // Step 4. fee 34 | const fee = await LoopringAPI.userAPI.getOffchainFeeAmt( 35 | { 36 | accountId: accInfo.accountId, 37 | requestType: sdk.OffchainFeeReqType.FORCE_WITHDRAWAL, 38 | amount: "0", 39 | }, 40 | apiKey 41 | ); 42 | console.log(fee); 43 | 44 | // Step 5. storageId 45 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 46 | { 47 | accountId: accInfo.accountId, 48 | sellTokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, // same as Step 7. transfer->token->tokenId 49 | }, 50 | apiKey 51 | ); 52 | 53 | // Step 6. broker 54 | const { broker } = await LoopringAPI.exchangeAPI.getAvailableBroker({ 55 | type: 1, 56 | }); 57 | 58 | // Step 7. Build transfer & Deploy 59 | const transfer = { 60 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 61 | payerAddr: LOOPRING_EXPORTED_ACCOUNT.address, 62 | payerId: LOOPRING_EXPORTED_ACCOUNT.accountId, 63 | payeeAddr: broker, 64 | // payeeAddr: LOOPRING_EXPORTED_ACCOUNT.address2, 65 | storageId: storageId.offchainId, 66 | token: { 67 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 68 | volume: fee.fees["LRC"].fee ?? "9400000000000000000", 69 | }, 70 | validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil, 71 | }; 72 | 73 | const response = await LoopringAPI.userAPI.submitForceWithdrawals({ 74 | request: { 75 | transfer, 76 | withdrawAddress: "0x7dF81E6683029011bBfefb5D57A1A364C3819110", //test for withdraw 77 | requesterAddress: accInfo.owner, 78 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 79 | }, 80 | web3, 81 | chainId: sdk.ChainId.GOERLI, 82 | walletType: sdk.ConnectorNames.Unknown, 83 | eddsaKey: eddsaKey.sk, 84 | apiKey: apiKey, 85 | }); 86 | 87 | console.log(response); 88 | }, 89 | DEFAULT_TIMEOUT 90 | ); 91 | -------------------------------------------------------------------------------- /src/tests/unitTest/withdraw/withdrawUT.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_TIMEOUT, 3 | LOOPRING_EXPORTED_ACCOUNT, 4 | LoopringAPI, 5 | web3, 6 | TOKEN_INFO, 7 | signatureKeyPairMock, 8 | } from "../../MockData"; 9 | import * as sdk from "../../../index"; 10 | 11 | describe("Withdraw NFTAction test", function () { 12 | // it( 13 | // "get_EddsaSig_Withdraw", 14 | // async () => { 15 | // const { accInfo } = await LoopringAPI.exchangeAPI.getAccount({ 16 | // owner: LOOPRING_EXPORTED_ACCOUNT.address, 17 | // }); 18 | // if (!accInfo) { 19 | // return; 20 | // } 21 | // /* 22 | // * @replace LOOPRING_EXPORTED_ACCOUNT.exchangeAddress = exchangeInfo.exchangeAddress 23 | // */ 24 | // const { exchangeInfo } = await LoopringAPI.exchangeAPI.getExchangeInfo(); 25 | // 26 | // const request: sdk.OffChainWithdrawalRequestV3 = { 27 | // exchange: exchangeInfo.exchangeAddress, 28 | // accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 29 | // counterFactualInfo: undefined, 30 | // fastWithdrawalMode: false, 31 | // hashApproved: "", 32 | // maxFee: { 33 | // tokenId: 1, 34 | // volume: "100000000000000000000", 35 | // }, 36 | // minGas: 0, 37 | // owner: LOOPRING_EXPORTED_ACCOUNT.address, 38 | // to: LOOPRING_EXPORTED_ACCOUNT.address, 39 | // storageId: 0, 40 | // token: { 41 | // tokenId: 1, 42 | // volume: "100000000000000000000", 43 | // }, 44 | // validUntil: 0, 45 | // }; 46 | // 47 | // const result = sdk.get_EddsaSig_OffChainWithdraw(request, ""); 48 | // console.log(`resultHash:`, result); 49 | // }, 50 | // DEFAULT_TIMEOUT 51 | // ); 52 | 53 | it( 54 | "forceWithdraw", 55 | async () => { 56 | /* 57 | * @replace LOOPRING_EXPORTED_ACCOUNT.exchangeAddress = exchangeInfo.exchangeAddress 58 | * const { exchangeInfo } = await LoopringAPI.exchangeAPI.getExchangeInfo(); 59 | */ 60 | // Step 1. getAccount 61 | const { accInfo } = await LoopringAPI.exchangeAPI.getAccount({ 62 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 63 | }); 64 | console.log("accInfo:", accInfo); 65 | 66 | // Step 2. eddsaKey 67 | const eddsaKey = await signatureKeyPairMock(accInfo); 68 | console.log("eddsaKey:", eddsaKey.sk); 69 | 70 | // Step 3. apiKey 71 | const { apiKey } = await LoopringAPI.userAPI.getUserApiKey( 72 | { 73 | accountId: accInfo.accountId, 74 | }, 75 | eddsaKey.sk 76 | ); 77 | console.log("apiKey:", apiKey); 78 | 79 | // Step 4. storageId 80 | const storageId = await LoopringAPI.userAPI.getNextStorageId( 81 | { 82 | accountId: accInfo.accountId, 83 | sellTokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 84 | }, 85 | apiKey 86 | ); 87 | console.log("storageId:", storageId); 88 | 89 | // Step 5. fee 90 | const fee = await LoopringAPI.userAPI.getOffchainFeeAmt( 91 | { 92 | accountId: accInfo.accountId, 93 | requestType: sdk.OffchainFeeReqType.FAST_OFFCHAIN_WITHDRAWAL, 94 | tokenSymbol: TOKEN_INFO.tokenMap.LRC.symbol, 95 | amount: LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue.toString(), 96 | }, 97 | apiKey 98 | ); 99 | console.log("fee:", fee); 100 | 101 | // Step 6. withdraw 102 | const response = await LoopringAPI.userAPI.submitOffchainWithdraw({ 103 | request: { 104 | exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress, 105 | accountId: LOOPRING_EXPORTED_ACCOUNT.accountId, 106 | counterFactualInfo: undefined, 107 | fastWithdrawalMode: true, 108 | hashApproved: "", 109 | maxFee: { 110 | tokenId: TOKEN_INFO.tokenMap["LRC"].tokenId, 111 | volume: fee.fees["LRC"].fee ?? "9400000000000000000", 112 | }, 113 | minGas: 0, 114 | owner: LOOPRING_EXPORTED_ACCOUNT.address, 115 | to: LOOPRING_EXPORTED_ACCOUNT.address, 116 | storageId: 0, 117 | token: { 118 | tokenId: TOKEN_INFO.tokenMap.LRC.tokenId, 119 | volume: LOOPRING_EXPORTED_ACCOUNT.tradeLRCValue.toString(), 120 | }, 121 | validUntil: 0, 122 | }, 123 | web3, 124 | chainId: sdk.ChainId.GOERLI, 125 | walletType: sdk.ConnectorNames.MetaMask, 126 | eddsaKey: eddsaKey.sk, 127 | apiKey, 128 | }); 129 | console.log("response:", response); 130 | }, 131 | DEFAULT_TIMEOUT * 3 132 | ); 133 | }); 134 | -------------------------------------------------------------------------------- /src/types.d.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | type Ethereum = any; 3 | interface Window { 4 | ethereum?: { 5 | [key: string]: boolean; 6 | isLoopring?: boolean; 7 | isImToken?: boolean; 8 | isMetaMask?: boolean; 9 | } & Ethereum; 10 | navigator: { userAgent: any } & any; 11 | // socketEventMap: {[key:string]:any 12 | // imageConfig:{[key:string]:any}|undefined 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/types/eddsa.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'ffjavascript' 2 | 3 | declare module 'blake-hash' 4 | 5 | declare module 'circomlib' 6 | 7 | declare module "blake2b"; 8 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./network_tools"; 2 | export * from "./symbol_tools"; 3 | export * from "./formatter"; 4 | export * from "./swap_calc_utils"; 5 | export type RequiredPart = Required<{ [K in keyof T]: Pick }> & T; 6 | -------------------------------------------------------------------------------- /src/utils/log_tools.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console, @typescript-eslint/ban-ts-comment */ 2 | let _myLog; 3 | 4 | if ( 5 | process.env.NODE_ENV !== "production" || 6 | // @ts-ignore 7 | (typeof window !== "undefined" && window?.___OhTrustDebugger___) 8 | ) { 9 | _myLog = console.log; 10 | } else { 11 | _myLog = function (message?: any, ...optionalParams: any[]) { 12 | return ""; 13 | }; 14 | } 15 | let _myError; 16 | if ( 17 | process.env.NODE_ENV !== "production" || 18 | // @ts-ignore 19 | (typeof window !== "undefined" && window?.___OhTrustDebugger___) 20 | ) { 21 | _myError = console.error; 22 | } else { 23 | _myError = function (message?: any, ...optionalParams: any[]) { 24 | return ""; 25 | }; 26 | } 27 | export const myLog = _myLog; 28 | export const myError = _myError; 29 | -------------------------------------------------------------------------------- /src/utils/network_tools.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | export const dumpError400 = (reason: any, src = '') => { 3 | if (src) { 4 | console.debug('src:', src) 5 | } 6 | if (reason && reason.response) { 7 | console.error(reason.response.data) 8 | } else { 9 | console.error(reason.message) 10 | } 11 | } 12 | 13 | export function sleep(milliseconds: number) { 14 | return new Promise((resolve) => setTimeout(resolve, milliseconds)) 15 | } 16 | -------------------------------------------------------------------------------- /src/utils/obj_tools.ts: -------------------------------------------------------------------------------- 1 | export const sortObject = (o: any) => 2 | Object.keys(o) 3 | .sort() 4 | .reduce((r: any, k) => ((r[k] = o[k]), r), {}); 5 | -------------------------------------------------------------------------------- /src/utils/symbol_tools.ts: -------------------------------------------------------------------------------- 1 | import { TokenInfo } from "defs"; 2 | 3 | const specialSymbols = ["ETH2x-FIL"]; 4 | 5 | export function getBaseQuote(symbol: string) { 6 | if (!symbol) { 7 | return { 8 | base: undefined, 9 | quote: undefined, 10 | }; 11 | } 12 | 13 | if (symbol.startsWith("AMM-")) { 14 | symbol = symbol.substr(4); 15 | } 16 | 17 | if (specialSymbols.length > 0) { 18 | for (let i = 0; i < specialSymbols.length; i++) { 19 | const ind = symbol.indexOf(specialSymbols[i]); 20 | if (ind >= 0) { 21 | if (ind === 0) { 22 | return { 23 | base: specialSymbols[i], 24 | quote: symbol.substr(symbol.lastIndexOf("-") + 1), 25 | }; 26 | } else { 27 | return { 28 | base: symbol.substr(0, symbol.indexOf("-")), 29 | quote: specialSymbols[i], 30 | }; 31 | } 32 | } 33 | } 34 | } 35 | 36 | const base = symbol.substr(0, symbol.indexOf("-")); 37 | const quote = symbol.substr(symbol.indexOf("-") + 1); 38 | 39 | return { 40 | base, 41 | quote, 42 | }; 43 | } 44 | 45 | export const getTokenInfoBySymbol = ( 46 | tokenSymbolMap: { [key: string]: TokenInfo }, 47 | symbol: string 48 | ) => { 49 | if (!tokenSymbolMap) { 50 | return undefined; 51 | } 52 | try { 53 | return tokenSymbolMap[symbol]; 54 | } catch (err) { 55 | return undefined; 56 | } 57 | return undefined; 58 | }; 59 | 60 | export const getTokenInfoById = ( 61 | tokenIdMap: { [key: number]: TokenInfo }, 62 | id: number 63 | ) => { 64 | if (!tokenIdMap) { 65 | return undefined; 66 | } 67 | try { 68 | return tokenIdMap[id]; 69 | } catch (err) { 70 | return undefined; 71 | } 72 | return undefined; 73 | }; 74 | 75 | export const hasMarket = (marketArr: any, market: string) => { 76 | if (!marketArr) { 77 | return false; 78 | } 79 | 80 | if (marketArr.includes(market)) { 81 | return true; 82 | } 83 | return false; 84 | }; 85 | 86 | export const getExistedMarket = ( 87 | marketArr: any, 88 | base: string | undefined, 89 | quote: string | undefined 90 | ) => { 91 | let market: any = undefined; 92 | let baseShow: any = undefined; 93 | let quoteShow: any = undefined; 94 | 95 | if (base && quote) { 96 | market = `${base}-${quote}`; 97 | baseShow = base; 98 | quoteShow = quote; 99 | if (!hasMarket(marketArr, market)) { 100 | market = `${quote}-${base}`; 101 | if (hasMarket(marketArr, market)) { 102 | baseShow = quote; 103 | quoteShow = base; 104 | } else { 105 | market = undefined; 106 | baseShow = undefined; 107 | quoteShow = undefined; 108 | } 109 | } 110 | } 111 | 112 | const amm = market ? `AMM-${market}` : undefined; 113 | 114 | return { 115 | market, 116 | amm, 117 | baseShow, 118 | quoteShow, 119 | }; 120 | }; 121 | export const getPair = (marketArr: any, market: string) => { 122 | const { base, quote } = getBaseQuote(market); 123 | 124 | return getExistedMarket(marketArr, base, quote); 125 | }; 126 | -------------------------------------------------------------------------------- /src/utils/window_utils.ts: -------------------------------------------------------------------------------- 1 | export const getWindowSafely = () => { 2 | if (typeof global.window === 'undefined' || typeof window === 'undefined') { 3 | return undefined 4 | } else { 5 | return window 6 | } 7 | } 8 | 9 | export const getNavigatorSafely = () => { 10 | if (typeof global.navigator === 'undefined' || typeof navigator === 'undefined') { 11 | return undefined 12 | } else { 13 | return navigator 14 | } 15 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./src", 4 | "rootDir": "./src", 5 | "outDir": "./dist", 6 | "module": "esnext", 7 | "target": "ES2022", 8 | "lib": [ 9 | "es2020", 10 | "es5" , 11 | "dom" 12 | ], 13 | "composite": true, 14 | "sourceMap": true, 15 | "allowJs": true, 16 | "skipLibCheck": true, 17 | "esModuleInterop": true, 18 | "declaration": true, 19 | "declarationMap": true, 20 | "esModuleInterop": true, 21 | "allowSyntheticDefaultImports": true, 22 | "noImplicitAny": true, 23 | "strict": true, 24 | "forceConsistentCasingInFileNames": true, 25 | "noFallthroughCasesInSwitch": true, 26 | "moduleResolution": "node", 27 | "resolveJsonModule": true, 28 | "isolatedModules": true, 29 | "noEmit": true 30 | }, 31 | "include": [ 32 | "src", 33 | "src/**/*.json", 34 | "src/*" 35 | ], 36 | "exclude": [ 37 | "node_modules", 38 | "dist", 39 | ".idea" 40 | ] 41 | } 42 | --------------------------------------------------------------------------------