diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..7b278de --- /dev/null +++ b/.classpath @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d46dcb8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +config +target +bin +*.sh +*.jar +*.pl +*.bak +node_modules +package-lock.json +.algo +.avm +.avm/* +.evm +.evm/* diff --git a/.project b/.project new file mode 100644 index 0000000..5ec4073 --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + forestfish + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.m2e.core.maven2Nature + org.eclipse.jdt.core.javanature + + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..f9bcb09 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/java/crypto/forestfish/utils/EVMContractUtils.java=UTF-8 +encoding//src/main/java/crypto/forestfish/utils/EVMUtils.java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding/=UTF-8 diff --git a/.settings/org.eclipse.core.runtime.prefs b/.settings/org.eclipse.core.runtime.prefs new file mode 100644 index 0000000..5a0ad22 --- /dev/null +++ b/.settings/org.eclipse.core.runtime.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +line.separator=\n diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..af7ce86 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,16 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=17 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..14b697b --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b4b3ee4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +# Released under MIT License + +Copyright (c) 2022 Daniel Dalek + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d08d5af --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +## FORESTFISH + +Java wrapper library for EVM compatible blockchains and Algorand. + +| ![alt text](https://github.com/p00temkin/forestfish/blob/master/img/forestfishto.png?raw=true) | +| :--: | + +### Why use/contribute to forestFISH? + +forestFISH attempts to make it easier to utilize JVM-based web3 SDKs. Typically helper libraries are much more mature for Javascript and are easier to use compared to its Java counterparts. It also provides useful features such as automatic node selection/failover and overall improved error handling. + +A simple example of getting the latest block on the POLYGON blockchain is shown below. On launch the connector will automatically grab the RPC node with best performance (based on your connectivity) and print the latest block. + + ``` + EVMBlockChainConnector connector = new EVMBlockChainConnector(EVMChain.POLYGON); + BigInteger latestBlockNR = EVMUtils.getLatestBlockNumber(connector); + System.out.println("latestBlockNR: " + latestBlockNR); + ``` + +Similarly for Algorand: + + ``` + AVMBlockChainConnector connector = new AVMBlockChainConnector(AVMChain.MAINNET); + Long lastRound = AVMUtils.getLastRound(connector); + System.out.println("lastRound: " + lastRound); + ``` + +If you want to print out an account portfolio across all EVM chains (similar to debank), you can launch an ultraconnector and make a call to getEVMPortfolioForAccount(): + + ``` + // Launch RPC node connectors for all known public chains + EVMBlockChainUltraConnector ultra_connector = new EVMBlockChainUltraConnector(BlockchainType.PUBLIC); + System.out.println("EVMBlockChainUltraConnector ready .."); + + // Print EVM portfolio, include known NFTs + EVMPortfolio evm_chainPortfolio = EVMUtils.getEVMPortfolioForAccount(ultra_connector, public_address); + String output = EVMUtils.getEVMPortfolioAsString(evm_chainPortfolio); + System.out.println(output); + ``` + +### Building the application + + ``` + mvn clean package install + ``` + +### How it works + +First git clone and install the forestfish library in your local Maven repository + + ``` + git clone https://github.com/p00temkin/forestfish.git + mvn clean package install + ``` + +Next, add a reference to this dependency in your new project pom.xml: + + ``` + + crypto.forestfish + forestfish + 0.0.1-SNAPSHOT + + ``` + +### Next steps +- Improved Ethereum and Algorand support +- Burst/Signum and more + +### Support/Donate + +To support this project directly: + + ``` + Ethereum/EVM: forestfish.x / 0x207d907768Df538F32f0F642a281416657692743 + Algorand: forestfish.x / 3LW6KZ5WZ22KAK4KV2G73H4HL2XBD3PD3Z5ZOSKFWGRWZDB5DTDCXE6NYU + ``` + +Or please consider donating to EFF: +[Electronic Frontier Foundation](https://supporters.eff.org/donate) diff --git a/abi/abiAavegotchiDiamond.json b/abi/abiAavegotchiDiamond.json new file mode 100644 index 0000000..6139eca --- /dev/null +++ b/abi/abiAavegotchiDiamond.json @@ -0,0 +1,7914 @@ +[ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "aavegotchiClaimTime", + "outputs": [ + { + "internalType": "uint256", + "name": "claimTime_", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "allAavegotchisOfOwner", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "randomNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "status", + "type": "uint256" + }, + { + "internalType": "int16[6]", + "name": "numericTraits", + "type": "int16[6]" + }, + { + "internalType": "int16[6]", + "name": "modifiedNumericTraits", + "type": "int16[6]" + }, + { + "internalType": "uint16[16]", + "name": "equippedWearables", + "type": "uint16[16]" + }, + { + "internalType": "address", + "name": "collateral", + "type": "address" + }, + { + "internalType": "address", + "name": "escrow", + "type": "address" + }, + { + "internalType": "uint256", + "name": "stakedAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minimumStake", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "kinship", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "lastInteracted", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "experience", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toNextLevel", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "usedSkillPoints", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "level", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "hauntId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "baseRarityScore", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "modifiedRarityScore", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "locked", + "type": "bool" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "itemId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "internalType": "string", + "name": "author", + "type": "string" + }, + { + "internalType": "int8[6]", + "name": "traitModifiers", + "type": "int8[6]" + }, + { + "internalType": "bool[16]", + "name": "slotPositions", + "type": "bool[16]" + }, + { + "internalType": "uint8[]", + "name": "allowedCollaterals", + "type": "uint8[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "x", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "y", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "width", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "height", + "type": "uint8" + } + ], + "internalType": "struct Dimensions", + "name": "dimensions", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "ghstPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxQuantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalQuantity", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "svgId", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "rarityScoreModifier", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "canPurchaseWithGhst", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "minLevel", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "canBeTransferred", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "category", + "type": "uint8" + }, + { + "internalType": "int16", + "name": "kinshipBonus", + "type": "int16" + }, + { + "internalType": "uint32", + "name": "experienceBonus", + "type": "uint32" + } + ], + "internalType": "struct ItemType", + "name": "itemType", + "type": "tuple" + } + ], + "internalType": "struct ItemTypeIO[]", + "name": "items", + "type": "tuple[]" + } + ], + "internalType": "struct AavegotchiInfo[]", + "name": "aavegotchiInfos_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_approved", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "balance_", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "getAavegotchi", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "randomNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "status", + "type": "uint256" + }, + { + "internalType": "int16[6]", + "name": "numericTraits", + "type": "int16[6]" + }, + { + "internalType": "int16[6]", + "name": "modifiedNumericTraits", + "type": "int16[6]" + }, + { + "internalType": "uint16[16]", + "name": "equippedWearables", + "type": "uint16[16]" + }, + { + "internalType": "address", + "name": "collateral", + "type": "address" + }, + { + "internalType": "address", + "name": "escrow", + "type": "address" + }, + { + "internalType": "uint256", + "name": "stakedAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minimumStake", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "kinship", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "lastInteracted", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "experience", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toNextLevel", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "usedSkillPoints", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "level", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "hauntId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "baseRarityScore", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "modifiedRarityScore", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "locked", + "type": "bool" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "itemId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "internalType": "string", + "name": "author", + "type": "string" + }, + { + "internalType": "int8[6]", + "name": "traitModifiers", + "type": "int8[6]" + }, + { + "internalType": "bool[16]", + "name": "slotPositions", + "type": "bool[16]" + }, + { + "internalType": "uint8[]", + "name": "allowedCollaterals", + "type": "uint8[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "x", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "y", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "width", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "height", + "type": "uint8" + } + ], + "internalType": "struct Dimensions", + "name": "dimensions", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "ghstPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxQuantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalQuantity", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "svgId", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "rarityScoreModifier", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "canPurchaseWithGhst", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "minLevel", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "canBeTransferred", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "category", + "type": "uint8" + }, + { + "internalType": "int16", + "name": "kinshipBonus", + "type": "int16" + }, + { + "internalType": "uint32", + "name": "experienceBonus", + "type": "uint32" + } + ], + "internalType": "struct ItemType", + "name": "itemType", + "type": "tuple" + } + ], + "internalType": "struct ItemTypeIO[]", + "name": "items", + "type": "tuple[]" + } + ], + "internalType": "struct AavegotchiInfo", + "name": "aavegotchiInfo_", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "approved_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "address", + "name": "_operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "approved_", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "owner_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_from", + "type": "address" + }, + { + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_from", + "type": "address" + }, + { + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "_approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_index", + "type": "uint256" + } + ], + "name": "tokenByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenId_", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "tokenIdsOfOwner", + "outputs": [ + { + "internalType": "uint32[]", + "name": "tokenIds_", + "type": "uint32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_index", + "type": "uint256" + } + ], + "name": "tokenOfOwnerByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenId_", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "totalSupply_", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_from", + "type": "address" + }, + { + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "ClaimAavegotchi", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_time", + "type": "uint256" + } + ], + "name": "LockAavegotchi", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "_oldName", + "type": "string" + }, + { + "indexed": false, + "internalType": "string", + "name": "_newName", + "type": "string" + } + ], + "name": "SetAavegotchiName", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "_batchId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + } + ], + "name": "SetBatchId", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "int16[4]", + "name": "_values", + "type": "int16[4]" + } + ], + "name": "SpendSkillpoints", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_time", + "type": "uint256" + } + ], + "name": "UnLockAavegotchi", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_experience", + "type": "uint256" + } + ], + "name": "aavegotchiLevel", + "outputs": [ + { + "internalType": "uint256", + "name": "level_", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "_name", + "type": "string" + } + ], + "name": "aavegotchiNameAvailable", + "outputs": [ + { + "internalType": "bool", + "name": "available_", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "availableSkillPoints", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int16[6]", + "name": "_numericTraits", + "type": "int16[6]" + } + ], + "name": "baseRarityScore", + "outputs": [ + { + "internalType": "uint256", + "name": "rarityScore_", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_option", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_stakeAmount", + "type": "uint256" + } + ], + "name": "claimAavegotchi", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "currentHaunt", + "outputs": [ + { + "internalType": "uint256", + "name": "hauntId_", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "hauntMaxSize", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "portalPrice", + "type": "uint256" + }, + { + "internalType": "bytes3", + "name": "bodyColor", + "type": "bytes3" + }, + { + "internalType": "uint24", + "name": "totalCount", + "type": "uint24" + } + ], + "internalType": "struct Haunt", + "name": "haunt_", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "getNumericTraits", + "outputs": [ + { + "internalType": "int16[6]", + "name": "numericTraits_", + "type": "int16[6]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ghstAddress", + "outputs": [ + { + "internalType": "address", + "name": "contract_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" + } + ], + "name": "interact", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "kinship", + "outputs": [ + { + "internalType": "uint256", + "name": "score_", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "modifiedTraitsAndRarityScore", + "outputs": [ + { + "internalType": "int16[6]", + "name": "numericTraits_", + "type": "int16[6]" + }, + { + "internalType": "uint256", + "name": "rarityScore_", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "portalAavegotchiTraits", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "randomNumber", + "type": "uint256" + }, + { + "internalType": "int16[6]", + "name": "numericTraits", + "type": "int16[6]" + }, + { + "internalType": "address", + "name": "collateralType", + "type": "address" + }, + { + "internalType": "uint256", + "name": "minimumStake", + "type": "uint256" + } + ], + "internalType": "struct PortalAavegotchiTraitsIO[10]", + "name": "portalAavegotchiTraits_", + "type": "tuple[10]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int16[6]", + "name": "_numericTraits", + "type": "int16[6]" + } + ], + "name": "rarityMultiplier", + "outputs": [ + { + "internalType": "uint256", + "name": "multiplier_", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "revenueShares", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "burnAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "daoAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "rarityFarming", + "type": "address" + }, + { + "internalType": "address", + "name": "pixelCraft", + "type": "address" + } + ], + "internalType": "struct AavegotchiGameFacet.RevenueSharesIO", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "_name", + "type": "string" + } + ], + "name": "setAavegotchiName", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "int16[4]", + "name": "_values", + "type": "int16[4]" + } + ], + "name": "spendSkillPoints", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_experience", + "type": "uint256" + } + ], + "name": "xpUntilNextLevel", + "outputs": [ + { + "internalType": "uint256", + "name": "requiredXp_", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + } + ], + "name": "AddedAavegotchiBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + } + ], + "name": "AddedItemsBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + } + ], + "name": "WithdrawnBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + } + ], + "name": "WithdrawnItems", + "type": "event" + }, + { + "inputs": [], + "name": "childChainManager", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_user", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_depositData", + "type": "bytes" + } + ], + "name": "deposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newChildChainManager", + "type": "address" + } + ], + "name": "setChildChainManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" + } + ], + "name": "withdrawAavegotchiBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_ids", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_values", + "type": "uint256[]" + } + ], + "name": "withdrawItemsBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_reduceAmount", + "type": "uint256" + } + ], + "name": "DecreaseStake", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "_fromTokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_toTokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "experience", + "type": "uint256" + } + ], + "name": "ExperienceTransfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_stakeAmount", + "type": "uint256" + } + ], + "name": "IncreaseStake", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "collateralBalance", + "outputs": [ + { + "internalType": "address", + "name": "collateralType_", + "type": "address" + }, + { + "internalType": "address", + "name": "escrow_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "balance_", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_collateralId", + "type": "uint256" + } + ], + "name": "collateralInfo", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "collateralType", + "type": "address" + }, + { + "components": [ + { + "internalType": "int16[6]", + "name": "modifiers", + "type": "int16[6]" + }, + { + "internalType": "bytes3", + "name": "primaryColor", + "type": "bytes3" + }, + { + "internalType": "bytes3", + "name": "secondaryColor", + "type": "bytes3" + }, + { + "internalType": "bytes3", + "name": "cheekColor", + "type": "bytes3" + }, + { + "internalType": "uint8", + "name": "svgId", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "eyeShapeSvgId", + "type": "uint8" + }, + { + "internalType": "uint16", + "name": "conversionRate", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "delisted", + "type": "bool" + } + ], + "internalType": "struct AavegotchiCollateralTypeInfo", + "name": "collateralTypeInfo", + "type": "tuple" + } + ], + "internalType": "struct AavegotchiCollateralTypeIO", + "name": "collateralInfo_", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collaterals", + "outputs": [ + { + "internalType": "address[]", + "name": "collateralTypes_", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_toId", + "type": "uint256" + } + ], + "name": "decreaseAndDestroy", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_reduceAmount", + "type": "uint256" + } + ], + "name": "decreaseStake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getCollateralInfo", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "collateralType", + "type": "address" + }, + { + "components": [ + { + "internalType": "int16[6]", + "name": "modifiers", + "type": "int16[6]" + }, + { + "internalType": "bytes3", + "name": "primaryColor", + "type": "bytes3" + }, + { + "internalType": "bytes3", + "name": "secondaryColor", + "type": "bytes3" + }, + { + "internalType": "bytes3", + "name": "cheekColor", + "type": "bytes3" + }, + { + "internalType": "uint8", + "name": "svgId", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "eyeShapeSvgId", + "type": "uint8" + }, + { + "internalType": "uint16", + "name": "conversionRate", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "delisted", + "type": "bool" + } + ], + "internalType": "struct AavegotchiCollateralTypeInfo", + "name": "collateralTypeInfo", + "type": "tuple" + } + ], + "internalType": "struct AavegotchiCollateralTypeIO[]", + "name": "collateralInfo_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_stakeAmount", + "type": "uint256" + } + ], + "name": "increaseStake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_collateralToken", + "type": "address" + }, + { + "internalType": "uint8", + "name": "_svgId", + "type": "uint8" + } + ], + "name": "setCollateralEyeShapeSvgId", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "collateralType", + "type": "address" + }, + { + "components": [ + { + "internalType": "int16[6]", + "name": "modifiers", + "type": "int16[6]" + }, + { + "internalType": "bytes3", + "name": "primaryColor", + "type": "bytes3" + }, + { + "internalType": "bytes3", + "name": "secondaryColor", + "type": "bytes3" + }, + { + "internalType": "bytes3", + "name": "cheekColor", + "type": "bytes3" + }, + { + "internalType": "uint8", + "name": "svgId", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "eyeShapeSvgId", + "type": "uint8" + }, + { + "internalType": "uint16", + "name": "conversionRate", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "delisted", + "type": "bool" + } + ], + "internalType": "struct AavegotchiCollateralTypeInfo", + "name": "collateralTypeInfo", + "type": "tuple" + } + ], + "indexed": false, + "internalType": "struct AavegotchiCollateralTypeIO", + "name": "_collateralType", + "type": "tuple" + } + ], + "name": "AddCollateralType", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "internalType": "string", + "name": "author", + "type": "string" + }, + { + "internalType": "int8[6]", + "name": "traitModifiers", + "type": "int8[6]" + }, + { + "internalType": "bool[16]", + "name": "slotPositions", + "type": "bool[16]" + }, + { + "internalType": "uint8[]", + "name": "allowedCollaterals", + "type": "uint8[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "x", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "y", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "width", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "height", + "type": "uint8" + } + ], + "internalType": "struct Dimensions", + "name": "dimensions", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "ghstPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxQuantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalQuantity", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "svgId", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "rarityScoreModifier", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "canPurchaseWithGhst", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "minLevel", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "canBeTransferred", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "category", + "type": "uint8" + }, + { + "internalType": "int16", + "name": "kinshipBonus", + "type": "int16" + }, + { + "internalType": "uint32", + "name": "experienceBonus", + "type": "uint32" + } + ], + "indexed": false, + "internalType": "struct ItemType", + "name": "_itemType", + "type": "tuple" + } + ], + "name": "AddItemType", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "uint8[]", + "name": "allowedCollaterals", + "type": "uint8[]" + }, + { + "internalType": "uint16[]", + "name": "wearableIds", + "type": "uint16[]" + }, + { + "internalType": "int8[5]", + "name": "traitsBonuses", + "type": "int8[5]" + } + ], + "indexed": false, + "internalType": "struct WearableSet", + "name": "_wearableSet", + "type": "tuple" + } + ], + "name": "AddWearableSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "_hauntId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_hauntMaxSize", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_portalPrice", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "_bodyColor", + "type": "bytes32" + } + ], + "name": "CreateHaunt", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousDao", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newDao", + "type": "address" + } + ], + "name": "DaoTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousDaoTreasury", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newDaoTreasury", + "type": "address" + } + ], + "name": "DaoTreasuryTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousGameManager", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newGameManager", + "type": "address" + } + ], + "name": "GameManagerTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_xpValues", + "type": "uint256[]" + } + ], + "name": "GrantExperience", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256[]", + "name": "_itemIds", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_maxQuanities", + "type": "uint256[]" + } + ], + "name": "ItemTypeMaxQuantity", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "int16[6]", + "name": "_oldModifiers", + "type": "int16[6]" + }, + { + "indexed": false, + "internalType": "int16[6]", + "name": "_newModifiers", + "type": "int16[6]" + } + ], + "name": "UpdateCollateralModifiers", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_setId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "uint8[]", + "name": "allowedCollaterals", + "type": "uint8[]" + }, + { + "internalType": "uint16[]", + "name": "wearableIds", + "type": "uint16[]" + }, + { + "internalType": "int8[5]", + "name": "traitsBonuses", + "type": "int8[5]" + } + ], + "indexed": false, + "internalType": "struct WearableSet", + "name": "_wearableSet", + "type": "tuple" + } + ], + "name": "UpdateWearableSet", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "collateralType", + "type": "address" + }, + { + "components": [ + { + "internalType": "int16[6]", + "name": "modifiers", + "type": "int16[6]" + }, + { + "internalType": "bytes3", + "name": "primaryColor", + "type": "bytes3" + }, + { + "internalType": "bytes3", + "name": "secondaryColor", + "type": "bytes3" + }, + { + "internalType": "bytes3", + "name": "cheekColor", + "type": "bytes3" + }, + { + "internalType": "uint8", + "name": "svgId", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "eyeShapeSvgId", + "type": "uint8" + }, + { + "internalType": "uint16", + "name": "conversionRate", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "delisted", + "type": "bool" + } + ], + "internalType": "struct AavegotchiCollateralTypeInfo", + "name": "collateralTypeInfo", + "type": "tuple" + } + ], + "internalType": "struct AavegotchiCollateralTypeIO[]", + "name": "_collateralTypes", + "type": "tuple[]" + } + ], + "name": "addCollateralTypes", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "internalType": "string", + "name": "author", + "type": "string" + }, + { + "internalType": "int8[6]", + "name": "traitModifiers", + "type": "int8[6]" + }, + { + "internalType": "bool[16]", + "name": "slotPositions", + "type": "bool[16]" + }, + { + "internalType": "uint8[]", + "name": "allowedCollaterals", + "type": "uint8[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "x", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "y", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "width", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "height", + "type": "uint8" + } + ], + "internalType": "struct Dimensions", + "name": "dimensions", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "ghstPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxQuantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalQuantity", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "svgId", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "rarityScoreModifier", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "canPurchaseWithGhst", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "minLevel", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "canBeTransferred", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "category", + "type": "uint8" + }, + { + "internalType": "int16", + "name": "kinshipBonus", + "type": "int16" + }, + { + "internalType": "uint32", + "name": "experienceBonus", + "type": "uint32" + } + ], + "internalType": "struct ItemType[]", + "name": "_itemTypes", + "type": "tuple[]" + } + ], + "name": "addItemTypes", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "internalType": "string", + "name": "author", + "type": "string" + }, + { + "internalType": "int8[6]", + "name": "traitModifiers", + "type": "int8[6]" + }, + { + "internalType": "bool[16]", + "name": "slotPositions", + "type": "bool[16]" + }, + { + "internalType": "uint8[]", + "name": "allowedCollaterals", + "type": "uint8[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "x", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "y", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "width", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "height", + "type": "uint8" + } + ], + "internalType": "struct Dimensions", + "name": "dimensions", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "ghstPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxQuantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalQuantity", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "svgId", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "rarityScoreModifier", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "canPurchaseWithGhst", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "minLevel", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "canBeTransferred", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "category", + "type": "uint8" + }, + { + "internalType": "int16", + "name": "kinshipBonus", + "type": "int16" + }, + { + "internalType": "uint32", + "name": "experienceBonus", + "type": "uint32" + } + ], + "internalType": "struct ItemType[]", + "name": "_itemTypes", + "type": "tuple[]" + }, + { + "internalType": "string", + "name": "_svg", + "type": "string" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "svgType", + "type": "bytes32" + }, + { + "internalType": "uint256[]", + "name": "sizes", + "type": "uint256[]" + } + ], + "internalType": "struct LibSvg.SvgTypeAndSizes[]", + "name": "_typesAndSizes", + "type": "tuple[]" + } + ], + "name": "addItemTypesAndSvgs", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "uint8[]", + "name": "allowedCollaterals", + "type": "uint8[]" + }, + { + "internalType": "uint16[]", + "name": "wearableIds", + "type": "uint16[]" + }, + { + "internalType": "int8[5]", + "name": "traitsBonuses", + "type": "int8[5]" + } + ], + "internalType": "struct WearableSet[]", + "name": "_wearableSets", + "type": "tuple[]" + } + ], + "name": "addWearableSets", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint24", + "name": "_hauntMaxSize", + "type": "uint24" + }, + { + "internalType": "uint96", + "name": "_portalPrice", + "type": "uint96" + }, + { + "internalType": "bytes3", + "name": "_bodyColor", + "type": "bytes3" + } + ], + "name": "createHaunt", + "outputs": [ + { + "internalType": "uint256", + "name": "hauntId_", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "gameManager", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_xpValues", + "type": "uint256[]" + } + ], + "name": "grantExperience", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "_itemIds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_quantities", + "type": "uint256[]" + } + ], + "name": "mintItems", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newDao", + "type": "address" + }, + { + "internalType": "address", + "name": "_newDaoTreasury", + "type": "address" + } + ], + "name": "setDao", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_gameManager", + "type": "address" + } + ], + "name": "setGameManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_collateralType", + "type": "address" + }, + { + "internalType": "int16[6]", + "name": "_modifiers", + "type": "int16[6]" + } + ], + "name": "updateCollateralModifiers", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_itemIds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_maxQuantities", + "type": "uint256[]" + } + ], + "name": "updateItemTypeMaxQuantity", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_setIds", + "type": "uint256[]" + }, + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "uint8[]", + "name": "allowedCollaterals", + "type": "uint8[]" + }, + { + "internalType": "uint16[]", + "name": "wearableIds", + "type": "uint16[]" + }, + { + "internalType": "int8[5]", + "name": "traitsBonuses", + "type": "int8[5]" + } + ], + "internalType": "struct WearableSet[]", + "name": "_wearableSets", + "type": "tuple[]" + } + ], + "name": "updateWearableSets", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "listingFeeInWei", + "type": "uint256" + } + ], + "name": "ChangedListingFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "seller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "buyer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "erc1155TokenAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "erc1155TypeId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "category", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_quantity", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "priceInWei", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "time", + "type": "uint256" + } + ], + "name": "ERC1155ExecutedListing", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "seller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "erc1155TokenAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "erc1155TypeId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "category", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "quantity", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "priceInWei", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "time", + "type": "uint256" + } + ], + "name": "ERC1155ListingAdd", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + } + ], + "name": "ERC1155ListingCancelled", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_listingId", + "type": "uint256" + } + ], + "name": "cancelERC1155Listing", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_listingIds", + "type": "uint256[]" + } + ], + "name": "cancelERC1155Listings", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_listingId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_quantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_priceInWei", + "type": "uint256" + } + ], + "name": "executeERC1155Listing", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_erc1155TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_erc1155TypeId", + "type": "uint256" + } + ], + "name": "getERC1155Category", + "outputs": [ + { + "internalType": "uint256", + "name": "category_", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_listingId", + "type": "uint256" + } + ], + "name": "getERC1155Listing", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "seller", + "type": "address" + }, + { + "internalType": "address", + "name": "erc1155TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc1155TypeId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "category", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "quantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "priceInWei", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeCreated", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeLastPurchased", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "sourceListingId", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "sold", + "type": "bool" + }, + { + "internalType": "bool", + "name": "cancelled", + "type": "bool" + } + ], + "internalType": "struct ERC1155Listing", + "name": "listing_", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_erc1155TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_erc1155TypeId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "getERC1155ListingFromToken", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "seller", + "type": "address" + }, + { + "internalType": "address", + "name": "erc1155TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc1155TypeId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "category", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "quantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "priceInWei", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeCreated", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeLastPurchased", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "sourceListingId", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "sold", + "type": "bool" + }, + { + "internalType": "bool", + "name": "cancelled", + "type": "bool" + } + ], + "internalType": "struct ERC1155Listing", + "name": "listing_", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_category", + "type": "uint256" + }, + { + "internalType": "string", + "name": "_sort", + "type": "string" + }, + { + "internalType": "uint256", + "name": "_length", + "type": "uint256" + } + ], + "name": "getERC1155Listings", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "seller", + "type": "address" + }, + { + "internalType": "address", + "name": "erc1155TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc1155TypeId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "category", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "quantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "priceInWei", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeCreated", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeLastPurchased", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "sourceListingId", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "sold", + "type": "bool" + }, + { + "internalType": "bool", + "name": "cancelled", + "type": "bool" + } + ], + "internalType": "struct ERC1155Listing[]", + "name": "listings_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getListingFeeInWei", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_category", + "type": "uint256" + }, + { + "internalType": "string", + "name": "_sort", + "type": "string" + }, + { + "internalType": "uint256", + "name": "_length", + "type": "uint256" + } + ], + "name": "getOwnerERC1155Listings", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "seller", + "type": "address" + }, + { + "internalType": "address", + "name": "erc1155TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc1155TypeId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "category", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "quantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "priceInWei", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeCreated", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeLastPurchased", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "sourceListingId", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "sold", + "type": "bool" + }, + { + "internalType": "bool", + "name": "cancelled", + "type": "bool" + } + ], + "internalType": "struct ERC1155Listing[]", + "name": "listings_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "erc1155TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc1155TypeId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "category", + "type": "uint256" + } + ], + "internalType": "struct ERC1155MarketplaceFacet.Category[]", + "name": "_categories", + "type": "tuple[]" + } + ], + "name": "setERC1155Categories", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_erc1155TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_erc1155TypeId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_quantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_priceInWei", + "type": "uint256" + } + ], + "name": "setERC1155Listing", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_listingFeeInWei", + "type": "uint256" + } + ], + "name": "setListingFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_erc1155TokenAddress", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "_erc1155TypeIds", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "updateBatchERC1155Listing", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_erc1155TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_erc1155TypeId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "updateERC1155Listing", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "seller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "buyer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "erc721TokenAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "erc721TokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "category", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "priceInWei", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "time", + "type": "uint256" + } + ], + "name": "ERC721ExecutedListing", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "seller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "erc721TokenAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "erc721TokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "category", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "time", + "type": "uint256" + } + ], + "name": "ERC721ListingAdd", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_erc721TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_erc721TokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_priceInWei", + "type": "uint256" + } + ], + "name": "addERC721Listing", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_listingId", + "type": "uint256" + } + ], + "name": "cancelERC721Listing", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_erc721TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_erc721TokenId", + "type": "uint256" + } + ], + "name": "cancelERC721ListingByToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_listingIds", + "type": "uint256[]" + } + ], + "name": "cancelERC721Listings", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_listingId", + "type": "uint256" + } + ], + "name": "executeERC721Listing", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_listingId", + "type": "uint256" + } + ], + "name": "getAavegotchiListing", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "seller", + "type": "address" + }, + { + "internalType": "address", + "name": "erc721TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc721TokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "category", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "priceInWei", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeCreated", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timePurchased", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "cancelled", + "type": "bool" + } + ], + "internalType": "struct ERC721Listing", + "name": "listing_", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "randomNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "status", + "type": "uint256" + }, + { + "internalType": "int16[6]", + "name": "numericTraits", + "type": "int16[6]" + }, + { + "internalType": "int16[6]", + "name": "modifiedNumericTraits", + "type": "int16[6]" + }, + { + "internalType": "uint16[16]", + "name": "equippedWearables", + "type": "uint16[16]" + }, + { + "internalType": "address", + "name": "collateral", + "type": "address" + }, + { + "internalType": "address", + "name": "escrow", + "type": "address" + }, + { + "internalType": "uint256", + "name": "stakedAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minimumStake", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "kinship", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "lastInteracted", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "experience", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toNextLevel", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "usedSkillPoints", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "level", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "hauntId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "baseRarityScore", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "modifiedRarityScore", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "locked", + "type": "bool" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "itemId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "internalType": "string", + "name": "author", + "type": "string" + }, + { + "internalType": "int8[6]", + "name": "traitModifiers", + "type": "int8[6]" + }, + { + "internalType": "bool[16]", + "name": "slotPositions", + "type": "bool[16]" + }, + { + "internalType": "uint8[]", + "name": "allowedCollaterals", + "type": "uint8[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "x", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "y", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "width", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "height", + "type": "uint8" + } + ], + "internalType": "struct Dimensions", + "name": "dimensions", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "ghstPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxQuantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalQuantity", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "svgId", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "rarityScoreModifier", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "canPurchaseWithGhst", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "minLevel", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "canBeTransferred", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "category", + "type": "uint8" + }, + { + "internalType": "int16", + "name": "kinshipBonus", + "type": "int16" + }, + { + "internalType": "uint32", + "name": "experienceBonus", + "type": "uint32" + } + ], + "internalType": "struct ItemType", + "name": "itemType", + "type": "tuple" + } + ], + "internalType": "struct ItemTypeIO[]", + "name": "items", + "type": "tuple[]" + } + ], + "internalType": "struct AavegotchiInfo", + "name": "aavegotchiInfo_", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_category", + "type": "uint256" + }, + { + "internalType": "string", + "name": "_sort", + "type": "string" + }, + { + "internalType": "uint256", + "name": "_length", + "type": "uint256" + } + ], + "name": "getAavegotchiListings", + "outputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "seller", + "type": "address" + }, + { + "internalType": "address", + "name": "erc721TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc721TokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "category", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "priceInWei", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeCreated", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timePurchased", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "cancelled", + "type": "bool" + } + ], + "internalType": "struct ERC721Listing", + "name": "listing_", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "randomNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "status", + "type": "uint256" + }, + { + "internalType": "int16[6]", + "name": "numericTraits", + "type": "int16[6]" + }, + { + "internalType": "int16[6]", + "name": "modifiedNumericTraits", + "type": "int16[6]" + }, + { + "internalType": "uint16[16]", + "name": "equippedWearables", + "type": "uint16[16]" + }, + { + "internalType": "address", + "name": "collateral", + "type": "address" + }, + { + "internalType": "address", + "name": "escrow", + "type": "address" + }, + { + "internalType": "uint256", + "name": "stakedAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minimumStake", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "kinship", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "lastInteracted", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "experience", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toNextLevel", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "usedSkillPoints", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "level", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "hauntId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "baseRarityScore", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "modifiedRarityScore", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "locked", + "type": "bool" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "itemId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "internalType": "string", + "name": "author", + "type": "string" + }, + { + "internalType": "int8[6]", + "name": "traitModifiers", + "type": "int8[6]" + }, + { + "internalType": "bool[16]", + "name": "slotPositions", + "type": "bool[16]" + }, + { + "internalType": "uint8[]", + "name": "allowedCollaterals", + "type": "uint8[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "x", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "y", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "width", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "height", + "type": "uint8" + } + ], + "internalType": "struct Dimensions", + "name": "dimensions", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "ghstPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxQuantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalQuantity", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "svgId", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "rarityScoreModifier", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "canPurchaseWithGhst", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "minLevel", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "canBeTransferred", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "category", + "type": "uint8" + }, + { + "internalType": "int16", + "name": "kinshipBonus", + "type": "int16" + }, + { + "internalType": "uint32", + "name": "experienceBonus", + "type": "uint32" + } + ], + "internalType": "struct ItemType", + "name": "itemType", + "type": "tuple" + } + ], + "internalType": "struct ItemTypeIO[]", + "name": "items", + "type": "tuple[]" + } + ], + "internalType": "struct AavegotchiInfo", + "name": "aavegotchiInfo_", + "type": "tuple" + } + ], + "internalType": "struct ERC721MarketplaceFacet.AavegotchiListing[]", + "name": "listings_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_erc721TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_erc721TokenId", + "type": "uint256" + } + ], + "name": "getERC721Category", + "outputs": [ + { + "internalType": "uint256", + "name": "category_", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_listingId", + "type": "uint256" + } + ], + "name": "getERC721Listing", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "seller", + "type": "address" + }, + { + "internalType": "address", + "name": "erc721TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc721TokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "category", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "priceInWei", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeCreated", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timePurchased", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "cancelled", + "type": "bool" + } + ], + "internalType": "struct ERC721Listing", + "name": "listing_", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_erc721TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_erc721TokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "getERC721ListingFromToken", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "seller", + "type": "address" + }, + { + "internalType": "address", + "name": "erc721TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc721TokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "category", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "priceInWei", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeCreated", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timePurchased", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "cancelled", + "type": "bool" + } + ], + "internalType": "struct ERC721Listing", + "name": "listing_", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_category", + "type": "uint256" + }, + { + "internalType": "string", + "name": "_sort", + "type": "string" + }, + { + "internalType": "uint256", + "name": "_length", + "type": "uint256" + } + ], + "name": "getERC721Listings", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "seller", + "type": "address" + }, + { + "internalType": "address", + "name": "erc721TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc721TokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "category", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "priceInWei", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeCreated", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timePurchased", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "cancelled", + "type": "bool" + } + ], + "internalType": "struct ERC721Listing[]", + "name": "listings_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_category", + "type": "uint256" + }, + { + "internalType": "string", + "name": "_sort", + "type": "string" + }, + { + "internalType": "uint256", + "name": "_length", + "type": "uint256" + } + ], + "name": "getOwnerAavegotchiListings", + "outputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "seller", + "type": "address" + }, + { + "internalType": "address", + "name": "erc721TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc721TokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "category", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "priceInWei", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeCreated", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timePurchased", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "cancelled", + "type": "bool" + } + ], + "internalType": "struct ERC721Listing", + "name": "listing_", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "randomNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "status", + "type": "uint256" + }, + { + "internalType": "int16[6]", + "name": "numericTraits", + "type": "int16[6]" + }, + { + "internalType": "int16[6]", + "name": "modifiedNumericTraits", + "type": "int16[6]" + }, + { + "internalType": "uint16[16]", + "name": "equippedWearables", + "type": "uint16[16]" + }, + { + "internalType": "address", + "name": "collateral", + "type": "address" + }, + { + "internalType": "address", + "name": "escrow", + "type": "address" + }, + { + "internalType": "uint256", + "name": "stakedAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minimumStake", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "kinship", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "lastInteracted", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "experience", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "toNextLevel", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "usedSkillPoints", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "level", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "hauntId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "baseRarityScore", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "modifiedRarityScore", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "locked", + "type": "bool" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "itemId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "internalType": "string", + "name": "author", + "type": "string" + }, + { + "internalType": "int8[6]", + "name": "traitModifiers", + "type": "int8[6]" + }, + { + "internalType": "bool[16]", + "name": "slotPositions", + "type": "bool[16]" + }, + { + "internalType": "uint8[]", + "name": "allowedCollaterals", + "type": "uint8[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "x", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "y", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "width", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "height", + "type": "uint8" + } + ], + "internalType": "struct Dimensions", + "name": "dimensions", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "ghstPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxQuantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalQuantity", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "svgId", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "rarityScoreModifier", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "canPurchaseWithGhst", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "minLevel", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "canBeTransferred", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "category", + "type": "uint8" + }, + { + "internalType": "int16", + "name": "kinshipBonus", + "type": "int16" + }, + { + "internalType": "uint32", + "name": "experienceBonus", + "type": "uint32" + } + ], + "internalType": "struct ItemType", + "name": "itemType", + "type": "tuple" + } + ], + "internalType": "struct ItemTypeIO[]", + "name": "items", + "type": "tuple[]" + } + ], + "internalType": "struct AavegotchiInfo", + "name": "aavegotchiInfo_", + "type": "tuple" + } + ], + "internalType": "struct ERC721MarketplaceFacet.AavegotchiListing[]", + "name": "listings_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_category", + "type": "uint256" + }, + { + "internalType": "string", + "name": "_sort", + "type": "string" + }, + { + "internalType": "uint256", + "name": "_length", + "type": "uint256" + } + ], + "name": "getOwnerERC721Listings", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "seller", + "type": "address" + }, + { + "internalType": "address", + "name": "erc721TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "erc721TokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "category", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "priceInWei", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeCreated", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timePurchased", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "cancelled", + "type": "bool" + } + ], + "internalType": "struct ERC721Listing[]", + "name": "listings_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_erc721TokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_erc721TokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "updateERC721Listing", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint16[16]", + "name": "_oldWearables", + "type": "uint16[16]" + }, + { + "indexed": false, + "internalType": "uint16[16]", + "name": "_newWearables", + "type": "uint16[16]" + } + ], + "name": "EquipWearables", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_toContract", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_toTokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_tokenTypeId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_value", + "type": "uint256" + } + ], + "name": "TransferToParent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_itemIds", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_quantities", + "type": "uint256[]" + } + ], + "name": "UseConsumables", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_id", + "type": "uint256" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "bal_", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_owners", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_ids", + "type": "uint256[]" + } + ], + "name": "balanceOfBatch", + "outputs": [ + { + "internalType": "uint256[]", + "name": "bals", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_tokenContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_id", + "type": "uint256" + } + ], + "name": "balanceOfToken", + "outputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "uint16[16]", + "name": "_equippedWearables", + "type": "uint16[16]" + } + ], + "name": "equipWearables", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "equippedWearables", + "outputs": [ + { + "internalType": "uint16[16]", + "name": "wearableIds_", + "type": "uint16[16]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_wearableIds", + "type": "uint256[]" + } + ], + "name": "findWearableSets", + "outputs": [ + { + "internalType": "uint256[]", + "name": "wearableSetIds_", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_itemId", + "type": "uint256" + } + ], + "name": "getItemType", + "outputs": [ + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "internalType": "string", + "name": "author", + "type": "string" + }, + { + "internalType": "int8[6]", + "name": "traitModifiers", + "type": "int8[6]" + }, + { + "internalType": "bool[16]", + "name": "slotPositions", + "type": "bool[16]" + }, + { + "internalType": "uint8[]", + "name": "allowedCollaterals", + "type": "uint8[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "x", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "y", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "width", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "height", + "type": "uint8" + } + ], + "internalType": "struct Dimensions", + "name": "dimensions", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "ghstPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxQuantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalQuantity", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "svgId", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "rarityScoreModifier", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "canPurchaseWithGhst", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "minLevel", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "canBeTransferred", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "category", + "type": "uint8" + }, + { + "internalType": "int16", + "name": "kinshipBonus", + "type": "int16" + }, + { + "internalType": "uint32", + "name": "experienceBonus", + "type": "uint32" + } + ], + "internalType": "struct ItemType", + "name": "itemType_", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_itemIds", + "type": "uint256[]" + } + ], + "name": "getItemTypes", + "outputs": [ + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "internalType": "string", + "name": "author", + "type": "string" + }, + { + "internalType": "int8[6]", + "name": "traitModifiers", + "type": "int8[6]" + }, + { + "internalType": "bool[16]", + "name": "slotPositions", + "type": "bool[16]" + }, + { + "internalType": "uint8[]", + "name": "allowedCollaterals", + "type": "uint8[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "x", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "y", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "width", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "height", + "type": "uint8" + } + ], + "internalType": "struct Dimensions", + "name": "dimensions", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "ghstPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxQuantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalQuantity", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "svgId", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "rarityScoreModifier", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "canPurchaseWithGhst", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "minLevel", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "canBeTransferred", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "category", + "type": "uint8" + }, + { + "internalType": "int16", + "name": "kinshipBonus", + "type": "int16" + }, + { + "internalType": "uint32", + "name": "experienceBonus", + "type": "uint32" + } + ], + "internalType": "struct ItemType[]", + "name": "itemTypes_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_index", + "type": "uint256" + } + ], + "name": "getWearableSet", + "outputs": [ + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "uint8[]", + "name": "allowedCollaterals", + "type": "uint8[]" + }, + { + "internalType": "uint16[]", + "name": "wearableIds", + "type": "uint16[]" + }, + { + "internalType": "int8[5]", + "name": "traitsBonuses", + "type": "int8[5]" + } + ], + "internalType": "struct WearableSet", + "name": "wearableSet_", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getWearableSets", + "outputs": [ + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "uint8[]", + "name": "allowedCollaterals", + "type": "uint8[]" + }, + { + "internalType": "uint16[]", + "name": "wearableIds", + "type": "uint16[]" + }, + { + "internalType": "int8[5]", + "name": "traitsBonuses", + "type": "int8[5]" + } + ], + "internalType": "struct WearableSet[]", + "name": "wearableSets_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "itemBalances", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "itemId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "internalType": "struct ItemsFacet.ItemIdIO[]", + "name": "bals_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_tokenContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "itemBalancesOfToken", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "itemId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "internalType": "struct ItemsFacet.ItemIdIO[]", + "name": "bals_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_tokenContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "itemBalancesOfTokenWithTypes", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "itemId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "internalType": "string", + "name": "author", + "type": "string" + }, + { + "internalType": "int8[6]", + "name": "traitModifiers", + "type": "int8[6]" + }, + { + "internalType": "bool[16]", + "name": "slotPositions", + "type": "bool[16]" + }, + { + "internalType": "uint8[]", + "name": "allowedCollaterals", + "type": "uint8[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "x", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "y", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "width", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "height", + "type": "uint8" + } + ], + "internalType": "struct Dimensions", + "name": "dimensions", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "ghstPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxQuantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalQuantity", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "svgId", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "rarityScoreModifier", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "canPurchaseWithGhst", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "minLevel", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "canBeTransferred", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "category", + "type": "uint8" + }, + { + "internalType": "int16", + "name": "kinshipBonus", + "type": "int16" + }, + { + "internalType": "uint32", + "name": "experienceBonus", + "type": "uint32" + } + ], + "internalType": "struct ItemType", + "name": "itemType", + "type": "tuple" + } + ], + "internalType": "struct ItemTypeIO[]", + "name": "itemBalancesOfTokenWithTypes_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "itemBalancesWithTypes", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "itemId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "internalType": "string", + "name": "author", + "type": "string" + }, + { + "internalType": "int8[6]", + "name": "traitModifiers", + "type": "int8[6]" + }, + { + "internalType": "bool[16]", + "name": "slotPositions", + "type": "bool[16]" + }, + { + "internalType": "uint8[]", + "name": "allowedCollaterals", + "type": "uint8[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "x", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "y", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "width", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "height", + "type": "uint8" + } + ], + "internalType": "struct Dimensions", + "name": "dimensions", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "ghstPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxQuantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalQuantity", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "svgId", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "rarityScoreModifier", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "canPurchaseWithGhst", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "minLevel", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "canBeTransferred", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "category", + "type": "uint8" + }, + { + "internalType": "int16", + "name": "kinshipBonus", + "type": "int16" + }, + { + "internalType": "uint32", + "name": "experienceBonus", + "type": "uint32" + } + ], + "internalType": "struct ItemType", + "name": "itemType", + "type": "tuple" + } + ], + "internalType": "struct ItemTypeIO[]", + "name": "output_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "_value", + "type": "string" + } + ], + "name": "setBaseURI", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_wearableId", + "type": "uint256" + }, + { + "internalType": "bool[16]", + "name": "_slotPositions", + "type": "bool[16]" + } + ], + "name": "setWearableSlotPositions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "totalWearableSets", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_id", + "type": "uint256" + } + ], + "name": "uri", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "_itemIds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_quantities", + "type": "uint256[]" + } + ], + "name": "useConsumables", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_fromContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_fromTokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_toContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_toTokenId", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "_ids", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_values", + "type": "uint256[]" + } + ], + "name": "batchTransferAsChild", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_fromContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_fromTokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "_ids", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_values", + "type": "uint256[]" + } + ], + "name": "batchTransferFromParent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_from", + "type": "address" + }, + { + "internalType": "address", + "name": "_toContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_toTokenId", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "_ids", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_values", + "type": "uint256[]" + } + ], + "name": "batchTransferToParent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC1155BatchReceived", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC1155Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_from", + "type": "address" + }, + { + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "_ids", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_values", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "safeBatchTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_from", + "type": "address" + }, + { + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_fromContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_fromTokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_toContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_toTokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_value", + "type": "uint256" + } + ], + "name": "transferAsChild", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_fromContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_fromTokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFromParent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_from", + "type": "address" + }, + { + "internalType": "address", + "name": "_toContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_toTokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_value", + "type": "uint256" + } + ], + "name": "transferToParent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "userAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address payable", + "name": "relayerAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "functionSignature", + "type": "bytes" + } + ], + "name": "MetaTransactionExecuted", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "userAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "functionSignature", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "sigR", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "sigS", + "type": "bytes32" + }, + { + "internalType": "uint8", + "name": "sigV", + "type": "uint8" + } + ], + "name": "executeMetaTransaction", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "getNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "nonce_", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_numAavegotchisToPurchase", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_totalPrice", + "type": "uint256" + } + ], + "name": "BuyPortals", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_buyer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_itemIds", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_quantities", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_totalPrice", + "type": "uint256" + } + ], + "name": "PurchaseItemsWithGhst", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_buyer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_itemIds", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_quantities", + "type": "uint256[]" + } + ], + "name": "PurchaseItemsWithVouchers", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_buyer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_itemIds", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_quantities", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_totalPrice", + "type": "uint256" + } + ], + "name": "PurchaseTransferItemsWithGhst", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_ghst", + "type": "uint256" + } + ], + "name": "buyPortals", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "_itemIds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_quantities", + "type": "uint256[]" + } + ], + "name": "purchaseItemsWithGhst", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "_itemIds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_quantities", + "type": "uint256[]" + } + ], + "name": "purchaseTransferItemsWithGhst", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_svgType", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "_numLayers", + "type": "uint256" + } + ], + "name": "deleteLastSvgLayers", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "getAavegotchiSvg", + "outputs": [ + { + "internalType": "string", + "name": "ag_", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_itemId", + "type": "uint256" + } + ], + "name": "getItemSvg", + "outputs": [ + { + "internalType": "string", + "name": "ag_", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_svgType", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "_itemId", + "type": "uint256" + } + ], + "name": "getSvg", + "outputs": [ + { + "internalType": "string", + "name": "svg_", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_svgType", + "type": "bytes32" + }, + { + "internalType": "uint256[]", + "name": "_itemIds", + "type": "uint256[]" + } + ], + "name": "getSvgs", + "outputs": [ + { + "internalType": "string[]", + "name": "svgs_", + "type": "string[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "portalAavegotchisSvg", + "outputs": [ + { + "internalType": "string[10]", + "name": "svg_", + "type": "string[10]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_itemIds", + "type": "uint256[]" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "x", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "y", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "width", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "height", + "type": "uint8" + } + ], + "internalType": "struct Dimensions[]", + "name": "_dimensions", + "type": "tuple[]" + } + ], + "name": "setItemsDimensions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "sleeveId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "wearableId", + "type": "uint256" + } + ], + "internalType": "struct SvgFacet.Sleeve[]", + "name": "_sleeves", + "type": "tuple[]" + } + ], + "name": "setSleeves", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "_svg", + "type": "string" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "svgType", + "type": "bytes32" + }, + { + "internalType": "uint256[]", + "name": "sizes", + "type": "uint256[]" + } + ], + "internalType": "struct LibSvg.SvgTypeAndSizes[]", + "name": "_typesAndSizes", + "type": "tuple[]" + } + ], + "name": "storeSvg", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "_svg", + "type": "string" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "svgType", + "type": "bytes32" + }, + { + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "sizes", + "type": "uint256[]" + } + ], + "internalType": "struct LibSvg.SvgTypeAndIdsAndSizes[]", + "name": "_typesAndIdsAndSizes", + "type": "tuple[]" + } + ], + "name": "updateSvg", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" + } + ], + "name": "OpenPortals", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "PortalOpened", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "randomNumber", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_vrfTimeSet", + "type": "uint256" + } + ], + "name": "VrfRandomNumber", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newFee", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "_keyHash", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "_vrfCoordinator", + "type": "address" + }, + { + "internalType": "address", + "name": "_link", + "type": "address" + } + ], + "name": "changeVrf", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "keyHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "link", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "linkBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "linkBalance_", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" + } + ], + "name": "openPortals", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_requestId", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "_randomNumber", + "type": "uint256" + } + ], + "name": "rawFulfillRandomness", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_value", + "type": "uint256" + } + ], + "name": "removeLinkTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "vrfCoordinator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_ids", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_values", + "type": "uint256[]" + } + ], + "name": "MigrateVouchers", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + } + ], + "internalType": "struct VoucherMigrationFacet.VouchersOwner[]", + "name": "_vouchersOwners", + "type": "tuple[]" + } + ], + "name": "migrateVouchers", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_buyer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_itemIds", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_quantities", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_totalPrice", + "type": "uint256" + } + ], + "name": "PurchaseItemsWithGhst", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_buyer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_itemIds", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_quantities", + "type": "uint256[]" + } + ], + "name": "PurchaseItemsWithVouchers", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_buyer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_itemIds", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_quantities", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_totalPrice", + "type": "uint256" + } + ], + "name": "PurchaseTransferItemsWithGhst", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_numAavegotchisToPurchase", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_totalPrice", + "type": "uint256" + } + ], + "name": "Xingyun", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "_itemIds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_quantities", + "type": "uint256[]" + } + ], + "name": "purchaseItemsWithGhst", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "_itemIds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "_quantities", + "type": "uint256[]" + } + ], + "name": "purchaseTransferItemsWithGhst", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_ghst", + "type": "uint256" + } + ], + "name": "xingyun", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "kinship", + "type": "uint256" + } + ], + "name": "AavegotchiInteract", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "category", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "time", + "type": "uint256" + } + ], + "name": "ERC1155ListingCancelled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "category", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "time", + "type": "uint256" + } + ], + "name": "ERC1155ListingRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "quantity", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "priceInWei", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "time", + "type": "uint256" + } + ], + "name": "UpdateERC1155Listing", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "category", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "time", + "type": "uint256" + } + ], + "name": "ERC721ListingCancelled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "listingId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "category", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "time", + "type": "uint256" + } + ], + "name": "ERC721ListingRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "svgType", + "type": "bytes32" + }, + { + "internalType": "uint256[]", + "name": "sizes", + "type": "uint256[]" + } + ], + "indexed": false, + "internalType": "struct LibSvg.SvgTypeAndSizes[]", + "name": "_typesAndSizes", + "type": "tuple[]" + } + ], + "name": "StoreSvg", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "svgType", + "type": "bytes32" + }, + { + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "sizes", + "type": "uint256[]" + } + ], + "indexed": false, + "internalType": "struct LibSvg.SvgTypeAndIdsAndSizes[]", + "name": "_typesAndIdsAndSizes", + "type": "tuple[]" + } + ], + "name": "UpdateSvg", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamondCut.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "indexed": false, + "internalType": "struct IDiamondCut.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "indexed": false, + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "DiamondCut", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "_approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_ids", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_values", + "type": "uint256[]" + } + ], + "name": "TransferBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_fromContract", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_fromTokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_tokenTypeId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_value", + "type": "uint256" + } + ], + "name": "TransferFromParent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_value", + "type": "uint256" + } + ], + "name": "TransferSingle", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_toContract", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_toTokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_tokenTypeId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_value", + "type": "uint256" + } + ], + "name": "TransferToParent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "_value", + "type": "string" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_id", + "type": "uint256" + } + ], + "name": "URI", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "_approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] \ No newline at end of file diff --git a/abi/abiERC1155.json b/abi/abiERC1155.json new file mode 100644 index 0000000..40e13a2 --- /dev/null +++ b/abi/abiERC1155.json @@ -0,0 +1,262 @@ +[{ + "anonymous": false, + "inputs": [{ + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, { + "anonymous": false, + "inputs": [{ + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, { + "indexed": false, + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, { + "indexed": false, + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + } + ], + "name": "TransferBatch", + "type": "event" + }, { + "anonymous": false, + "inputs": [{ + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "TransferSingle", + "type": "event" + }, { + "anonymous": false, + "inputs": [{ + "indexed": false, + "internalType": "string", + "name": "value", + "type": "string" + }, { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "URI", + "type": "event" + }, { + "inputs": [{ + "internalType": "address", + "name": "account", + "type": "address" + }, { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "balanceOf", + "outputs": [{ + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { + "inputs": [{ + "internalType": "address[]", + "name": "accounts", + "type": "address[]" + }, { + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + } + ], + "name": "balanceOfBatch", + "outputs": [{ + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, { + "inputs": [{ + "internalType": "address", + "name": "account", + "type": "address" + }, { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [{ + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { + "inputs": [{ + "internalType": "address", + "name": "from", + "type": "address" + }, { + "internalType": "address", + "name": "to", + "type": "address" + }, { + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeBatchTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { + "inputs": [{ + "internalType": "address", + "name": "from", + "type": "address" + }, { + "internalType": "address", + "name": "to", + "type": "address" + }, { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { + "inputs": [{ + "internalType": "address", + "name": "operator", + "type": "address" + }, { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { + "inputs": [{ + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [{ + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { + "inputs": [{ + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "uri", + "outputs": [{ + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/abiERC20Interface.json b/abi/abiERC20Interface.json new file mode 100644 index 0000000..52f09d4 --- /dev/null +++ b/abi/abiERC20Interface.json @@ -0,0 +1,145 @@ +[{ + "anonymous": false, + "inputs": [{ + "indexed": true, + "name": "from", + "type": "address" + }, { + "indexed": true, + "name": "to", + "type": "address" + }, { + "indexed": false, + "name": "tokens", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, { + "anonymous": false, + "inputs": [{ + "indexed": true, + "name": "tokenOwner", + "type": "address" + }, { + "indexed": true, + "name": "spender", + "type": "address" + }, { + "indexed": false, + "name": "tokens", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [{ + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "tokenOwner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [{ + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "tokenOwner", + "type": "address" + }, { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [{ + "name": "remaining", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "to", + "type": "address" + }, { + "name": "tokens", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [{ + "name": "success", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "spender", + "type": "address" + }, { + "name": "tokens", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [{ + "name": "success", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "from", + "type": "address" + }, { + "name": "to", + "type": "address" + }, { + "name": "tokens", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [{ + "name": "success", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abi/abiERC721Basic.json b/abi/abiERC721Basic.json new file mode 100644 index 0000000..92ab78d --- /dev/null +++ b/abi/abiERC721Basic.json @@ -0,0 +1,226 @@ +[{ + "anonymous": false, + "inputs": [{ + "indexed": true, + "name": "_from", + "type": "address" + }, { + "indexed": true, + "name": "_to", + "type": "address" + }, { + "indexed": false, + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, { + "anonymous": false, + "inputs": [{ + "indexed": true, + "name": "_owner", + "type": "address" + }, { + "indexed": true, + "name": "_approved", + "type": "address" + }, { + "indexed": false, + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, { + "anonymous": false, + "inputs": [{ + "indexed": true, + "name": "_owner", + "type": "address" + }, { + "indexed": true, + "name": "_operator", + "type": "address" + }, { + "indexed": false, + "name": "_approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, { + "constant": true, + "inputs": [{ + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [{ + "name": "_balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [{ + "name": "_owner", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "exists", + "outputs": [{ + "name": "_exists", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_to", + "type": "address" + }, { + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [{ + "name": "_operator", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_operator", + "type": "address" + }, { + "name": "_approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_owner", + "type": "address" + }, { + "name": "_operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [{ + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_from", + "type": "address" + }, { + "name": "_to", + "type": "address" + }, { + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_from", + "type": "address" + }, { + "name": "_to", + "type": "address" + }, { + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_from", + "type": "address" + }, { + "name": "_to", + "type": "address" + }, { + "name": "_tokenId", + "type": "uint256" + }, { + "name": "_data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/abiERC721Enumerable.json b/abi/abiERC721Enumerable.json new file mode 100644 index 0000000..514d180 --- /dev/null +++ b/abi/abiERC721Enumerable.json @@ -0,0 +1,273 @@ +[{ + "constant": true, + "inputs": [{ + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [{ + "name": "_operator", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_to", + "type": "address" + }, { + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_from", + "type": "address" + }, { + "name": "_to", + "type": "address" + }, { + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_from", + "type": "address" + }, { + "name": "_to", + "type": "address" + }, { + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "exists", + "outputs": [{ + "name": "_exists", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [{ + "name": "_owner", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [{ + "name": "_balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_operator", + "type": "address" + }, { + "name": "_approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_from", + "type": "address" + }, { + "name": "_to", + "type": "address" + }, { + "name": "_tokenId", + "type": "uint256" + }, { + "name": "_data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_owner", + "type": "address" + }, { + "name": "_operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [{ + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "anonymous": false, + "inputs": [{ + "indexed": true, + "name": "_from", + "type": "address" + }, { + "indexed": true, + "name": "_to", + "type": "address" + }, { + "indexed": false, + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, { + "anonymous": false, + "inputs": [{ + "indexed": true, + "name": "_owner", + "type": "address" + }, { + "indexed": true, + "name": "_approved", + "type": "address" + }, { + "indexed": false, + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, { + "anonymous": false, + "inputs": [{ + "indexed": true, + "name": "_owner", + "type": "address" + }, { + "indexed": true, + "name": "_operator", + "type": "address" + }, { + "indexed": false, + "name": "_approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [{ + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_owner", + "type": "address" + }, { + "name": "_index", + "type": "uint256" + } + ], + "name": "tokenOfOwnerByIndex", + "outputs": [{ + "name": "_tokenId", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_index", + "type": "uint256" + } + ], + "name": "tokenByIndex", + "outputs": [{ + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/abiERC721Metadata.json b/abi/abiERC721Metadata.json new file mode 100644 index 0000000..f6dcc56 --- /dev/null +++ b/abi/abiERC721Metadata.json @@ -0,0 +1,266 @@ +[{ + "constant": true, + "inputs": [{ + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [{ + "name": "_operator", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_to", + "type": "address" + }, { + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_from", + "type": "address" + }, { + "name": "_to", + "type": "address" + }, { + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_from", + "type": "address" + }, { + "name": "_to", + "type": "address" + }, { + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "exists", + "outputs": [{ + "name": "_exists", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [{ + "name": "_owner", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [{ + "name": "_balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_operator", + "type": "address" + }, { + "name": "_approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_from", + "type": "address" + }, { + "name": "_to", + "type": "address" + }, { + "name": "_tokenId", + "type": "uint256" + }, { + "name": "_data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_owner", + "type": "address" + }, { + "name": "_operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [{ + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "anonymous": false, + "inputs": [{ + "indexed": true, + "name": "_from", + "type": "address" + }, { + "indexed": true, + "name": "_to", + "type": "address" + }, { + "indexed": false, + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, { + "anonymous": false, + "inputs": [{ + "indexed": true, + "name": "_owner", + "type": "address" + }, { + "indexed": true, + "name": "_approved", + "type": "address" + }, { + "indexed": false, + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, { + "anonymous": false, + "inputs": [{ + "indexed": true, + "name": "_owner", + "type": "address" + }, { + "indexed": true, + "name": "_operator", + "type": "address" + }, { + "indexed": false, + "name": "_approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [{ + "name": "_name", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [{ + "name": "_symbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [{ + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/abiERC721Receiver.json b/abi/abiERC721Receiver.json new file mode 100644 index 0000000..f72978b --- /dev/null +++ b/abi/abiERC721Receiver.json @@ -0,0 +1,24 @@ +[{ + "constant": false, + "inputs": [{ + "name": "_from", + "type": "address" + }, { + "name": "_tokenId", + "type": "uint256" + }, { + "name": "_data", + "type": "bytes" + } + ], + "name": "onERC721Received", + "outputs": [{ + "name": "", + "type": "bytes4" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/abiERC721Token.json b/abi/abiERC721Token.json new file mode 100644 index 0000000..0d03d18 --- /dev/null +++ b/abi/abiERC721Token.json @@ -0,0 +1,325 @@ +[{ + "constant": true, + "inputs": [{ + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [{ + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_to", + "type": "address" + }, { + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_from", + "type": "address" + }, { + "name": "_to", + "type": "address" + }, { + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_from", + "type": "address" + }, { + "name": "_to", + "type": "address" + }, { + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "exists", + "outputs": [{ + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [{ + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [{ + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_to", + "type": "address" + }, { + "name": "_approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": false, + "inputs": [{ + "name": "_from", + "type": "address" + }, { + "name": "_to", + "type": "address" + }, { + "name": "_tokenId", + "type": "uint256" + }, { + "name": "_data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_owner", + "type": "address" + }, { + "name": "_operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [{ + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "inputs": [{ + "name": "_name", + "type": "string" + }, { + "name": "_symbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, { + "anonymous": false, + "inputs": [{ + "indexed": true, + "name": "_from", + "type": "address" + }, { + "indexed": true, + "name": "_to", + "type": "address" + }, { + "indexed": false, + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, { + "anonymous": false, + "inputs": [{ + "indexed": true, + "name": "_owner", + "type": "address" + }, { + "indexed": true, + "name": "_approved", + "type": "address" + }, { + "indexed": false, + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, { + "anonymous": false, + "inputs": [{ + "indexed": true, + "name": "_owner", + "type": "address" + }, { + "indexed": true, + "name": "_operator", + "type": "address" + }, { + "indexed": false, + "name": "_approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [{ + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [{ + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [{ + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_owner", + "type": "address" + }, { + "name": "_index", + "type": "uint256" + } + ], + "name": "tokenOfOwnerByIndex", + "outputs": [{ + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [{ + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { + "constant": true, + "inputs": [{ + "name": "_index", + "type": "uint256" + } + ], + "name": "tokenByIndex", + "outputs": [{ + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/avaxtokenindex.json b/avaxtokenindex.json new file mode 100644 index 0000000..9478e4b --- /dev/null +++ b/avaxtokenindex.json @@ -0,0 +1,64 @@ +{ + "tokens": { + "STG": { + "category": "DEFI", + "chain": "AVAX", + "contractAddress": "0x2f6f07cdcf3588944bf4c42ac74ff24bf56e7590", + "decimals": 18, + "name": "StarGate token", + "origins": [ + "https://snowtrace.io/address/0x2f6f07cdcf3588944bf4c42ac74ff24bf56e7590", + "https://www.coingecko.com/en/coins/stargate-finance" + ], + "symbol": "STG" + }, + "PNG": { + "category": "DEFI", + "chain": "AVAX", + "contractAddress": "0x60781c2586d68229fde47564546784ab3faca982", + "decimals": 18, + "name": "PNG token", + "origins": [ + "https://snowtrace.io/address/0x60781c2586d68229fde47564546784ab3faca982", + "https://www.coingecko.com/en/coins/pangolin" + ], + "symbol": "PNG" + }, + "USDT": { + "category": "STABLECOIN", + "chain": "AVAX", + "contractAddress": "0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7", + "decimals": 18, + "name": "Tether stablecoin token", + "origins": [ + "https://snowtrace.io/address/0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7", + "https://www.coingecko.com/en/coins/tether" + ], + "symbol": "USDT" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "AVAX", + "contractAddress": "0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e", + "decimals": 6, + "name": "USDC stablecoin token", + "origins": [ + "https://snowtrace.io/address/0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e", + "https://www.coingecko.com/en/coins/usd-coin" + ], + "symbol": "USDC" + }, + "DAI": { + "category": "STABLECOIN", + "chain": "AVAX", + "contractAddress": "0xd586e7f844cea2f87f50152665bcbc2c279d8d70", + "decimals": 18, + "name": "DAI stablecoin token", + "origins": [ + "https://snowtrace.io/address/0xd586e7f844cea2f87f50152665bcbc2c279d8d70", + "https://www.coingecko.com/en/coins/dai" + ], + "symbol": "DAI" + } + } +} diff --git a/bitkubnfttokenindex.json b/bitkubnfttokenindex.json new file mode 100644 index 0000000..754e8d8 --- /dev/null +++ b/bitkubnfttokenindex.json @@ -0,0 +1,32 @@ +{ + "erc1155tokens": {}, + "erc721tokens": { + "MMV_ITEM": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xd08ac40b3a0a7fb20b026a3b6cd5d7cfadc3d6f5", + "description": "Morning Moon Village game item", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://www.bkcscan.com/address/0xd08ac40b3a0a7fb20b026a3b6cd5d7cfadc3d6f5", + "https://morningmoonvillage.com/", + "https://mmv.megaland.io/" + ], + "symbol": "MMV_ITEM" + }, + "SANDX": { + "category": "NFT", + "chain": "BITKUB", + "contractAddress": "0x998c4a4f5231b10ad867bd5d99fa181495f34cd8", + "description": "SandX NFT", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://www.bkcscan.com/address/0x998c4a4f5231b10ad867bd5d99fa181495f34cd8", + "https://www.megaland.io/" + ], + "symbol": "SANDX" + } + } +} diff --git a/bitkubtokenindex.json b/bitkubtokenindex.json new file mode 100644 index 0000000..09573a8 --- /dev/null +++ b/bitkubtokenindex.json @@ -0,0 +1,313 @@ +{ + "tokens": { + "MMV_CABBAGESEED": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x1f8b5af0ec97c44b24366b36c40f2d4aca2c73e2", + "decimals": 18, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x1f8b5af0ec97c44b24366b36c40f2d4aca2c73e2/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_CABBAGESEED" + }, + "MMV_TOMATOSOUP": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xbE46a81D181069aC0Ff18F4F7239Df10422E6DC3", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xbE46a81D181069aC0Ff18F4F7239Df10422E6DC3/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_TOMATOSOUP" + }, + "MMV_GREENHERB": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xde496524c30c460922e7810ddc6c806c0e2c5354", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xde496524c30c460922e7810ddc6c806c0e2c5354/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_GREENHERB" + }, + "MMV_SHITAKE_MUSHROOM": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xd3b314b101b26fa2bd19df0d845a632d72c4fc44", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xd3b314b101b26fa2bd19df0d845a632d72c4fc44/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_SHITAKE_MUSHROOM" + }, + "USDT": { + "category": "STABLECOIN", + "chain": "BITKUB", + "contractAddress": "0x7d984c24d2499d840eb3b7016077164e15e5faa6", + "decimals": 18, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x7d984c24d2499d840eb3b7016077164e15e5faa6/token-transfers" + ], + "symbol": "USDT" + }, + "MMV_TOMATOSEED": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xe991151Bf43bD712beAC33e5cFF2580841c9b440", + "decimals": 18, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xe991151Bf43bD712beAC33e5cFF2580841c9b440/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_TOMATOSEED" + }, + "MMV_LEATHER_PIECE": { + "category": "DEFI", + "chain": "BITKUB", + "contractAddress": "0x15aa87eb74069d3800f8e75A93FC04fda79AA24d", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x15aa87eb74069d3800f8e75A93FC04fda79AA24d/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_LEATHER_PIECE" + }, + "MMV_HONEY": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x575d7bfdbdf255d5741571334f159d903de1544f", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x575d7bfdbdf255d5741571334f159d903de1544f/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_HONEY" + }, + "KKUB": { + "category": "DEFI", + "chain": "BITKUB", + "contractAddress": "0x67eBD850304c70d983B2d1b93ea79c7CD6c3F6b5", + "decimals": 18, + "name": "Wrapped KUB (KKUB) token", + "origins": [ + "https://www.bkcscan.com/tokens/0x67eBD850304c70d983B2d1b93ea79c7CD6c3F6b5/token-transfers" + ], + "symbol": "KKUB" + }, + "MMV_SF_CABBAGE": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xc2990515610028139f68016b321a0c36a5101104", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xc2990515610028139f68016b321a0c36a5101104/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_SF_CABBAGE" + }, + "MMV_SILVERKEY": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x73d05f935534918bbc87cb353928cb957ed03697", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x73d05f935534918bbc87cb353928cb957ed03697/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_SILVERKEY" + }, + "MMV_LUMI": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x95013dcb6a561e6c003aed9c43fb8b64008aa361", + "decimals": 18, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x95013dcb6a561e6c003aed9c43fb8b64008aa361/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_LUMI" + }, + "MMV_DRIEDAPPLE": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xb035c229903a0cff939be36b532d8c11204e6837", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xb035c229903a0cff939be36b532d8c11204e6837/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_DRIEDAPPLE" + }, + "MMV_BANANA": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x0944882cf373adc8c3de740821fb14c8669e89eb", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x0944882cf373adc8c3de740821fb14c8669e89eb/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_BANANA" + }, + "MMV_REDHERB": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x3F69C740456150268C5e23bD05a2A10Bf9e5c3CB", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x3F69C740456150268C5e23bD05a2A10Bf9e5c3CB/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_REDHERB" + }, + "MMV_HEALTHPOTION": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xbd60c8caf6e22907576d9e363ab1f91b43aaf769", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xbd60c8caf6e22907576d9e363ab1f91b43aaf769/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_HEALTHPOTION" + }, + "MMV_DIAMON_LP": { + "category": "DEFI", + "chain": "BITKUB", + "contractAddress": "0x7Bf51541208A70b784006eF7Bd6F774F4012Cd38", + "decimals": 18, + "name": "Morning Moon Village diamon LP", + "origins": [ + "https://www.bkcscan.com/tokens/0x7Bf51541208A70b784006eF7Bd6F774F4012Cd38/token-transfers" + ], + "symbol": "MMV_DIAMON_LP" + }, + "MMV_RAG": { + "category": "DEFI", + "chain": "BITKUB", + "contractAddress": "0x1F14690e6c7D02fCeB67c6b818aa2C093e16fe27", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x1F14690e6c7D02fCeB67c6b818aa2C093e16fe27/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_RAG" + }, + "MMV_KTRUMPET_MUSHROOM": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xc14f24835efe355106ab8725488f16f93c8c5f96", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xc14f24835efe355106ab8725488f16f93c8c5f96/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_KTRUMPET_MUSHROOM" + }, + "MMV_CORNSEED": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xe27aebed61be207e83fc05fbc408420c737881da", + "decimals": 18, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xe27aebed61be207e83fc05fbc408420c737881da/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_CORNSEED" + }, + "MMV_GREENAPPLE": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x417e28bd41cd45d9f996b69450f81b02821a6d64", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x417e28bd41cd45d9f996b69450f81b02821a6d64/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_GREENAPPLE" + }, + "MMV_CARROTSEED": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x7b263d648fff39142abecb07a1bb85297e09982d", + "decimals": 18, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x7b263d648fff39142abecb07a1bb85297e09982d/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_CARROTSEED" + }, + "MMV_LHEALTHPOTION": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xe66f21d817af8f99129af6023332dd7b37503b9d", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xe66f21d817af8f99129af6023332dd7b37503b9d/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_LHEALTHPOTION" + }, + "MMV_SALAD": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x2944d051dc66669e04629b827ae9e3ebcb1e48d9", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x2944d051dc66669e04629b827ae9e3ebcb1e48d9/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_SALAD" + }, + "MMV_CORNSOUP": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x2b09ae76dfc601210407560502b340e104787b34", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x2b09ae76dfc601210407560502b340e104787b34/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_CORNSOUP" + }, + "MMV_WBUTTON_MUSHROOM": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xcb74a1A9dB4285E97D4dE8aa4B61cd10277Ab479", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xcb74a1A9dB4285E97D4dE8aa4B61cd10277Ab479/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_WBUTTON_MUSHROOM" + } + } +} diff --git a/bscnfttokenindex.json b/bscnfttokenindex.json new file mode 100644 index 0000000..a880ffd --- /dev/null +++ b/bscnfttokenindex.json @@ -0,0 +1,100 @@ +{ + "erc1155tokens": {}, + "erc721tokens": { + "DREAMCARD": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0xe6965b4f189dbdb2bd65e60abaeb531b6fe9580b", + "description": "X World Games Dreamcard", + "linked_tokens": [ + "BSC:XWG" + ], + "mintBlock": 0, + "origins": [ + "https://bscscan.com/address/0xe6965b4f189dbdb2bd65e60abaeb531b6fe9580b", + "https://babylons.io/outerringofficial" + ], + "symbol": "DREAMCARD" + }, + "OUTERRINGMMO_SPACEVEH": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0xceaac6759038d4d3b8791683b27b1021efa57003", + "description": "Outer Ring MMO Space Vehicle", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://bscscan.com/token/0xceaac6759038d4d3b8791683b27b1021efa57003", + "https://babylons.io/outerringofficial" + ], + "symbol": "OUTERRINGMMO_SPACEVEH" + }, + "OUTERRINGMMO_ARMOR": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x0b36f379d7b3b4588f8b8e7e65091b2c44fa6dde", + "description": "Outer Ring MMO Armor", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://bscscan.com/token/0x0b36f379d7b3b4588f8b8e7e65091b2c44fa6dde", + "https://babylons.io/outerringofficial" + ], + "symbol": "OUTERRINGMMO_ARMOR" + }, + "OUTERRINGMMO_EXOCRED": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x3fb6e0dd0eefff9615f186a6bb3a66a396ed0a58", + "description": "Outer Ring MMO Exocredits", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://bscscan.com/address/0x3fb6e0dd0eefff9615f186a6bb3a66a396ed0a58", + "https://babylons.io/outerringofficial" + ], + "symbol": "OUTERRINGMMO_EXOCRED" + }, + "OUTERRINGMMO_LANDVEH": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x21d7d56350fcf7470e4ac38bb2f32c1461a73d8c", + "description": "Outer Ring MMO Land Vehicle", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://bscscan.com/token/0x21d7d56350fcf7470e4ac38bb2f32c1461a73d8c", + "https://babylons.io/outerringofficial" + ], + "symbol": "OUTERRINGMMO_LANDVEH" + }, + "STELLAFANTASY_ASSET": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x80461f88de22b2363113226f0749a7a59cc2225a", + "description": "Stella Fantasy Asset", + "linked_tokens": [ + "BSC:SFTY" + ], + "mintBlock": 0, + "origins": [ + "https://bscscan.com/token/0x80461f88de22b2363113226f0749a7a59cc2225a", + "https://www.stellafantasy.io/" + ], + "symbol": "STELLAFANTASY_ASSET" + }, + "OUTERRINGMMO_WEAPON": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0xeb1aca4e9aa3448b7fecb2b555301325b5931ad9", + "description": "Outer Ring MMO Weapon", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://bscscan.com/token/0xeb1aca4e9aa3448b7fecb2b555301325b5931ad9", + "https://babylons.io/outerringofficial" + ], + "symbol": "OUTERRINGMMO_WEAPON" + } + } +} diff --git a/bsctokenindex.json b/bsctokenindex.json new file mode 100644 index 0000000..a036ca4 --- /dev/null +++ b/bsctokenindex.json @@ -0,0 +1,364 @@ +{ + "tokens": { + "STARGATE_BUSD_LP": { + "category": "LIQUIDITY_PROVIDER", + "chain": "BSC", + "contractAddress": "0x98a5737749490856b401db5dc27f522fc314a4e1", + "decimals": 18, + "name": "StarGate sBUSD Pool token", + "origins": [ + "https://bscscan.com/token/0x98a5737749490856b401db5dc27f522fc314a4e1" + ], + "symbol": "STARGATE_BUSD_LP" + }, + "SUPS": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0xc99cfaa8f5d9bd9050182f29b83cc9888c5846c4", + "decimals": 18, + "name": "Supremacy game token", + "origins": [ + "https://bscscan.com/address/0xc99cfaa8f5d9bd9050182f29b83cc9888c5846c4", + "https://www.coingecko.com/en/coins/supremacy" + ], + "symbol": "SUPS" + }, + "VAN": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0xd3dbf84f7aed90d5f56e8d7cab2f43004e9ef6a6", + "decimals": 18, + "name": "Outer Ring MMO Vanadium Token", + "origins": [ + "https://bscscan.com/token/0xd3dbf84f7aed90d5f56e8d7cab2f43004e9ef6a6" + ], + "symbol": "VAN" + }, + "STG": { + "category": "DEFI", + "chain": "BSC", + "contractAddress": "0xb0d502e938ed5f4df2e681fe6e419ff29631d62b", + "decimals": 18, + "name": "StarGate token", + "origins": [ + "https://bscscan.com/address/0xb0d502e938ed5f4df2e681fe6e419ff29631d62b", + "https://www.coingecko.com/en/coins/stargate-finance" + ], + "symbol": "STG" + }, + "USDT": { + "category": "STABLECOIN", + "chain": "BSC", + "contractAddress": "0x55d398326f99059ff775485246999027b3197955", + "decimals": 18, + "name": "Tether stablecoin token", + "origins": [ + "https://bscscan.com/address/0x55d398326f99059ff775485246999027b3197955", + "https://www.coingecko.com/en/coins/tether" + ], + "symbol": "USDT" + }, + "XVS": { + "category": "DEFI", + "chain": "BSC", + "contractAddress": "0xcf6bb5389c92bdda8a3747ddb454cb7a64626c63", + "decimals": 18, + "name": "Venus Token", + "origins": [ + "https://bscscan.com/address/0xcf6bb5389c92bdda8a3747ddb454cb7a64626c63", + "https://www.coingecko.com/en/coins/venus" + ], + "symbol": "XVS" + }, + "PLU": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x07958be5d12365db62a6535d0a88105944a2e81e", + "decimals": 18, + "name": "Outer Ring MMO Plutonium Token", + "origins": [ + "https://bscscan.com/token/0x07958be5d12365db62a6535d0a88105944a2e81e" + ], + "symbol": "PLU" + }, + "ACE": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x6bf6c2b429421a55d90a02c56b2d8bffbc636039", + "decimals": 18, + "name": "Outer Ring MMO Acetylene Token", + "origins": [ + "https://bscscan.com/token/0x6bf6c2b429421a55d90a02c56b2d8bffbc636039" + ], + "symbol": "ACE" + }, + "COP": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x892f23e32b82ef0d5394cf33dcd4dff7f4b274b0", + "decimals": 18, + "name": "Outer Ring MMO Copper Token", + "origins": [ + "https://bscscan.com/token/0x892f23e32b82ef0d5394cf33dcd4dff7f4b274b0" + ], + "symbol": "COP" + }, + "CHMB": { + "category": "DEFI", + "chain": "BSC", + "contractAddress": "0x5492ef6aeeba1a3896357359ef039a8b11621b45", + "decimals": 18, + "name": "Chumbi Valley Game Token", + "origins": [ + "https://bscscan.com/token/0x5492ef6aeeba1a3896357359ef039a8b11621b45", + "https://www.coingecko.com/en/coins/chumbai-valley" + ], + "symbol": "CHMB" + }, + "VIKINGSWAP": { + "category": "DEFI", + "chain": "BSC", + "contractAddress": "0x896ede222d3f7f3414e136a2791bdb08aaa25ce0", + "decimals": 18, + "name": "Vikingswap Token", + "origins": [ + "https://bscscan.com/address/0x896ede222d3f7f3414e136a2791bdb08aaa25ce0", + "https://www.coingecko.com/en/coins/viking-swap" + ], + "symbol": "VIKINGSWAP" + }, + "BABYCAKE": { + "category": "DEFI", + "chain": "BSC", + "contractAddress": "0xdb8d30b74bf098af214e862c90e647bbb1fcc58c", + "decimals": 18, + "name": "BABYCAKE DEFI reflection Token", + "origins": [ + "https://bscscan.com/token/0xdb8d30b74bf098af214e862c90e647bbb1fcc58c", + "https://www.coingecko.com/en/coins/baby-cake" + ], + "symbol": "BABYCAKE" + }, + "CAKE": { + "category": "DEFI", + "chain": "BSC", + "contractAddress": "0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82", + "decimals": 18, + "name": "Pancakeswap DEFI Token", + "origins": [ + "https://bscscan.com/token/0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82", + "https://www.coingecko.com/en/coins/pancakeswap" + ], + "symbol": "CAKE" + }, + "MOBOX": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x3203c9e46ca618c8c1ce5dc67e7e9d75f5da2377", + "decimals": 18, + "name": "MOBOX game token", + "origins": [ + "https://bscscan.com/address/0x3203c9e46ca618c8c1ce5dc67e7e9d75f5da2377", + "https://www.coingecko.com/en/coins/mobox" + ], + "symbol": "MOBOX" + }, + "NIC": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0xf9a71cba51e260e184a72d9edf888d3f99f3bac1", + "decimals": 18, + "name": "Outer Ring MMO Nickel Token", + "origins": [ + "https://bscscan.com/token/0xf9a71cba51e260e184a72d9edf888d3f99f3bac1" + ], + "symbol": "NIC" + }, + "XWG": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x6b23c89196deb721e6fd9726e6c76e4810a464bc", + "decimals": 18, + "name": "X World Games Token", + "origins": [ + "https://bscscan.com/address/0x6b23c89196deb721e6fd9726e6c76e4810a464bc", + "https://www.coingecko.com/en/coins/x-world-games" + ], + "symbol": "XWG" + }, + "GQ": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0xf700d4c708c2be1463e355f337603183d20e0808", + "decimals": 18, + "name": "Outer Ring MMO Game Token", + "origins": [ + "https://bscscan.com/address/0xf700d4c708c2be1463e355f337603183d20e0808", + "https://www.coingecko.com/en/coins/outer-ring" + ], + "symbol": "GQ" + }, + "IRON": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0xbd1945cd85a2be93a6475381c9f5edf19407a921", + "decimals": 18, + "name": "Outer Ring MMO Iron Token", + "origins": [ + "https://bscscan.com/token/0xbd1945cd85a2be93a6475381c9f5edf19407a921" + ], + "symbol": "IRON" + }, + "DAI": { + "category": "STABLECOIN", + "chain": "BSC", + "contractAddress": "0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3", + "decimals": 18, + "name": "DAI stablecoin token", + "origins": [ + "https://bscscan.com/address/0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3", + "https://www.coingecko.com/en/coins/dai" + ], + "symbol": "DAI" + }, + "CAR": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x253b7a24003684f7b4fe87e531a017c7382a3894", + "decimals": 18, + "name": "Outer Ring MMO Carbon Token", + "origins": [ + "https://bscscan.com/token/0x253b7a24003684f7b4fe87e531a017c7382a3894" + ], + "symbol": "CAR" + }, + "TEST": { + "category": "TEST", + "chain": "BSC", + "contractAddress": "0x1c3c3941acb8a9be35e50f086fae6a481f7d9df7", + "decimals": 18, + "name": "TEST token", + "origins": [ + "https://bscscan.com/token/0xMOJO" + ], + "symbol": "TEST" + }, + "ARG": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x0efcf1737b81ce89325b17eafae2686a8afe8bd4", + "decimals": 18, + "name": "Outer Ring MMO Acetylene Token", + "origins": [ + "https://bscscan.com/token/0x0efcf1737b81ce89325b17eafae2686a8afe8bd4" + ], + "symbol": "ARG" + }, + "SCK": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x227a3ef4d41d0215123f3197faa087bf71d2236a", + "decimals": 18, + "name": "Space Corsair Key", + "origins": [ + "https://bscscan.com/address/0x227a3ef4d41d0215123f3197faa087bf71d2236a", + "https://www.coingecko.com/en/coins/space-corsair-key" + ], + "symbol": "SCK" + }, + "TRON": { + "category": "SCAM", + "chain": "BSC", + "contractAddress": "0x85eac5ac2f758618dfa09bdbe0cf174e7d574d5b", + "decimals": 18, + "name": "TRON TRX token", + "origins": [ + "https://coinmarketcap.com/currencies/tron/" + ], + "symbol": "TRON" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "BSC", + "contractAddress": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "decimals": 6, + "name": "USDC stablecoin token", + "origins": [ + "https://bscscan.com/address/0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "https://www.coingecko.com/en/coins/usd-coin" + ], + "symbol": "USDC" + }, + "METIS": { + "category": "GASCURRENCY", + "chain": "BSC", + "contractAddress": "0xe552fb52a4f19e44ef5a967632dbc320b0820639", + "decimals": 18, + "name": "METIS token on BSC", + "origins": [ + "https://bscscan.com/address/0xe552fb52a4f19e44ef5a967632dbc320b0820639", + "https://www.coingecko.com/en/coins/metis-token" + ], + "symbol": "METIS" + }, + "BUSD": { + "category": "STABLECOIN", + "chain": "BSC", + "contractAddress": "0xe9e7cea3dedca5984780bafc599bd69add087d56", + "decimals": 18, + "name": "Binance stablecoin token", + "origins": [ + "https://bscscan.com/address/0xe9e7cea3dedca5984780bafc599bd69add087d56", + "https://www.coingecko.com/en/coins/binance-usd" + ], + "symbol": "BUSD" + }, + "NFTART": { + "category": "DEFI", + "chain": "BSC", + "contractAddress": "0xf7844cb890f4c339c497aeab599abdc3c874b67a", + "decimals": 18, + "name": "NFT Art Token", + "origins": [ + "https://bscscan.com/address/0xf7844cb890f4c339c497aeab599abdc3c874b67a", + "https://www.coingecko.com/en/coins/nft-art-finance" + ], + "symbol": "NFTART" + }, + "MET": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x03697caf2e5458c7c2a8d9f8818079c2ae72f353", + "decimals": 18, + "name": "Outer Ring MMO Methane Token", + "origins": [ + "https://bscscan.com/token/0x03697caf2e5458c7c2a8d9f8818079c2ae72f353" + ], + "symbol": "MET" + }, + "SFTY": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0xe9d6d6d7cde5c7d45927f8c37460d932e612c902", + "decimals": 18, + "name": "Stella Fantasy gaming token", + "origins": [ + "https://bscscan.com/address/0xe9d6d6d7cde5c7d45927f8c37460d932e612c902", + "https://www.coingecko.com/en/coins/stella-fantasy-token" + ], + "symbol": "SFTY" + }, + "CATGIRL": { + "category": "NFT", + "chain": "BSC", + "contractAddress": "0x79ebc9a2ce02277a4b5b3a768b1c0a4ed75bd936", + "decimals": 18, + "name": "Catgirl NFT Token", + "origins": [ + "https://bscscan.com/address/0x79ebc9a2ce02277a4b5b3a768b1c0a4ed75bd936", + "https://www.coingecko.com/en/coins/catgirl" + ], + "symbol": "CATGIRL" + } + } +} diff --git a/celotokenindex.json b/celotokenindex.json new file mode 100644 index 0000000..2fab48c --- /dev/null +++ b/celotokenindex.json @@ -0,0 +1,27 @@ +{ + "tokens": { + "ZEROCASINO": { + "category": "TEST", + "chain": "CELO", + "contractAddress": "0xbccEc3bfd4639440b1714a502bb3940F407b890A", + "decimals": 18, + "name": "0CASINO token", + "origins": [ + "https://explorer.celo.org/token/0xbccEc3bfd4639440b1714a502bb3940F407b890A" + ], + "symbol": "ZEROCASINO" + }, + "cUSD": { + "category": "STABLECOIN", + "chain": "CELO", + "contractAddress": "0x765DE816845861e75A25fCA122bb6898B8B1282a", + "decimals": 18, + "name": "CELO USD stable token", + "origins": [ + "https://explorer.celo.org/token/0x765DE816845861e75A25fCA122bb6898B8B1282a", + "https://www.coingecko.com/en/coins/celo-dollar" + ], + "symbol": "cUSD" + } + } +} diff --git a/clients/ethers/blocknr/blocknr.js b/clients/ethers/blocknr/blocknr.js new file mode 100644 index 0000000..029006b --- /dev/null +++ b/clients/ethers/blocknr/blocknr.js @@ -0,0 +1,18 @@ +const ethers = require('ethers'); +const fs = require('fs') +const evmchainindex = require('../../../evmchainindex.json'); + +const nodeURLs = evmchainindex['networks']['ETHEREUM'].nodeURLs; +var providerurl = nodeURLs[Math.floor(Math.random() * nodeURLs.length)]; +console.log(' - using providerurl: ' + providerurl); + +// Initiate provider +var provider = new ethers.providers.JsonRpcProvider(providerurl); + +const getBlock = async() => { + const blocknr = await provider.getBlockNumber(); + console.log(" - latest block: ", blocknr); +} + +getBlock(); + diff --git a/clients/ethers/blocknr/package.json b/clients/ethers/blocknr/package.json new file mode 100644 index 0000000..ca2d196 --- /dev/null +++ b/clients/ethers/blocknr/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "ethers": "^5.7.0" + } +} diff --git a/clients/web3j/nft/abi/BoredApe.json b/clients/web3j/nft/abi/BoredApe.json new file mode 100644 index 0000000..8ea9a3e --- /dev/null +++ b/clients/web3j/nft/abi/BoredApe.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"maxNftSupply","type":"uint256"},{"internalType":"uint256","name":"saleStart","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"BAYC_PROVENANCE","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_APES","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REVEAL_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"apePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencySetStartingIndexBlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"flipSaleState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxApePurchase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"numberOfTokens","type":"uint256"}],"name":"mintApe","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserveApes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"saleIsActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"provenanceHash","type":"string"}],"name":"setProvenanceHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"revealTimeStamp","type":"uint256"}],"name":"setRevealTimestamp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setStartingIndex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startingIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startingIndexBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}] diff --git a/clients/web3j/nft/abi/erc20.json b/clients/web3j/nft/abi/erc20.json new file mode 100644 index 0000000..06b572d --- /dev/null +++ b/clients/web3j/nft/abi/erc20.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/clients/web3j/nft/abi/erc721.json b/clients/web3j/nft/abi/erc721.json new file mode 100644 index 0000000..0195698 --- /dev/null +++ b/clients/web3j/nft/abi/erc721.json @@ -0,0 +1,388 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "_approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "tokenByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "tokenOfOwnerByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/clients/web3j/nft/boredape.js b/clients/web3j/nft/boredape.js new file mode 100644 index 0000000..c14ea1c --- /dev/null +++ b/clients/web3j/nft/boredape.js @@ -0,0 +1,38 @@ +const Web3 = require('web3'); +const fs = require('fs') +const evmchainindex = require('../../../evmchainindex.json'); + +const nodeURLs = evmchainindex['networks']['ETHEREUM'].nodeURLs; +var providerurl = nodeURLs[Math.floor(Math.random() * nodeURLs.length)]; +console.log(' - using providerurl: ' + providerurl); + +// BoredApe address +const boredape_ca = evmchainindex['networks']['ETHEREUM']['nftindex']['erc721tokens']['BORED_APE'].contractAddress; +console.log(" - BoredApe contract_address:", boredape_ca.toString()); + +// Initiate web3 +const web3Provider = new Web3.providers.HttpProvider(providerurl); +const web3 = new Web3(web3Provider); + +// Get the contract ABI, https://etherscan.io/address/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d#code +const boredape_abi = JSON.parse(fs.readFileSync('./abi/erc721.json', 'utf8')); +const BoredApe = new web3.eth.Contract(boredape_abi, boredape_ca); + +(async function() { + + const blocknr = await web3.eth.getBlockNumber(); + console.log(" - latest block: ", blocknr); + + const nodeversion = await web3.eth.getNodeInfo(); + console.log(" - RPC node is running client: " + nodeversion); + + const chainid = await web3.eth.getChainId(); + console.log(" - RPC node has chainid: " + chainid); + + let totalSupply = await BoredApe.methods.totalSupply().call(); + console.log(" - ERC721 BoredApe totalSupply: " + totalSupply); + + let tokenURI = await BoredApe.methods.tokenURI(0).call(); + console.log(" - ERC721 BoredApe tokenURI: " + tokenURI); + +})(); diff --git a/clients/web3j/nft/package.json b/clients/web3j/nft/package.json new file mode 100644 index 0000000..bf73a02 --- /dev/null +++ b/clients/web3j/nft/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "web3": "^1.7.5" + } +} diff --git a/clients/web3j/sign/package.json b/clients/web3j/sign/package.json new file mode 100644 index 0000000..bf73a02 --- /dev/null +++ b/clients/web3j/sign/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "web3": "^1.7.5" + } +} diff --git a/clients/web3j/sign/sign.js b/clients/web3j/sign/sign.js new file mode 100644 index 0000000..e9bc6d1 --- /dev/null +++ b/clients/web3j/sign/sign.js @@ -0,0 +1,19 @@ +const Web3 = require('web3'); +const evmchainindex = require('../../../evmchainindex.json'); + +const nodeURLs = evmchainindex['networks']['POLYGON'].nodeURLs; +var providerurl = nodeURLs[Math.floor(Math.random() * nodeURLs.length)]; +console.log(' - using providerurl: ' + providerurl); + +// Initiate web3 +const web3Provider = new Web3.providers.HttpProvider(providerurl); +const web3 = new Web3(web3Provider); + +// https://medium.com/singapore-blockchain-dapps/ethereum-using-web3-js-for-message-signing-a542676b50b5 +const sig = web3.eth.accounts.sign("Hello, I am Kenneth!", '0xb5b1870957d373ef0eeffecc6e4812c0fd08f554b37b233526acc331bf1544f7'); +console.log(" - sig.message: " + sig.message); +console.log(" - sig.signature: " + sig.signature); +console.log(" - sig.r: " + sig.r); +console.log(" - sig.s: " + sig.s); +console.log(" - sig.v: " + sig.v); + diff --git a/ethereumnfttokenindex.json b/ethereumnfttokenindex.json new file mode 100644 index 0000000..abf5dbb --- /dev/null +++ b/ethereumnfttokenindex.json @@ -0,0 +1,74 @@ +{ + "erc1155tokens": {}, + "erc721tokens": { + "BORED_APE": { + "category": "GAMING", + "chain": "ETHEREUM", + "contractAddress": "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", + "description": "Bored Ape NFT", + "linked_tokens": [ + "ETHEREUM:APECOIN" + ], + "mintBlock": 0, + "origins": [ + "https://etherscan.io/address/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", + "https://opensea.io/collection/boredapeyachtclub" + ], + "symbol": "BORED_APE" + }, + "ENS_DOMAIN": { + "category": "NAMESERVICE", + "chain": "ETHEREUM", + "contractAddress": "0x57f1887a8bf19b14fc0df6fd9b2acc9af147ea85", + "description": "Ethereum Name Service Domain NFT", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://etherscan.io/token/0x57f1887a8bf19b14fc0df6fd9b2acc9af147ea85", + "https://opensea.io/collection/ens" + ], + "symbol": "ENS_DOMAIN" + }, + "LUCHADORES": { + "category": "GAMING", + "chain": "ETHEREUM", + "contractAddress": "0x8b4616926705fb61e9c4eeac07cd946a5d4b0760", + "description": "Luchadores game NFT", + "linked_tokens": [ + "POLYGON:LUCHA" + ], + "mintBlock": 0, + "origins": [ + "https://etherscan.io/address/0x8b4616926705fb61e9c4eeac07cd946a5d4b0760", + "https://opensea.io/collection/luchadores-io" + ], + "symbol": "LUCHADORES" + }, + "WWW_LAND": { + "category": "GAMING", + "chain": "ETHEREUM", + "contractAddress": "0xa1d4657e0e6507d5a94d06da93e94dc7c8c44b51", + "description": "World Wide Webb game NFT", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://etherscan.io/address/0xa1d4657e0e6507d5a94d06da93e94dc7c8c44b51", + "https://opensea.io/collection/worldwidewebbland" + ], + "symbol": "WWW_LAND" + }, + "UNSTOPPABLE_DOMAIN": { + "category": "NAMESERVICE", + "chain": "ETHEREUM", + "contractAddress": "0x049aba7510f45ba5b64ea9e658e342f904db358d", + "description": "Unstoppable Domains NFT", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://etherscan.io/token/0x049aba7510f45ba5b64ea9e658e342f904db358d", + "https://opensea.io/collection/unstoppable-domains" + ], + "symbol": "UNSTOPPABLE_DOMAIN" + } + } +} diff --git a/ethereumtokenindex.json b/ethereumtokenindex.json new file mode 100644 index 0000000..4ed8e95 --- /dev/null +++ b/ethereumtokenindex.json @@ -0,0 +1,243 @@ +{ + "tokens": { + "APECOIN": { + "category": "GAMING", + "chain": "ETHEREUM", + "contractAddress": "0x4d224452801aced8b2f0aebe155379bb5d594381", + "decimals": 18, + "name": "Bored Ape game token", + "origins": [ + "https://www.coingecko.com/en/coins/apecoin", + "https://etherscan.io/address/0x4d224452801aced8b2f0aebe155379bb5d594381" + ], + "symbol": "APECOIN" + }, + "CULT": { + "category": "MEME", + "chain": "ETHEREUM", + "contractAddress": "0xf0f9d895aca5c8678f706fb8216fa22957685a13", + "decimals": 18, + "name": "The CULT DAO token", + "origins": [ + "https://etherscan.io/address/0xf0f9d895aca5c8678f706fb8216fa22957685a13", + "https://www.coingecko.com/en/coins/cult-dao" + ], + "symbol": "CULT" + }, + "VIDYA": { + "category": "GAMING", + "chain": "ETHEREUM", + "contractAddress": "0x3d3d35bb9bec23b06ca00fe472b50e7a4c692c30", + "decimals": 18, + "name": "VIDYA token", + "origins": [ + "https://etherscan.io/address/0x3d3d35bb9bec23b06ca00fe472b50e7a4c692c30", + "https://www.coingecko.com/en/coins/vidya" + ], + "symbol": "VIDYA" + }, + "TRAC": { + "category": "SUPPLYCHAIN", + "chain": "ETHEREUM", + "contractAddress": "0xaa7a9ca87d3694b5755f213b5d04094b8d0f0a6f", + "decimals": 18, + "name": "OriginTrail token", + "origins": [ + "https://etherscan.io/address/0xaa7a9ca87d3694b5755f213b5d04094b8d0f0a6f", + "https://www.coingecko.com/en/coins/origintrail" + ], + "symbol": "TRAC" + }, + "USDT": { + "category": "STABLECOIN", + "chain": "ETHEREUM", + "contractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7", + "decimals": 6, + "name": "Tether stablecoin token", + "origins": [ + "https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7", + "https://www.coingecko.com/en/coins/tether" + ], + "symbol": "USDT" + }, + "SERUM": { + "category": "DEFI", + "chain": "ETHEREUM", + "contractAddress": "0x476c5e26a75bd202a9683ffd34359c0cc15be0ff", + "decimals": 18, + "name": "Serum token", + "origins": [ + "https://etherscan.io/address/0x476c5e26a75bd202a9683ffd34359c0cc15be0ff", + "https://www.coingecko.com/en/coins/serum" + ], + "symbol": "SERUM" + }, + "DINU": { + "category": "MEME", + "chain": "ETHEREUM", + "contractAddress": "0xbb1ee07d6c7baeb702949904080eb61f5d5e7732", + "decimals": 18, + "name": "The Dogey-Inu token", + "origins": [ + "https://etherscan.io/address/0xbb1ee07d6c7baeb702949904080eb61f5d5e7732", + "https://www.coingecko.com/en/coins/dogey-inu" + ], + "symbol": "DINU" + }, + "DAI": { + "category": "STABLECOIN", + "chain": "ETHEREUM", + "contractAddress": "0x6b175474e89094c44da98b954eedeac495271d0f", + "decimals": 18, + "name": "DAI stablecoin token", + "origins": [ + "https://etherscan.io/address/0x6b175474e89094c44da98b954eedeac495271d0f", + "https://www.coingecko.com/en/coins/dai" + ], + "symbol": "DAI" + }, + "DOBE": { + "category": "MEME", + "chain": "ETHEREUM", + "contractAddress": "0xe7ab45162f5979f09b0bda1cc7dfc97c270ea3d5", + "decimals": 18, + "name": "The Dobermann token", + "origins": [ + "https://etherscan.io/address/0xe7ab45162f5979f09b0bda1cc7dfc97c270ea3d5", + "https://www.coingecko.com/en/coins/dobermann" + ], + "symbol": "DOBE" + }, + "DOJO": { + "category": "MEME", + "chain": "ETHEREUM", + "contractAddress": "0x180dae91d6d56235453a892d2e56a3e40ba81df8", + "decimals": 18, + "name": "The DOJO token", + "origins": [ + "https://etherscan.io/address/0x180dae91d6d56235453a892d2e56a3e40ba81df8", + "https://www.coingecko.com/en/coins/dojo" + ], + "symbol": "DOJO" + }, + "FWB": { + "category": "SOCIAL", + "chain": "ETHEREUM", + "contractAddress": "0x35bd01fc9d6d5d81ca9e055db88dc49aa2c699a8", + "decimals": 18, + "name": "Friends With Benefits token", + "origins": [ + "https://etherscan.io/address/0x35bd01fc9d6d5d81ca9e055db88dc49aa2c699a8", + "https://www.coingecko.com/en/coins/friends-with-benefits-pro" + ], + "symbol": "FWB" + }, + "JINDOGE": { + "category": "MEME", + "chain": "ETHEREUM", + "contractAddress": "0x3f4cd830543db25254ec0f05eac058d4d6e86166", + "decimals": 18, + "name": "The Jindoge token", + "origins": [ + "https://etherscan.io/address/0x3f4cd830543db25254ec0f05eac058d4d6e86166", + "https://www.coingecko.com/en/coins/jindoge" + ], + "symbol": "JINDOGE" + }, + "JSHIBA": { + "category": "MEME", + "chain": "ETHEREUM", + "contractAddress": "0x1426cc6d52d1b14e2b3b1cb04d57ea42b39c4c7c", + "decimals": 18, + "name": "The Jomon Shiba token", + "origins": [ + "https://etherscan.io/address/0x1426cc6d52d1b14e2b3b1cb04d57ea42b39c4c7c", + "https://www.coingecko.com/en/coins/jomon-shiba" + ], + "symbol": "JSHIBA" + }, + "NB": { + "category": "MEME", + "chain": "ETHEREUM", + "contractAddress": "0x20be82943e8d9c682580e11d424ec15db95b4a24", + "decimals": 18, + "name": "The No Bull token", + "origins": [ + "https://etherscan.io/address/0x20be82943e8d9c682580e11d424ec15db95b4a24", + "https://www.coingecko.com/en/coins/no-bull" + ], + "symbol": "NB" + }, + "SHUSHKY": { + "category": "MEME", + "chain": "ETHEREUM", + "contractAddress": "0x236d53148f83706c3d670064809577385f923a75", + "decimals": 18, + "name": "The Siberian Husky token", + "origins": [ + "https://etherscan.io/address/0x236d53148f83706c3d670064809577385f923a75", + "https://www.coingecko.com/en/coins/siberian-husky" + ], + "symbol": "SHUSHKY" + }, + "TEST": { + "category": "TEST", + "chain": "ETHEREUM", + "contractAddress": "0x2b591e99afe9f32eaa6214f7b7629768c40eeb39", + "decimals": 18, + "name": "TEST token", + "origins": [ + "https://etherscan.io/token/0xMOJO" + ], + "symbol": "TEST" + }, + "SOS": { + "category": "NFT", + "chain": "ETHEREUM", + "contractAddress": "0x3b484b82567a09e2588a13d54d032153f0c0aee0", + "decimals": 18, + "name": "The OpenDAO SOS token", + "origins": [ + "https://etherscan.io/address/0x3b484b82567a09e2588a13d54d032153f0c0aee0", + "https://www.coingecko.com/en/coins/opendao" + ], + "symbol": "SOS" + }, + "UNIDX": { + "category": "DEFI", + "chain": "ETHEREUM", + "contractAddress": "0x95b3497bbcccc46a8f45f5cf54b0878b39f8d96c", + "decimals": 18, + "name": "UniDex token", + "origins": [ + "https://etherscan.io/address/0x95b3497bbcccc46a8f45f5cf54b0878b39f8d96c", + "https://www.coingecko.com/en/coins/unidex" + ], + "symbol": "UNIDX" + }, + "XOR": { + "category": "UNKNOWN", + "chain": "ETHEREUM", + "contractAddress": "0x40fd72257597aa14c7231a7b1aaa29fce868f677", + "decimals": 18, + "name": "The SORA token", + "origins": [ + "https://etherscan.io/address/0x40fd72257597aa14c7231a7b1aaa29fce868f677", + "https://www.coingecko.com/en/coins/sora" + ], + "symbol": "XOR" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "ETHEREUM", + "contractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "decimals": 6, + "name": "USDC stablecoin token", + "origins": [ + "https://etherscan.io/address/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "https://www.coingecko.com/en/coins/usd-coin" + ], + "symbol": "USDC" + } + } +} diff --git a/evmchainindex.json b/evmchainindex.json new file mode 100644 index 0000000..2164636 --- /dev/null +++ b/evmchainindex.json @@ -0,0 +1,7440 @@ +{ + "networks": { + "GANACHE8545_5777": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://blockexplorer.x" + ], + "chainId": 5777, + "chainName": "Ganache Test Chain, default local port 8545 and chainid 5777", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Development Test Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "http://127.0.0.1:8545" + ], + "origins": [ + "https://gsthina.medium.com/the-default-chain-id-for-ganache-metamask-is-1337-can-you-try-to-override-it-de5ad1bcb3ab" + ], + "priceMechanism": "LEGACY", + "shortName": "GANACHE8545_5777", + "tokenIndex": { + "tokens": {} + }, + "type": "LOCAL" + }, + "ETHW": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://mainnet.ethwscan.com/" + ], + "chainId": 10001, + "chainName": "ETH PoW Mainnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "ETHW Gas Token", + "symbol": "ETHW" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://mainnet.ethereumpow.org" + ], + "origins": [ + "https://ethereumpow.org/" + ], + "priceMechanism": "EIP1559", + "shortName": "ETHW", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "LUKSO": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.execution.mainnet.lukso.network" + ], + "chainId": 42, + "chainName": "LUKSO Mainnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "LUKSO Gas Token", + "symbol": "LYX" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.mainnet.lukso.network" + ], + "origins": [ + "https://lukso.network/" + ], + "priceMechanism": "EIP1559", + "shortName": "LUKSO", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "ROPSTENTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://ropsten.etherscan.io" + ], + "chainId": 3, + "chainName": "Ropsten Test Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "decomissioned" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Ropsten Test Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://ropsten.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161", + "https://rpc.ankr.com/eth_ropsten" + ], + "origins": [ + "https://chainlist.org/chain/3" + ], + "priceMechanism": "EIP1559", + "shortName": "ROPSTENTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "SCROLL": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://blockscout.scroll.io" + ], + "chainId": 534352, + "chainName": "Scroll Mainnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://scroll.io/bridge" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Scroll Test Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://scroll.blockpi.network/v1/rpc/public", + "https://rpc-scroll.icecreamswap.com", + "https://rpc.scroll.io", + "https://1rpc.io/scroll" + ], + "origins": [ + "https://scroll.io" + ], + "priceMechanism": "EIP1559", + "shortName": "SCROLL", + "tokenIndex": { + "tokens": { + "PAPYRUS": { + "category": "DEFI", + "chain": "SCROLL", + "contractAddress": "0x0Fc479e2f9b7310BfB1Db606CF565deA6910eedc", + "decimals": 18, + "name": "Papyrus token", + "origins": [ + "https://blockscout.scroll.io/address/0x0Fc479e2f9b7310BfB1Db606CF565deA6910eedc" + ], + "symbol": "PAPYRUS" + }, + "gPAPYRUS": { + "category": "DEFI", + "chain": "SCROLL", + "contractAddress": "0xf4BA885557b8E0dCE70e14CCD1a4A73E4a09793e", + "decimals": 18, + "name": "Papyrus locked token", + "origins": [ + "https://blockscout.scroll.io/address/0xf4BA885557b8E0dCE70e14CCD1a4A73E4a09793e" + ], + "symbol": "gPAPYRUS" + }, + "USDC": { + "category": "DEFI", + "chain": "SCROLL", + "contractAddress": "0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4", + "decimals": 6, + "name": "USDC stable token", + "origins": [ + "https://blockscout.scroll.io/address/0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4" + ], + "symbol": "USDC" + } + } + }, + "type": "PUBLIC" + }, + "CELO": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.celo.org" + ], + "chainId": 42220, + "chainName": "Celo Mainnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "CELO Native Token", + "symbol": "CELO" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://forno.celo.org" + ], + "origins": [ + "https://chainlist.org/chain/42220" + ], + "priceMechanism": "EIP1559", + "shortName": "CELO", + "tokenIndex": { + "tokens": { + "ZEROCASINO": { + "category": "TEST", + "chain": "CELO", + "contractAddress": "0xbccEc3bfd4639440b1714a502bb3940F407b890A", + "decimals": 18, + "name": "0CASINO token", + "origins": [ + "https://explorer.celo.org/token/0xbccEc3bfd4639440b1714a502bb3940F407b890A" + ], + "symbol": "ZEROCASINO" + }, + "cUSD": { + "category": "STABLECOIN", + "chain": "CELO", + "contractAddress": "0x765DE816845861e75A25fCA122bb6898B8B1282a", + "decimals": 18, + "name": "CELO USD stable token", + "origins": [ + "https://explorer.celo.org/token/0x765DE816845861e75A25fCA122bb6898B8B1282a", + "https://www.coingecko.com/en/coins/celo-dollar" + ], + "symbol": "cUSD" + } + } + }, + "type": "PUBLIC" + }, + "HARDHAT8545_31337": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://blockexplorer.x" + ], + "chainId": 31337, + "chainName": "Hardhat Test Chain, default local port 8545 and chainid 31337", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Development Test Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "http://127.0.0.1:8545", + "http://127.0.0.1:8545/rpc" + ], + "origins": [ + "https://hardhat.org/hardhat-network/docs/reference" + ], + "priceMechanism": "LEGACY", + "shortName": "HARDHAT8545_31337", + "tokenIndex": { + "tokens": {} + }, + "type": "LOCAL" + }, + "GANACHE7545_5777": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://blockexplorer.x" + ], + "chainId": 5777, + "chainName": "Ganache Test Chain, default local port 7545 and chainid 5777", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Development Test Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "http://127.0.0.1:7545" + ], + "origins": [ + "https://gsthina.medium.com/the-default-chain-id-for-ganache-metamask-is-1337-can-you-try-to-override-it-de5ad1bcb3ab" + ], + "priceMechanism": "LEGACY", + "shortName": "GANACHE7545_5777", + "tokenIndex": { + "tokens": {} + }, + "type": "LOCAL" + }, + "KAVATEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.testnet.kava.io" + ], + "chainId": 2221, + "chainName": "KAVA Evm Testnet", + "fallbackGasLimitInUnits": "30000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://faucet.kava.io/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "KAVA Testnet Token", + "symbol": "KAVA" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://evm.testnet.kava.io" + ], + "origins": [ + "https://kava.io", + "https://docs.kava.io/docs/ethereum/metamask/" + ], + "priceMechanism": "EIP1559", + "shortName": "KAVATEST", + "tokenIndex": { + "tokens": { + "USDC": { + "category": "STABLECOIN", + "chain": "KAVATEST", + "contractAddress": "0x43D8814FdFB9B8854422Df13F1c66e34E4fa91fD", + "decimals": 6, + "name": "USDC token", + "origins": [ + "https://explorer.testnet.kava.io/address/0x43D8814FdFB9B8854422Df13F1c66e34E4fa91fD" + ], + "symbol": "USDC" + } + } + }, + "type": "PUBLIC" + }, + "KARURATEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "todo block explorer" + ], + "chainId": 596, + "chainName": "KARURA Testnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "todo faucet" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "KARURA Test Token", + "symbol": "KAR" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://eth-rpc-karura-testnet.aca-staging.network" + ], + "origins": [ + "https://acala.network/karura" + ], + "priceMechanism": "EIP1559", + "shortName": "KARURATEST", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "LAMINA1BETATEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.lamina1.com" + ], + "chainId": 7649, + "chainName": "Lamina1 Betanet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "1000000000", + "faucets": [ + "" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Lamina1 Gas Token", + "symbol": "L1" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": { + "CITIZEN": { + "category": "CHAINMASCOT", + "chain": "MANTLE", + "contractAddress": "0x7cf4aC414C94E03Ecb2A7d6EA8F79087453cAEf0", + "description": "Citizen of Mantle", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://explorer.mantle.xyz/token/0x7cf4aC414C94E03Ecb2A7d6EA8F79087453cAEf0", + "https://journey.mantle.xyz/" + ], + "symbol": "CITIZEN" + } + } + }, + "nodeURLs": [ + "https://rpc-betanet.lamina1.com/ext/bc/C/rpc" + ], + "origins": [ + "https://www.mantle.xyz/" + ], + "priceMechanism": "EIP1559", + "shortName": "LAMINA1BETATEST", + "tokenIndex": { + "tokens": { + "USDT": { + "category": "STABLECOIN", + "chain": "MANTLE", + "contractAddress": "0x201EBa5CC46D216Ce6DC03F6a759e8E766e956aE", + "decimals": 6, + "name": "Tether stable coin", + "origins": [ + "https://explorer.mantle.xyz/token/0x201EBa5CC46D216Ce6DC03F6a759e8E766e956aE" + ], + "symbol": "USDT" + }, + "WETH": { + "category": "DEFI", + "chain": "MANTLE", + "contractAddress": "0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111", + "decimals": 18, + "name": "Wrapped ETH token", + "origins": [ + "https://explorer.mantle.xyz/token/0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111", + "https://www.coingecko.com/en/coins/wrapped-ether-mantle-bridge" + ], + "symbol": "WETH" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "MANTLE", + "contractAddress": "0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9", + "decimals": 6, + "name": "USDC stable coin", + "origins": [ + "https://explorer.mantle.xyz/address/0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9" + ], + "symbol": "USDC" + } + } + }, + "type": "PUBLIC" + }, + "POLYGON": { + "archivenodeURLs": [ + "https://polygon-mainnet.g.alchemy.com/v2/" + ], + "blockexplorerURLs": [ + "https://polygonscan.com" + ], + "chainId": 137, + "chainName": "Polygon Mainnet", + "enforcedMinGasPriceInWEI": "31000000000", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://matic.supply" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "MATIC", + "symbol": "MATIC" + }, + "nftindex": { + "erc1155tokens": { + "AAVEGOTCHI_INSTALLATION": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x9216c31d8146bcb3ea5a9162dc1702e8aedca355", + "description": "AAvegotchi game land installation NFT", + "linked_tokens": [ + "POLYGON:GHST", + "POLYGON:KEK", + "POLYGON:ALPHA", + "POLYGON:FOMO", + "POLYGON:FUD", + "POLYGON:GLTR" + ], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0x9216c31d8146bcb3ea5a9162dc1702e8aedca355", + "https://opensea.io/collection/gotchiverse-installations" + ], + "symbol": "AAVEGOTCHI_INSTALLATION" + } + }, + "erc721tokens": { + "UNISWAPV3_POSITION": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0xC36442b4a4522E871399CD717aBDD847Ab11FE88", + "description": "Uniswap v3 position NFT", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/token/0xc36442b4a4522e871399cd717abdd847ab11fe88" + ], + "symbol": "UNISWAPV3_POSITION" + }, + "UAPX_SONG": { + "category": "NFT", + "chain": "POLYGON", + "contractAddress": "0x86c47873dd7d2186f5bd87da4757aecf1e16ac2e", + "description": "UAPx song NFT (formerly Terra)", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0x86c47873dd7d2186f5bd87da4757aecf1e16ac2e" + ], + "symbol": "UAPX_SONG" + }, + "UAPX_SHIP": { + "category": "NFT", + "chain": "POLYGON", + "contractAddress": "0x2148da6c55c10ea3d9b33311d19a065592abd24b", + "description": "UAPx ship NFT (formerly Terra)", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0x2148da6c55c10ea3d9b33311d19a065592abd24b" + ], + "symbol": "UAPX_SHIP" + }, + "UAPX_ALIEN": { + "category": "NFT", + "chain": "POLYGON", + "contractAddress": "0xd8f000eac06cebab3b967eeb137fbcac842a1472", + "description": "UAPx alien NFT (formerly Terra)", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0xd8f000eac06cebab3b967eeb137fbcac842a1472" + ], + "symbol": "UAPX_ALIEN" + }, + "AAVEGOTCHI": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x86935f11c86623dec8a25696e1c19a8659cbf95d", + "description": "AAvegotchi game NFT", + "linked_tokens": [ + "POLYGON:GHST", + "POLYGON:KEK", + "POLYGON:ALPHA", + "POLYGON:FOMO", + "POLYGON:FUD", + "POLYGON:GLTR" + ], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/token/0x86935f11c86623dec8a25696e1c19a8659cbf95d" + ], + "symbol": "AAVEGOTCHI" + }, + "UNSTOPPABLE_DOMAIN": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0xa9a6a3626993d487d2dbda3173cf58ca1a9d9e9f", + "description": "Unstoppable domains NFT", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0xa9a6a3626993d487d2dbda3173cf58ca1a9d9e9f" + ], + "symbol": "UNSTOPPABLE_DOMAIN" + }, + "UNIOVERSE": { + "category": "NFT", + "chain": "POLYGON", + "contractAddress": "0xed55e4477b795eaa9bb4bca24df42214e1a05c18", + "description": "Unioverse Collectibles", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0xed55e4477b795eaa9bb4bca24df42214e1a05c18" + ], + "symbol": "UNIOVERSE" + }, + "AAVEGOTCHI_LAND": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x1d0360bac7299c86ec8e99d0c1c9a95fefaf2a11", + "description": "AAvegotchi game LAND NFT", + "linked_tokens": [ + "POLYGON:GHST", + "POLYGON:KEK", + "POLYGON:ALPHA", + "POLYGON:FOMO", + "POLYGON:FUD", + "POLYGON:GLTR" + ], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0x1d0360bac7299c86ec8e99d0c1c9a95fefaf2a11" + ], + "symbol": "AAVEGOTCHI_LAND" + }, + "LENSPROTOCOLPROFILE": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0xdb46d1dc155634fbc732f92e853b10b288ad5a1d", + "description": "Lens Protocol Profile NFT", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0xdb46d1dc155634fbc732f92e853b10b288ad5a1d" + ], + "symbol": "LENSPROTOCOLPROFILE" + }, + "MYCRYPTOHEROES": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x77bd275ff2b3dc007475aac9ce7f408f5a800188", + "description": "My Crypto Heroes NFT", + "linked_tokens": [], + "mintBlock": 16765971, + "origins": [ + "https://polygonscan.com/address/0x77bd275ff2b3dc007475aac9ce7f408f5a800188" + ], + "symbol": "MYCRYPTOHEROES" + }, + "SANDBOX_LAND": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x9d305a42a3975ee4c1c57555bed5919889dce63f", + "description": "The Sandbox LAND NFT", + "linked_tokens": [ + "POLYGON:SAND" + ], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0x9d305a42a3975ee4c1c57555bed5919889dce63f", + "https://opensea.io/collection/sandbox" + ], + "symbol": "SANDBOX_LAND" + }, + "TRUMP": { + "category": "SCAM", + "chain": "POLYGON", + "contractAddress": "0x24a11e702cd90f034ea44faf1e180c0c654ac5d9", + "description": "Trump Digital Trading Card NFT", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0x24a11e702cd90f034ea44faf1e180c0c654ac5d9" + ], + "symbol": "TRUMP" + }, + "AAVEGOTCHI_GMI": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x3f0e22b827e51ff567d7388c2b598e2eabfa74be", + "description": "AAvegotchi GMI NFT", + "linked_tokens": [ + "POLYGON:GHST", + "POLYGON:KEK", + "POLYGON:ALPHA", + "POLYGON:FOMO", + "POLYGON:FUD", + "POLYGON:GLTR" + ], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0x3f0e22b827e51ff567d7388c2b598e2eabfa74be" + ], + "symbol": "AAVEGOTCHI_GMI" + } + } + }, + "nodeURLs": [ + "https://polygon-rpc.com/", + "https://rpc-mainnet.matic.quiknode.pro", + "https://rpc-mainnet.maticvigil.com", + "https://poly-rpc.gateway.pokt.network", + "https://polygon-mainnet.public.blastapi.io", + "https://rpc.ankr.com/polygon", + "https://1rpc.io/matic", + "https://polygon-bor.publicnode.com", + "https://polygon.llamarpc.com", + "https://polygon.rpc.blxrbdn.com", + "https://polygon.blockpi.network/v1/rpc/public", + "https://endpoints.omniatech.io/v1/matic/mainnet/public", + "https://polygon.api.onfinality.io/public" + ], + "origins": [ + "https://chainlist.org/chain/137" + ], + "priceMechanism": "EIP1559", + "shortName": "POLYGON", + "tokenIndex": { + "tokens": { + "GLTR": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x3801c3b3b5c98f88a9c9005966aa96aa440b9afc", + "decimals": 18, + "name": "GAX Liquidity Token Reward, Aavegotchi game token", + "origins": [ + "https://polygonscan.com/token/0x3801c3b3b5c98f88a9c9005966aa96aa440b9afc", + "https://www.coingecko.com/en/coins/gax-liquidity-token-reward" + ], + "symbol": "GLTR" + }, + "RICOCHET_WBTCx": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x4086eBf75233e8492F1BCDa41C7f2A8288c2fB92", + "decimals": 18, + "name": "Ricochet WBTC token, WBTCx", + "origins": [ + "https://polygonscan.com/token/0x4086eBf75233e8492F1BCDa41C7f2A8288c2fB92", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "RICOCHET_WBTCx" + }, + "RICOCHET_ETHx": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x27e1e4E6BC79D93032abef01025811B7E4727e85", + "decimals": 18, + "name": "Ricochet ETH token, ETHx", + "origins": [ + "https://polygonscan.com/token/0x27e1e4E6BC79D93032abef01025811B7E4727e85", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "RICOCHET_ETHx" + }, + "LUCHA": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x6749441fdc8650b5b5a854ed255c82ef361f1596", + "decimals": 18, + "name": "Luchadores game token", + "origins": [ + "https://polygonscan.com/address/0x6749441fdc8650b5b5a854ed255c82ef361f1596", + "https://www.coingecko.com/en/coins/lucha" + ], + "symbol": "LUCHA" + }, + "SYNAPSE": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0xf8f9efc0db77d8881500bb06ff5d6abc3070e695", + "decimals": 18, + "name": "Synapse Defi token", + "origins": [ + "https://polygonscan.com/token/0xf8f9efc0db77d8881500bb06ff5d6abc3070e695", + "https://www.coingecko.com/en/coins/synapse" + ], + "symbol": "SYNAPSE" + }, + "STG": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x2f6f07cdcf3588944bf4c42ac74ff24bf56e7590", + "decimals": 18, + "name": "StarGate token", + "origins": [ + "https://polygonscan.com/token/0x2f6f07cdcf3588944bf4c42ac74ff24bf56e7590", + "https://www.coingecko.com/en/coins/stargate-finance" + ], + "symbol": "STG" + }, + "VRSW": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x57999936fc9a9ec0751a8d146cce11901be8bed0", + "decimals": 18, + "name": "Virtuswap token", + "origins": [ + "https://polygonscan.com/token/0x57999936fc9a9ec0751a8d146cce11901be8bed0" + ], + "symbol": "VRSW" + }, + "ALPHA": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x6a3e7c3c6ef65ee26975b12293ca1aad7e1daed2", + "decimals": 18, + "name": "Aavegotchi ALPHA game token", + "origins": [ + "https://polygonscan.com/address/0x6a3e7c3c6ef65ee26975b12293ca1aad7e1daed2", + "https://www.coingecko.com/en/coins/aavegotchi-alpha" + ], + "symbol": "ALPHA" + }, + "QUICKSWAP_aWMATIC_GHST_LP": { + "category": "LIQUIDITY_PROVIDER", + "chain": "POLYGON", + "contractAddress": "0x2ef46196d7d25b5111ca1fcba206b248fee32d8d", + "decimals": 18, + "name": "WMATIC/GHST Quickswap Pool token", + "origins": [ + "https://polygonscan.com/token/0x2ef46196d7d25b5111ca1fcba206b248fee32d8d" + ], + "symbol": "QUICKSWAP_aWMATIC_GHST_LP" + }, + "USDT": { + "category": "STABLECOIN", + "chain": "POLYGON", + "contractAddress": "0xc2132d05d31c914a87c6611c10748aeb04b58e8f", + "decimals": 18, + "name": "Tether stablecoin token", + "origins": [ + "https://polygonscan.com/address/0xc2132d05d31c914a87c6611c10748aeb04b58e8f", + "https://www.coingecko.com/en/coins/tether" + ], + "symbol": "USDT" + }, + "FOMO": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x44a6e0be76e1d9620a7f76588e4509fe4fa8e8c8", + "decimals": 18, + "name": "Aavegotchi FOMO game token", + "origins": [ + "https://polygonscan.com/address/0x44a6e0be76e1d9620a7f76588e4509fe4fa8e8c8", + "https://www.coingecko.com/en/coins/aavegotchi-fomo" + ], + "symbol": "FOMO" + }, + "gDAI": { + "category": "STABLECOIN", + "chain": "POLYGON", + "contractAddress": "0x91993f2101cc758d0deb7279d41e880f7defe827", + "decimals": 18, + "name": "GAINS Network DAI token", + "origins": [ + "https://polygonscan.com/address/0x91993f2101cc758d0deb7279d41e880f7defe827" + ], + "symbol": "gDAI" + }, + "amLINK": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x0ca2e42e8c21954af73bc9af1213e4e81d6a669a", + "decimals": 18, + "name": "Aave LINK token", + "origins": [ + "https://polygonscan.com/token/0x0ca2e42e8c21954af73bc9af1213e4e81d6a669a", + "https://www.coingecko.com/en/coins/chainlink" + ], + "symbol": "amLINK" + }, + "CXDOGE": { + "category": "WRECKED", + "chain": "POLYGON", + "contractAddress": "0x9bd9ad490dd3a52f096d229af4483b94d63be618", + "decimals": 18, + "name": "CelsiusX Wrapped DOGE token (wrecked)", + "origins": [ + "https://polygonscan.com/address/0x9bd9ad490dd3a52f096d229af4483b94d63be618", + "https://www.coingecko.com/en/coins/celsiusx-wrapped-doge" + ], + "symbol": "CXDOGE" + }, + "FUD": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x403e967b044d4be25170310157cb1a4bf10bdd0f", + "decimals": 18, + "name": "Aavegotchi FUD game token", + "origins": [ + "https://polygonscan.com/address/0x403e967b044d4be25170310157cb1a4bf10bdd0f", + "https://www.coingecko.com/en/coins/aavegotchi-fud" + ], + "symbol": "FUD" + }, + "LINK": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x53e0bca35ec356bd5dddfebbd1fc0fd03fabad39", + "decimals": 18, + "name": "LINK token", + "origins": [ + "https://polygonscan.com/address/0x53e0bca35ec356bd5dddfebbd1fc0fd03fabad39", + "https://www.coingecko.com/en/coins/chainlink" + ], + "symbol": "LINK" + }, + "ROLL": { + "category": "DUST", + "chain": "POLYGON", + "contractAddress": "0xC68e83a305b0FaD69E264A1769a0A070F190D2d6", + "decimals": 18, + "name": "ROLL SCAM token", + "origins": [ + "https://polygonscan.com/token/0xc68e83a305b0fad69e264a1769a0a070f190d2d6#comments", + "https://polyroll.org/" + ], + "symbol": "ROLL" + }, + "MATICX": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0xfa68fb4628dff1028cfec22b4162fccd0d45efb6", + "decimals": 18, + "name": "Stader Liquid Staking Matic (PoS) token", + "origins": [ + "https://polygonscan.com/token/0xfa68fb4628dff1028cfec22b4162fccd0d45efb6", + "https://www.coingecko.com/en/coins/stader-maticx" + ], + "symbol": "MATICX" + }, + "SAND": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0xbbba073c31bf03b8acf7c28ef0738decf3695683", + "decimals": 18, + "name": "The Sandbox SAND game token", + "origins": [ + "https://polygonscan.com/address/0xbbba073c31bf03b8acf7c28ef0738decf3695683", + "https://www.coingecko.com/en/coins/the-sandbox" + ], + "symbol": "SAND" + }, + "RICOCHET": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x263026e7e53dbfdce5ae55ade22493f828922965", + "decimals": 18, + "name": "Ricochet reward token", + "origins": [ + "https://polygonscan.com/address/0x263026e7e53dbfdce5ae55ade22493f828922965", + "https://www.coingecko.com/en/coins/ricochet" + ], + "symbol": "RICOCHET" + }, + "GHST": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x385eeac5cb85a38a9a07a70c73e0a3271cfb54a7", + "decimals": 18, + "name": "Aavegotchi GHST game token", + "origins": [ + "https://polygonscan.com/address/0x385eeac5cb85a38a9a07a70c73e0a3271cfb54a7", + "https://www.coingecko.com/en/coins/aavegotchi" + ], + "symbol": "GHST" + }, + "MOD": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x8346ab8d5ea7a9db0209aed2d1806afa0e2c4c21", + "decimals": 18, + "name": "MOD token", + "origins": [ + "https://www.coingecko.com/en/coins/modefi", + "https://polygonscan.com/token/0x8346ab8d5ea7a9db0209aed2d1806afa0e2c4c21", + "https://modefi.io/" + ], + "symbol": "MOD" + }, + "amWMATIC": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x8df3aad3a84da6b69a4da8aec3ea40d9091b2ac4", + "decimals": 18, + "name": "Aave WMATIC token", + "origins": [ + "https://polygonscan.com/token/0x8df3aad3a84da6b69a4da8aec3ea40d9091b2ac4", + "https://www.coingecko.com/en/coins/aave-polygon-wmatic" + ], + "symbol": "amWMATIC" + }, + "dQUICK": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x958d208cdf087843e9ad98d23823d32e17d723a1", + "decimals": 18, + "name": "Dragon QUICK token", + "origins": [ + "https://polygonscan.com/token/0x958d208cdf087843e9ad98d23823d32e17d723a1", + "https://www.coingecko.com/en/exchanges/quickswap" + ], + "symbol": "dQUICK" + }, + "WETH": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x7ceb23fd6bc0add59e62ac25578270cff1b9f619", + "decimals": 18, + "name": "Wrapped ETH token", + "origins": [ + "https://polygonscan.com/token/0x7ceb23fd6bc0add59e62ac25578270cff1b9f619", + "https://www.coingecko.com/en/coins/weth" + ], + "symbol": "WETH" + }, + "RICOCHET_MATICx": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x3aD736904E9e65189c3000c7DD2c8AC8bB7cD4e3", + "decimals": 18, + "name": "Ricochet MATIC token, MATICx", + "origins": [ + "https://polygonscan.com/token/0x3aD736904E9e65189c3000c7DD2c8AC8bB7cD4e3", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "RICOCHET_MATICx" + }, + "IDEX": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x9cb74c8032b007466865f060ad2c46145d45553d", + "decimals": 18, + "name": "IDEX token", + "origins": [ + "https://polygonscan.com/token/0x9cb74c8032b007466865f060ad2c46145d45553d" + ], + "symbol": "IDEX" + }, + "RICOCHET_USDCx": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0xcaa7349cea390f89641fe306d93591f87595dc1f", + "decimals": 18, + "name": "Ricochet USDC token, USDCx", + "origins": [ + "https://polygonscan.com/token/0xcaa7349cea390f89641fe306d93591f87595dc1f", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "RICOCHET_USDCx" + }, + "TOWER": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x2bc07124d8dac638e290f401046ad584546bc47b", + "decimals": 18, + "name": "Crazy Defense Heroes game token", + "origins": [ + "https://polygonscan.com/address/0x2bc07124d8dac638e290f401046ad584546bc47b", + "https://www.coingecko.com/en/coins/tower" + ], + "symbol": "TOWER" + }, + "DAI": { + "category": "STABLECOIN", + "chain": "POLYGON", + "contractAddress": "0x8f3cf7ad23cd3cadbd9735aff958023239c6a063", + "decimals": 18, + "name": "DAI stablecoin token", + "origins": [ + "https://polygonscan.com/address/0x8f3cf7ad23cd3cadbd9735aff958023239c6a063", + "https://www.coingecko.com/en/coins/dai" + ], + "symbol": "DAI" + }, + "TITAN": { + "category": "SCAM", + "chain": "POLYGON", + "contractAddress": "0xaaa5b9e6c589642f98a1cda99b9d024b8407285a", + "decimals": 18, + "name": "IRON TITAN scam token", + "origins": [ + "https://polygonscan.com/token/0xaaa5b9e6c589642f98a1cda99b9d024b8407285a" + ], + "symbol": "TITAN" + }, + "KEK": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x42e5e06ef5b90fe15f853f59299fc96259209c5c", + "decimals": 18, + "name": "Aavegotchi KEK game token", + "origins": [ + "https://polygonscan.com/address/0x42e5e06ef5b90fe15f853f59299fc96259209c5c", + "https://www.coingecko.com/en/coins/aavegotchi-kek" + ], + "symbol": "KEK" + }, + "STARGATE_USDC_LP": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x1205f31718499dbf1fca446663b532ef87481fe1", + "decimals": 6, + "name": "StarGate USDC Pool token", + "origins": [ + "https://polygonscan.com/token/0x1205f31718499dbf1fca446663b532ef87481fe1" + ], + "symbol": "STARGATE_USDC_LP" + }, + "BGEM": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x1386617A1Bb2A6AA712AB3616bCAF1211152D1e8", + "decimals": 18, + "name": "BitGem gaming token", + "origins": [ + "https://polygonscan.com/token/0x1386617A1Bb2A6AA712AB3616bCAF1211152D1e8", + "https://boomland.io/daily" + ], + "symbol": "BGEM" + }, + "WMATIC": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270", + "decimals": 18, + "name": "WMATIC token", + "origins": [ + "https://polygonscan.com/address/0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270", + "https://www.coingecko.com/en/coins/wmatic" + ], + "symbol": "WMATIC" + }, + "rETH": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x0266f4f08d82372cf0fcbccc0ff74309089c74d1", + "decimals": 18, + "name": "Rocketpool ETH token", + "origins": [ + "https://polygonscan.com/token/0x0266f4f08d82372cf0fcbccc0ff74309089c74d1", + "https://rocketpool.net/" + ], + "symbol": "rETH" + }, + "SANDBOX_WMATIC_SAND_LP": { + "category": "LIQUIDITY_PROVIDER", + "chain": "POLYGON", + "contractAddress": "0x4ab071c42c28c4858c4bac171f06b13586b20f30", + "decimals": 18, + "name": "Sandbox WMATIC+SAND LP Token", + "origins": [ + "https://polygonscan.com/token/0x4ab071c42c28c4858c4bac171f06b13586b20f30", + "https://medium.com/sandbox-game/introducing-msand-matic-staking-at-the-sandbox-319f983d20a4" + ], + "symbol": "SANDBOX_WMATIC_SAND_LP" + }, + "TEST": { + "category": "TEST", + "chain": "POLYGON", + "contractAddress": "0x23D29D30e35C5e8D321e1dc9A8a61BFD846D4C5C", + "decimals": 18, + "name": "TEST token", + "origins": [ + "https://polygonscan.com/token/0xMOJO" + ], + "symbol": "TEST" + }, + "RICOCHET_DAIx": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x8f3cf7ad23cd3cadbd9735aff958023239c6a063", + "decimals": 18, + "name": "Ricochet DAI token, DAIx", + "origins": [ + "https://polygonscan.com/token/0x8f3cf7ad23cd3cadbd9735aff958023239c6a063", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "RICOCHET_DAIx" + }, + "AGHST": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x8eb270e296023e9d92081fdf967ddd7878724424", + "decimals": 18, + "name": "AAve Aavegotchi GHST game token", + "origins": [ + "https://polygonscan.com/address/0x8eb270e296023e9d92081fdf967ddd7878724424", + "https://www.coingecko.com/en/coins/aavegotchi" + ], + "symbol": "AGHST" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "POLYGON", + "contractAddress": "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", + "decimals": 6, + "name": "USDC stablecoin token", + "origins": [ + "https://polygonscan.com/address/0x2791bca1f2de4661ed88a30c99a7a9449aa84174", + "https://www.coingecko.com/en/coins/usd-coin" + ], + "symbol": "USDC" + } + } + }, + "type": "PUBLIC" + }, + "SCROLLSEPOLIATEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://sepolia.scrollscan.dev" + ], + "chainId": 534351, + "chainName": "Scroll Sepolia Testnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://sepolia.scroll.io/bridge" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Scroll Testnet Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://scroll-sepolia.blockpi.network/v1/rpc/public", + "https://sepolia-rpc.scroll.io", + "https://scroll-public.scroll-testnet.quiknode.pro", + "https://rpc.ankr.com/scroll_sepolia_testnet", + "https://scroll-testnet-public.unifra.io", + "https://1rpc.io/scroll/sepolia", + "https://scroll-sepolia.chainstacklabs.com" + ], + "origins": [ + "https://scroll.io" + ], + "priceMechanism": "EIP1559", + "shortName": "SCROLLSEPOLIATEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "ZKSYNCERATEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://goerli.explorer.zksync.io" + ], + "chainId": 280, + "chainName": "zkSync Test Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "brige test funds from goerli using https://portal.zksync.io/bridge", + "https://goerli.portal.zksync.io/faucet" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "zkSync Era Test Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://testnet.era.zksync.dev" + ], + "origins": [ + "https://chainlist.org/chain/280" + ], + "priceMechanism": "EIP1559", + "shortName": "ZKSYNCERATEST", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "ZETAATHENSTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.athens.zetachain.com" + ], + "chainId": 7001, + "chainName": "ZetaChain Athens Testnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://labs.zetachain.com/get-zeta" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Zetachain Testnet Token", + "symbol": "aZETA" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://zetachain-athens-evm.blockpi.network/v1/rpc/public", + "https://rpc.ankr.com/zetachain_evm_testnet" + ], + "origins": [ + "https://www.zetachain.com/" + ], + "priceMechanism": "EIP1559", + "shortName": "ZETAATHENSTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "OASISSAPPHIRETEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.sapphire.oasis.io/" + ], + "chainId": 23295, + "chainName": "Oasis Sapphire Test Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://faucet.testnet.oasis.dev/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Oasis Test Token", + "symbol": "TEST" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://testnet.sapphire.oasis.dev" + ], + "origins": [ + "https://oasisprotocol.org/" + ], + "priceMechanism": "EIP1559", + "shortName": "OASISSAPPHIRETEST", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "TOMOCHAINTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://scan.testnet.tomochain.com" + ], + "chainId": 89, + "chainName": "Tomochain Mainnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Tomo Gas Token", + "symbol": "TOMO" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.testnet.tomochain.com" + ], + "origins": [ + "https://tomochain.com" + ], + "priceMechanism": "EIP1559", + "shortName": "TOMOCHAINTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "HARDHAT443_31337": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://blockexplorer.x" + ], + "chainId": 31337, + "chainName": "Hardhat Test Chain, default local https port 443 and chainid 31337", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Development Test Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://localhost" + ], + "origins": [ + "https://hardhat.org/hardhat-network/docs/reference" + ], + "priceMechanism": "LEGACY", + "shortName": "HARDHAT443_31337", + "tokenIndex": { + "tokens": {} + }, + "type": "LOCAL" + }, + "TAIKOALPHATEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://l2explorer.a1.taiko.xyz" + ], + "chainId": 167003, + "chainName": "Taiko Ethereum A1 Test Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://l2faucet.a1.taiko.xyz/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Taiko A1 Test Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://l2rpc.a1.taiko.xyz" + ], + "origins": [ + "https://taiko.xyz/docs/alpha-1-testnet/configure-wallet" + ], + "priceMechanism": "EIP1559", + "shortName": "TAIKOALPHATEST", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "CONFLUX": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://evm.confluxscan.net", + "https://conflux-espace-public.unifra.io" + ], + "chainId": 1030, + "chainName": "Conflux eSpace", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet todo" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Conflux Token", + "symbol": "CFX" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://evm.confluxrpc.com", + "https://conflux-espace-public.unifra.io" + ], + "origins": [ + "https://confluxnetwork.org/" + ], + "priceMechanism": "EIP1559", + "shortName": "CONFLUX", + "tokenIndex": { + "tokens": { + "SWAPPI_CFX_PPI_LP": { + "category": "LIQUIDITY_PROVIDER", + "chain": "CONFLUX", + "contractAddress": "0x1112a6c61a2eec4bd3aec78bd5bf3396bdd37d57", + "decimals": 18, + "name": "Swappi CFX-PPI LP token", + "origins": [ + "https://evm.confluxscan.io/token/0x1112a6c61a2eec4bd3aec78bd5bf3396bdd37d57" + ], + "symbol": "SWAPPI_CFX_PPI_LP" + }, + "WCFX": { + "category": "DEFI", + "chain": "CONFLUX", + "contractAddress": "0x14b2d3bc65e74dae1030eafd8ac30c533c976a9b", + "decimals": 18, + "name": "Wrapped Conflux token", + "origins": [ + "https://evm.confluxscan.io/token/0x14b2d3bc65e74dae1030eafd8ac30c533c976a9b" + ], + "symbol": "WCFX" + }, + "vePPI": { + "category": "DEFI", + "chain": "CONFLUX", + "contractAddress": "0xf270e44105c1270bc7a4ffedbcb699486ada7a6a", + "decimals": 18, + "name": "Swappi Vote Escrowed token", + "origins": [ + "https://evm.confluxscan.io/address/0xf270e44105c1270bc7a4ffedbcb699486ada7a6a" + ], + "symbol": "vePPI" + }, + "PPI": { + "category": "DEFI", + "chain": "CONFLUX", + "contractAddress": "0x22f41abf77905f50df398f21213290597e7414dd", + "decimals": 18, + "name": "Swappi token", + "origins": [ + "https://evm.confluxscan.io/token/0x22f41abf77905f50df398f21213290597e7414dd", + "https://app.swappi.io/" + ], + "symbol": "PPI" + }, + "USDT": { + "category": "STABLECOIN", + "chain": "CONFLUX", + "contractAddress": "0xfe97e85d13abd9c1c33384e796f10b73905637ce", + "decimals": 18, + "name": "Tether stable token", + "origins": [ + "https://evm.confluxscan.io/token/0xfe97e85d13abd9c1c33384e796f10b73905637ce" + ], + "symbol": "USDT" + } + } + }, + "type": "PUBLIC" + }, + "BITKUBTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://testnet.bkcscan.com" + ], + "chainId": 25925, + "chainName": "Bitkub Test Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://faucet.bitkubchain.com" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Bitkub Native Token", + "symbol": "tKUB" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc-testnet.bitkubchain.io" + ], + "origins": [ + "https://bitkub.com" + ], + "priceMechanism": "LEGACY", + "shortName": "BITKUBTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "FANTOMTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://testnet.ftmscan.com/" + ], + "chainId": 4002, + "chainName": "Fantom Test Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://faucet.fantom.network/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Fantom Native Token", + "symbol": "FTM" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://fantom.api.onfinality.io/public", + "https://fantom-testnet.public.blastapi.io", + "https://rpc.testnet.fantom.network", + "https://rpc.ankr.com/fantom_testnet" + ], + "origins": [ + "https://chainlist.org/chain/4002" + ], + "priceMechanism": "EIP1559", + "shortName": "FANTOMTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "MODETEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://sepolia.explorer.mode.network" + ], + "chainId": 919, + "chainName": "MODE Testnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://www.mode.network" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Mode Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://sepolia.mode.network" + ], + "origins": [ + "https://confluxnetwork.org/" + ], + "priceMechanism": "EIP1559", + "shortName": "MODETEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "EVMOS": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://www.mintscan.io/evmos", + "https://evm.evmos.org/" + ], + "chainId": 9001, + "chainName": "EVMOS Mainnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://stakely.io/en/faucet/evmos-evm" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "EVMOS", + "symbol": "EVMOS" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://evmos-json-rpc.agoranodes.com", + "https://json-rpc.evmos.blockhunters.org", + "https://evmos-mainnet.public.blastapi.io", + "https://evmos-evm.publicnode.com", + "https://evmos-json-rpc.stakely.io", + "https://evmos-mainnet.gateway.pokt.network/v1/lb/627586ddea1b320039c95205" + ], + "origins": [ + "https://chainlist.org/chain/9001" + ], + "priceMechanism": "EIP1559", + "shortName": "EVMOS", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "OPBNBTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://testnet.opbnbscan.com" + ], + "chainId": 5611, + "chainName": "opBNB Testnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "1000000000", + "faucets": [ + "https://opbnb-testnet-bridge.bnbchain.org/deposit" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "opBNB Gas Token", + "symbol": "tBNB" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://opbnb-testnet-rpc.bnbchain.org", + "https://opbnb-testnet.nodereal.io/v1/64a9df0874fb4a93b9d0a3849de012d3", + "https://opbnb-testnet.nodereal.io/v1/e9a36765eb8a40b9bd12e680a1fd2bc5" + ], + "origins": [ + "https://opbnb.bnbchain.org" + ], + "priceMechanism": "EIP1559", + "shortName": "OPBNBTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "METIS": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://andromeda-explorer.metis.io/" + ], + "chainId": 1088, + "chainName": "Metis Mainnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Metis Native Token", + "symbol": "METIS" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://andromeda.metis.io/?owner=1088", + "https://metis-mainnet.public.blastapi.io" + ], + "origins": [ + "https://chainlist.org/chain/1088" + ], + "priceMechanism": "LEGACY", + "shortName": "METIS", + "tokenIndex": { + "tokens": { + "HERMES_M_USDC_LP": { + "category": "LIQUIDITY_PROVIDER", + "chain": "METIS", + "contractAddress": "0x5ab390084812E145b619ECAA8671d39174a1a6d1", + "decimals": 18, + "name": "VolatileV1 AMM - Metis/m.USDC LP token", + "origins": [ + "https://andromeda-explorer.metis.io/address/0x5ab390084812E145b619ECAA8671d39174a1a6d1" + ], + "symbol": "HERMES_M_USDC_LP" + }, + "USDT": { + "category": "STABLECOIN", + "chain": "METIS", + "contractAddress": "0xbB06DCA3AE6887fAbF931640f67cab3e3a16F4dC", + "decimals": 6, + "name": "USDT stable token", + "origins": [ + "https://andromeda-explorer.metis.io/token/0xbB06DCA3AE6887fAbF931640f67cab3e3a16F4dC" + ], + "symbol": "USDT" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "METIS", + "contractAddress": "0xEA32A96608495e54156Ae48931A7c20f0dcc1a21", + "decimals": 6, + "name": "USDC stable token", + "origins": [ + "https://andromeda-explorer.metis.io/address/0xEA32A96608495e54156Ae48931A7c20f0dcc1a21" + ], + "symbol": "USDC" + } + } + }, + "type": "PUBLIC" + }, + "CORETEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://scan.test.btcs.network" + ], + "chainId": 1115, + "chainName": "Core DAO Testnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://bridge.coredao.org/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Core Test Token", + "symbol": "tCORE" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.test.btcs.network" + ], + "origins": [ + "https://coredao.org/" + ], + "priceMechanism": "EIP1559", + "shortName": "CORETEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "MILKOMEDAA1TEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://testnet-algorand-rollup.a1.milkomeda.com" + ], + "chainId": 200202, + "chainName": "Milkomeda Algorand testnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "milkTALGO", + "symbol": "milkTALGO" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc-devnet-algorand-rollup.a1.milkomeda.com" + ], + "origins": [ + "https://chainlist.org/chain/200202", + "https://dcspark.github.io/milkomeda-documentation/algorand/for-end-users/configuring-metamask/", + "https://algorand-bridge.milkomeda.com/devnet/" + ], + "priceMechanism": "EIP1559", + "shortName": "MILKOMEDAA1TEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "SATOSHICHAINTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://satoshiscan.io" + ], + "chainId": 5758, + "chainName": "SatoshiChain Testnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "550030000000000", + "faucets": [ + "https://faucet.satoshichain.io/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "SATS Token", + "symbol": "SATS" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://testnet-rpc.satoshichain.io/" + ], + "origins": [ + "https://satoshix.io/" + ], + "priceMechanism": "EIP1559", + "shortName": "SATOSHICHAINTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "OASISCHAIN": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://scan.oasischain.io/" + ], + "chainId": 26863, + "chainName": "Oasis Chain", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-todo" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Oasis Token", + "symbol": "OAC" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc1.oasischain.io", + "https://rpc2.oasischain.io", + "https://rpc3.oasischain.io" + ], + "origins": [ + "https://oasischain.io/" + ], + "priceMechanism": "EIP1559", + "shortName": "OASISCHAIN", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "GOERLITEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://goerli.etherscan.io" + ], + "chainId": 5, + "chainName": "Goerli Test Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://goerli-faucet.mudit.blog/", + "https://faucets.chain.link/goerli", + "https://goerli-faucet.slock.it/" + ], + "flashbotnodeURLs": [ + "https://rpc-goerli.flashbots.net" + ], + "flashbotrelaynodeURLs": [ + "https://relay-goerli.flashbots.net" + ], + "nativeCurrency": { + "decimal": 18, + "name": "Goerli ETH Test Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": { + "MFNFT": { + "category": "DEFI", + "chain": "GOERLITEST", + "contractAddress": "0xf5de760f2e916647fd766b4ad9e85ff943ce3a2b", + "description": "MultiFaucet NFT", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://goerli.etherscan.io/token/0xf5de760f2e916647fd766b4ad9e85ff943ce3a2b" + ], + "symbol": "MFNFT" + } + } + }, + "nodeURLs": [ + "https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161", + "https://rpc.ankr.com/eth_goerli" + ], + "origins": [ + "https://chainlist.org/chain/5" + ], + "priceMechanism": "EIP1559", + "shortName": "GOERLITEST", + "tokenIndex": { + "tokens": { + "ZETA": { + "category": "DEFI", + "chain": "GOERLITEST", + "contractAddress": "0xCc7bb2D219A0FC08033E130629C2B854b7bA9195", + "decimals": 18, + "name": "ZETA swap/bridge gas token", + "origins": [ + "https://goerli.etherscan.io/token/0xCc7bb2D219A0FC08033E130629C2B854b7bA9195" + ], + "symbol": "ZETA" + }, + "MNT": { + "category": "DEFI", + "chain": "GOERLITEST", + "contractAddress": "0xc1dC2d65A2243c22344E725677A3E3BEBD26E604", + "decimals": 18, + "name": "Mantle ERC-20 token", + "origins": [ + "https://goerli.etherscan.io/token/0xc1dC2d65A2243c22344E725677A3E3BEBD26E604" + ], + "symbol": "MNT" + }, + "TSTv4": { + "category": "TEST", + "chain": "GOERLITEST", + "contractAddress": "0x499d11E0b6eAC7c0593d8Fb292DCBbF815Fb29Ae", + "decimals": 18, + "name": "Goerli ERC-20 TST token", + "origins": [ + "https://goerli.etherscan.io/token/0x499d11E0b6eAC7c0593d8Fb292DCBbF815Fb29Ae" + ], + "symbol": "TSTv4" + }, + "TEST": { + "category": "TEST", + "chain": "GOERLITEST", + "contractAddress": "0x3f152b63ec5ca5831061b2dccfb29a874c317502", + "decimals": 18, + "name": "TEST token", + "origins": [ + "https://goerli.etherscan.io/token/0xMOJO" + ], + "symbol": "TEST" + }, + "TST4": { + "category": "TEST", + "chain": "GOERLITEST", + "contractAddress": "0x3f152b63ec5ca5831061b2dccfb29a874c317502", + "decimals": 18, + "name": "Official Goerli ERC-20 TST token", + "origins": [ + "https://goerli.etherscan.io/token/0x3f152b63ec5ca5831061b2dccfb29a874c317502" + ], + "symbol": "TST4" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "GOERLITEST", + "contractAddress": "0x07865c6e87b9f70255377e024ace6630c1eaa37f", + "decimals": 6, + "name": "USDC Stable token", + "origins": [ + "https://goerli.etherscan.io/token/0x07865c6e87b9f70255377e024ace6630c1eaa37f" + ], + "symbol": "USDC" + }, + "WETH": { + "category": "DEFI", + "chain": "GOERLITEST", + "contractAddress": "0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6", + "decimals": 18, + "name": "Wrapped ETH token", + "origins": [ + "https://goerli.etherscan.io/address/0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6" + ], + "symbol": "WETH" + }, + "DAI": { + "category": "DEFI", + "chain": "GOERLITEST", + "contractAddress": "0x11fe4b6ae13d2a6055c8d9cf65c55bac32b5d844", + "decimals": 18, + "name": "DAI USD stablecoin token", + "origins": [ + "https://goerli.etherscan.io/address/0x11fe4b6ae13d2a6055c8d9cf65c55bac32b5d844" + ], + "symbol": "DAI" + } + } + }, + "type": "PUBLIC" + }, + "KLAYTN": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://scope.klaytn.com" + ], + "chainId": 8217, + "chainName": "KLAYTN Mainnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "KLAYTN Native Token", + "symbol": "KLAY" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://public-node-api.klaytnapi.com/v1/cypress", + "https://klaytn.blockpi.network/v1/rpc/public", + "https://klaytn.api.onfinality.io/public", + "https://klaytn.drpc.org" + ], + "origins": [ + "https://chainlist.org/chain/8217", + "https://medium.com/klaytn/how-to-add-klaytn-to-metamask-b3bdd970c0e8" + ], + "priceMechanism": "LEGACY", + "shortName": "KLAYTN", + "tokenIndex": { + "tokens": { + "BORA": { + "category": "GAMING", + "chain": "KLAYTN", + "contractAddress": "0x02cbe46fb8a1f579254a9b485788f2d86cad51aa", + "decimals": 18, + "name": "BORA game token", + "origins": [ + "https://scope.klaytn.com/token/0x02cbe46fb8a1f579254a9b485788f2d86cad51aa", + "https://www.coingecko.com/en/coins/bora" + ], + "symbol": "BORA" + }, + "WEMIX": { + "category": "GAMING", + "chain": "KLAYTN", + "contractAddress": "0x5096db80b21ef45230c9e423c373f1fc9c0198dd", + "decimals": 18, + "name": "WEMIX game token", + "origins": [ + "https://scope.klaytn.com/token/0x5096db80b21ef45230c9e423c373f1fc9c0198dd", + "https://www.coingecko.com/en/coins/wemix-token" + ], + "symbol": "WEMIX" + }, + "TEST": { + "category": "TEST", + "chain": "KLAYTN", + "contractAddress": "0x7f1712f846a69bf2a9dbc4d48f45f1d52ca32e28", + "decimals": 18, + "name": "TEST token", + "origins": [ + "https://scope.klaytn.com/token/0xMOJO" + ], + "symbol": "TEST" + }, + "KSP": { + "category": "DEFI", + "chain": "KLAYTN", + "contractAddress": "0xc6a2ad8cc6e4a7e08fc37cc5954be07d499e7654", + "decimals": 18, + "name": "Klay Swap token", + "origins": [ + "https://scope.klaytn.com/token/0xc6a2ad8cc6e4a7e08fc37cc5954be07d499e7654", + "https://www.coingecko.com/en/coins/klayswap-protocol" + ], + "symbol": "KSP" + } + } + }, + "type": "PUBLIC" + }, + "TARAXATEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.testnet.taraxa.io" + ], + "chainId": 842, + "chainName": "Taraxa Testnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://testnet.explorer.taraxa.io/faucet" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Taraxa Native Token", + "symbol": "TARA" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.testnet.taraxa.io" + ], + "origins": [ + "https://chainlist.org/chain/842", + "https://www.coingecko.com/sv/coins/taraxa", + "https://www.taraxa.io/" + ], + "priceMechanism": "EIP1559", + "shortName": "TARAXATEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "OASISSAPPHIRE": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.sapphire.oasis.io/" + ], + "chainId": 23294, + "chainName": "Oasis Sapphire Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-todo" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Oasis Token", + "symbol": "ROSE" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://sapphire.oasis.io" + ], + "origins": [ + "https://oasisprotocol.org/" + ], + "priceMechanism": "EIP1559", + "shortName": "OASISSAPPHIRE", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "HARMONY": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.harmony.one" + ], + "chainId": 1666600000, + "chainName": "Harmony Mainnet Shard 0", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Harmony Native Token", + "symbol": "ONE" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://api.harmony.one", + "https://harmony-0-rpc.gateway.pokt.network", + "https://harmony-mainnet.chainstacklabs.com", + "https://api.s0.t.hmny.io", + "https://rpc.ankr.com/harmony", + "https://a.api.s0.t.hmny.io" + ], + "origins": [ + "https://chainlist.org/chain/1666600000" + ], + "priceMechanism": "EIP1559", + "shortName": "HARMONY", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "TOMOCHAIN": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://tomoscan.io" + ], + "chainId": 88, + "chainName": "Tomochain Mainnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Tomo Gas Token", + "symbol": "TOMO" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.tomochain.com", + "https://tomo.blockpi.network/v1/rpc/public" + ], + "origins": [ + "https://tomochain.com" + ], + "priceMechanism": "EIP1559", + "shortName": "TOMOCHAIN", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "BSCTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://testnet.bscscan.com" + ], + "chainId": 97, + "chainName": "Binance Smart Chain Testnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://testnet.binance.org/faucet-smart" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Binance Chain Test Native Token", + "symbol": "tBNB" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://data-seed-prebsc-1-s1.binance.org:8545", + "https://data-seed-prebsc-1-s2.binance.org:8545", + "https://data-seed-prebsc-1-s3.binance.org:8545", + "https://data-seed-prebsc-2-s2.binance.org:8545", + "https://bsc-testnet.public.blastapi.io", + "https://bsc-testnet.publicnode.com", + "https://bsc-testnet.blockpi.network/v1/rpc/public" + ], + "origins": [ + "https://chainlist.org/chain/97" + ], + "priceMechanism": "LEGACY", + "shortName": "BSCTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "FUSE": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.fuse.io/" + ], + "chainId": 122, + "chainName": "FUSE Mainnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "10000000000", + "faucets": [ + "" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "FUSE Gas Token", + "symbol": "FUSE" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://fuse-mainnet.chainstacklabs.com", + "https://rpc.fuse.io", + "https://fuse-rpc.gateway.pokt.network", + "https://fuse.api.onfinality.io/public" + ], + "origins": [ + "https://www.fuse.io/" + ], + "priceMechanism": "EIP1559", + "shortName": "FUSE", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "FUJITEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://testnet.snowtrace.io" + ], + "chainId": 43113, + "chainName": "Avalanche Fuji Test Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://faucet.avax.network/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "AVAX FUJI Test Token", + "symbol": "AVAX" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://api.avax-test.network/ext/bc/C/rpc", + "https://avalanche-fuji-c-chain.publicnode.com", + "https://ava-testnet.public.blastapi.io/ext/bc/C/rpc", + "https://rpc.ankr.com/avalanche_fuji", + "https://endpoints.omniatech.io/v1/avax/fuji/public" + ], + "origins": [ + "https://chainlist.org/chain/43113" + ], + "priceMechanism": "EIP1559", + "shortName": "FUJITEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "AVAX": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://snowtrace.io/" + ], + "chainId": 43114, + "chainName": "Avalanche C-Chain", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Avalanche Native Token", + "symbol": "AVAX" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://api.avax.network/ext/bc/C/rpc", + "https://rpc.ankr.com/avalanche", + "https://ava-mainnet.public.blastapi.io/ext/bc/C/rpc", + "https://avax.meowrpc.com" + ], + "origins": [ + "https://chainlist.org/chain/43114" + ], + "priceMechanism": "EIP1559", + "shortName": "AVAX", + "tokenIndex": { + "tokens": { + "STG": { + "category": "DEFI", + "chain": "AVAX", + "contractAddress": "0x2f6f07cdcf3588944bf4c42ac74ff24bf56e7590", + "decimals": 18, + "name": "StarGate token", + "origins": [ + "https://snowtrace.io/address/0x2f6f07cdcf3588944bf4c42ac74ff24bf56e7590", + "https://www.coingecko.com/en/coins/stargate-finance" + ], + "symbol": "STG" + }, + "PNG": { + "category": "DEFI", + "chain": "AVAX", + "contractAddress": "0x60781c2586d68229fde47564546784ab3faca982", + "decimals": 18, + "name": "PNG token", + "origins": [ + "https://snowtrace.io/address/0x60781c2586d68229fde47564546784ab3faca982", + "https://www.coingecko.com/en/coins/pangolin" + ], + "symbol": "PNG" + }, + "USDT": { + "category": "STABLECOIN", + "chain": "AVAX", + "contractAddress": "0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7", + "decimals": 18, + "name": "Tether stablecoin token", + "origins": [ + "https://snowtrace.io/address/0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7", + "https://www.coingecko.com/en/coins/tether" + ], + "symbol": "USDT" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "AVAX", + "contractAddress": "0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e", + "decimals": 6, + "name": "USDC stablecoin token", + "origins": [ + "https://snowtrace.io/address/0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e", + "https://www.coingecko.com/en/coins/usd-coin" + ], + "symbol": "USDC" + }, + "DAI": { + "category": "STABLECOIN", + "chain": "AVAX", + "contractAddress": "0xd586e7f844cea2f87f50152665bcbc2c279d8d70", + "decimals": 18, + "name": "DAI stablecoin token", + "origins": [ + "https://snowtrace.io/address/0xd586e7f844cea2f87f50152665bcbc2c279d8d70", + "https://www.coingecko.com/en/coins/dai" + ], + "symbol": "DAI" + } + } + }, + "type": "PUBLIC" + }, + "OASISEMERALD": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.emerald.oasis.dev/" + ], + "chainId": 42262, + "chainName": "Oasis Emerald Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-todo" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Oasis Token", + "symbol": "ROSE" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://emerald.oasis.dev", + "https://1rpc.io/oasis/emerald" + ], + "origins": [ + "https://oasisprotocol.org/" + ], + "priceMechanism": "EIP1559", + "shortName": "OASISEMERALD", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "ARBITRUMGOERLITEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://goerli.arbiscan.io/", + "https://goerli-rollup-explorer.arbitrum.io" + ], + "chainId": 421613, + "chainName": "Arbitrum Goerli Test Network", + "fallbackGasLimitInUnits": "20000000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://faucetttt", + "https://bridge.arbitrum.io" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Arbitrum Goerli ETH Test Token", + "symbol": "AGOR" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://goerli-rollup.arbitrum.io/rpc", + "https://arbitrum-goerli.public.blastapi.io", + "https://endpoints.omniatech.io/v1/arbitrum/goerli/public" + ], + "origins": [ + "https://chainlist.org/chain/421613" + ], + "priceMechanism": "EIP1559", + "shortName": "ARBITRUMGOERLITEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "CRONOS": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://cronoscan.com/" + ], + "chainId": 25, + "chainName": "Cronos Main Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://cronos.org/faucet" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "CRONOS Main Token", + "symbol": "CRO" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://cronosrpc-1.xstaking.sg", + "https://evm.cronos.org", + "https://cronos.blockpi.network/v1/rpc/public", + "https://cronos-evm.publicnode.com" + ], + "origins": [ + "https://chainlist.org/chain/25" + ], + "priceMechanism": "EIP1559", + "shortName": "CRONOS", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "LINEA": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://lineascan.build" + ], + "chainId": 59144, + "chainName": "Linea Mainnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "1600000000", + "faucets": [ + "faucet-todo" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Linea Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": { + "HRZNLP": { + "category": "LIQUIDITY_PROVIDER", + "chain": "LINEA", + "contractAddress": "0x438670d41d5118003b2f42cc0466fbadd760dbf4", + "description": "HorizonDEX Reinvestment Token", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://lineascan.build/token/0x438670d41d5118003b2f42cc0466fbadd760dbf4" + ], + "symbol": "HRZNLP" + }, + "BATTLEMON_LGEM": { + "category": "GAMING", + "chain": "LINEA", + "contractAddress": "0x6bf309ad2b7c0ebe44e69a53bb2cced79f17fc66", + "description": "BattleMon Lemon GEM", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://lineascan.build/token/0x6bf309ad2b7c0ebe44e69a53bb2cced79f17fc66", + "https://battlemon.com/" + ], + "symbol": "BATTLEMON_LGEM" + }, + "BATTLEMON_PAXE": { + "category": "GAMING", + "chain": "LINEA", + "contractAddress": "0x35d42d4bdc36cfe33a5ea6672a1b81752a963d6d", + "description": "BattleMon PickAxe", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://lineascan.build/token/0x35d42d4bdc36cfe33a5ea6672a1b81752a963d6d", + "https://battlemon.com/" + ], + "symbol": "BATTLEMON_PAXE" + } + } + }, + "nodeURLs": [ + "https://rpc.linea.build/", + "https://linea.drpc.org", + "https://linea.blockpi.network/v1/rpc/public", + "https://1rpc.io/linea" + ], + "origins": [ + "https://linea.build/" + ], + "priceMechanism": "EIP1559", + "shortName": "LINEA", + "tokenIndex": { + "tokens": { + "MATIC": { + "category": "DEFI", + "chain": "LINEA", + "contractAddress": "0x265b25e22bcd7f10a5bd6e6410f10537cc7567e8", + "decimals": 18, + "name": "MATIC token", + "origins": [ + "https://lineascan.build/token/0x265b25e22bcd7f10a5bd6e6410f10537cc7567e8" + ], + "symbol": "MATIC" + }, + "veLVC": { + "category": "DEFI", + "chain": "LINEA", + "contractAddress": "0xaec06345b26451bda999d83b361beaad6ea93f87", + "decimals": 18, + "name": "Locked Velocore token", + "origins": [ + "https://lineascan.build/token/0xaec06345b26451bda999d83b361beaad6ea93f87" + ], + "symbol": "veLVC" + }, + "LVC": { + "category": "DEFI", + "chain": "LINEA", + "contractAddress": "0xcc22f6aa610d1b2a0e89ef228079cb3e1831b1d1", + "decimals": 18, + "name": "Velocore token", + "origins": [ + "https://lineascan.build/token/0xcc22f6aa610d1b2a0e89ef228079cb3e1831b1d1" + ], + "symbol": "LVC" + }, + "WETH": { + "category": "DEFI", + "chain": "LINEA", + "contractAddress": "0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f", + "decimals": 18, + "name": "WETH token", + "origins": [ + "https://lineascan.build/address/0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f" + ], + "symbol": "WETH" + }, + "USDC": { + "category": "DEFI", + "chain": "LINEA", + "contractAddress": "0x176211869ca2b568f2a7d4ee941e073a821ee1ff", + "decimals": 6, + "name": "USDC stable token", + "origins": [ + "https://lineascan.build/token/0x176211869ca2b568f2a7d4ee941e073a821ee1ff" + ], + "symbol": "USDC" + } + } + }, + "type": "PUBLIC" + }, + "SATOSHICHAIN": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://satoshiscan.io" + ], + "chainId": 12009, + "chainName": "SatoshiChain Mainnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "550030000000000", + "faucets": [ + "https://faucet.satoshichain.io/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "SATS Token", + "symbol": "SATS" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://mainnet-rpc.satoshichain.io" + ], + "origins": [ + "https://satoshix.io/" + ], + "priceMechanism": "EIP1559", + "shortName": "SATOSHICHAIN", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "ETHOTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://testnetexplorer.ethoprotocol.com/" + ], + "chainId": 27292, + "chainName": "ETHO HC Test Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "ETHOTest Token", + "symbol": "ETHO" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://testnetrpc.ethoprotocol.com/" + ], + "origins": [ + "https://docs.ethoprotocol.com/install-metamask" + ], + "priceMechanism": "EIP1559", + "shortName": "ETHOTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "SCROLLALPHATEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://blockscout.scroll.io" + ], + "chainId": 534353, + "chainName": "Scroll Alpha Testnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://scroll.io/alpha/bridge" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Scroll Alpha Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://alpha-rpc.scroll.io/l2", + "https://scroll-alphanet.public.blastapi.io", + "https://scroll-testnet.blockpi.network/v1/rpc/public" + ], + "origins": [ + "https://scroll.io" + ], + "priceMechanism": "EIP1559", + "shortName": "SCROLLALPHATEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "TARAXA": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.mainnet.taraxa.io" + ], + "chainId": 841, + "chainName": "Taraxa Mainnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Taraxa Native Token", + "symbol": "TARA" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.mainnet.taraxa.io" + ], + "origins": [ + "https://chainlist.org/chain/841", + "https://www.coingecko.com/sv/coins/taraxa", + "https://www.taraxa.io/" + ], + "priceMechanism": "EIP1559", + "shortName": "TARAXA", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "BSC": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://bscscan.com" + ], + "chainId": 56, + "chainName": "Binance Smart Chain Mainnet", + "fallbackGasLimitInUnits": "500000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Binance Chain Native Token", + "symbol": "BNB" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": { + "DREAMCARD": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0xe6965b4f189dbdb2bd65e60abaeb531b6fe9580b", + "description": "X World Games Dreamcard", + "linked_tokens": [ + "BSC:XWG" + ], + "mintBlock": 0, + "origins": [ + "https://bscscan.com/address/0xe6965b4f189dbdb2bd65e60abaeb531b6fe9580b", + "https://babylons.io/outerringofficial" + ], + "symbol": "DREAMCARD" + }, + "OUTERRINGMMO_SPACEVEH": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0xceaac6759038d4d3b8791683b27b1021efa57003", + "description": "Outer Ring MMO Space Vehicle", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://bscscan.com/token/0xceaac6759038d4d3b8791683b27b1021efa57003", + "https://babylons.io/outerringofficial" + ], + "symbol": "OUTERRINGMMO_SPACEVEH" + }, + "OUTERRINGMMO_ARMOR": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x0b36f379d7b3b4588f8b8e7e65091b2c44fa6dde", + "description": "Outer Ring MMO Armor", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://bscscan.com/token/0x0b36f379d7b3b4588f8b8e7e65091b2c44fa6dde", + "https://babylons.io/outerringofficial" + ], + "symbol": "OUTERRINGMMO_ARMOR" + }, + "OUTERRINGMMO_EXOCRED": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x3fb6e0dd0eefff9615f186a6bb3a66a396ed0a58", + "description": "Outer Ring MMO Exocredits", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://bscscan.com/address/0x3fb6e0dd0eefff9615f186a6bb3a66a396ed0a58", + "https://babylons.io/outerringofficial" + ], + "symbol": "OUTERRINGMMO_EXOCRED" + }, + "OUTERRINGMMO_LANDVEH": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x21d7d56350fcf7470e4ac38bb2f32c1461a73d8c", + "description": "Outer Ring MMO Land Vehicle", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://bscscan.com/token/0x21d7d56350fcf7470e4ac38bb2f32c1461a73d8c", + "https://babylons.io/outerringofficial" + ], + "symbol": "OUTERRINGMMO_LANDVEH" + }, + "STELLAFANTASY_ASSET": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x80461f88de22b2363113226f0749a7a59cc2225a", + "description": "Stella Fantasy Asset", + "linked_tokens": [ + "BSC:SFTY" + ], + "mintBlock": 0, + "origins": [ + "https://bscscan.com/token/0x80461f88de22b2363113226f0749a7a59cc2225a", + "https://www.stellafantasy.io/" + ], + "symbol": "STELLAFANTASY_ASSET" + }, + "OUTERRINGMMO_WEAPON": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0xeb1aca4e9aa3448b7fecb2b555301325b5931ad9", + "description": "Outer Ring MMO Weapon", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://bscscan.com/token/0xeb1aca4e9aa3448b7fecb2b555301325b5931ad9", + "https://babylons.io/outerringofficial" + ], + "symbol": "OUTERRINGMMO_WEAPON" + } + } + }, + "nodeURLs": [ + "https://bsc-dataseed.binance.org", + "https://bsc-dataseed1.binance.org", + "https://bsc-dataseed2.binance.org", + "https://bsc-dataseed3.binance.org", + "https://bsc-dataseed4.binance.org", + "https://bsc-dataseed1.defibit.io", + "https://bsc-dataseed2.defibit.io", + "https://bsc-dataseed3.defibit.io", + "https://bsc-dataseed4.defibit.io", + "https://bsc-dataseed1.ninicoin.io", + "https://bsc-dataseed2.ninicoin.io", + "https://bsc-dataseed3.ninicoin.io", + "https://bsc-dataseed4.ninicoin.io" + ], + "origins": [ + "https://chainlist.org/chain/56" + ], + "priceMechanism": "LEGACY", + "shortName": "BSC", + "tokenIndex": { + "tokens": { + "STARGATE_BUSD_LP": { + "category": "LIQUIDITY_PROVIDER", + "chain": "BSC", + "contractAddress": "0x98a5737749490856b401db5dc27f522fc314a4e1", + "decimals": 18, + "name": "StarGate sBUSD Pool token", + "origins": [ + "https://bscscan.com/token/0x98a5737749490856b401db5dc27f522fc314a4e1" + ], + "symbol": "STARGATE_BUSD_LP" + }, + "SUPS": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0xc99cfaa8f5d9bd9050182f29b83cc9888c5846c4", + "decimals": 18, + "name": "Supremacy game token", + "origins": [ + "https://bscscan.com/address/0xc99cfaa8f5d9bd9050182f29b83cc9888c5846c4", + "https://www.coingecko.com/en/coins/supremacy" + ], + "symbol": "SUPS" + }, + "VAN": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0xd3dbf84f7aed90d5f56e8d7cab2f43004e9ef6a6", + "decimals": 18, + "name": "Outer Ring MMO Vanadium Token", + "origins": [ + "https://bscscan.com/token/0xd3dbf84f7aed90d5f56e8d7cab2f43004e9ef6a6" + ], + "symbol": "VAN" + }, + "STG": { + "category": "DEFI", + "chain": "BSC", + "contractAddress": "0xb0d502e938ed5f4df2e681fe6e419ff29631d62b", + "decimals": 18, + "name": "StarGate token", + "origins": [ + "https://bscscan.com/address/0xb0d502e938ed5f4df2e681fe6e419ff29631d62b", + "https://www.coingecko.com/en/coins/stargate-finance" + ], + "symbol": "STG" + }, + "USDT": { + "category": "STABLECOIN", + "chain": "BSC", + "contractAddress": "0x55d398326f99059ff775485246999027b3197955", + "decimals": 18, + "name": "Tether stablecoin token", + "origins": [ + "https://bscscan.com/address/0x55d398326f99059ff775485246999027b3197955", + "https://www.coingecko.com/en/coins/tether" + ], + "symbol": "USDT" + }, + "XVS": { + "category": "DEFI", + "chain": "BSC", + "contractAddress": "0xcf6bb5389c92bdda8a3747ddb454cb7a64626c63", + "decimals": 18, + "name": "Venus Token", + "origins": [ + "https://bscscan.com/address/0xcf6bb5389c92bdda8a3747ddb454cb7a64626c63", + "https://www.coingecko.com/en/coins/venus" + ], + "symbol": "XVS" + }, + "PLU": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x07958be5d12365db62a6535d0a88105944a2e81e", + "decimals": 18, + "name": "Outer Ring MMO Plutonium Token", + "origins": [ + "https://bscscan.com/token/0x07958be5d12365db62a6535d0a88105944a2e81e" + ], + "symbol": "PLU" + }, + "ACE": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x6bf6c2b429421a55d90a02c56b2d8bffbc636039", + "decimals": 18, + "name": "Outer Ring MMO Acetylene Token", + "origins": [ + "https://bscscan.com/token/0x6bf6c2b429421a55d90a02c56b2d8bffbc636039" + ], + "symbol": "ACE" + }, + "COP": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x892f23e32b82ef0d5394cf33dcd4dff7f4b274b0", + "decimals": 18, + "name": "Outer Ring MMO Copper Token", + "origins": [ + "https://bscscan.com/token/0x892f23e32b82ef0d5394cf33dcd4dff7f4b274b0" + ], + "symbol": "COP" + }, + "CHMB": { + "category": "DEFI", + "chain": "BSC", + "contractAddress": "0x5492ef6aeeba1a3896357359ef039a8b11621b45", + "decimals": 18, + "name": "Chumbi Valley Game Token", + "origins": [ + "https://bscscan.com/token/0x5492ef6aeeba1a3896357359ef039a8b11621b45", + "https://www.coingecko.com/en/coins/chumbai-valley" + ], + "symbol": "CHMB" + }, + "VIKINGSWAP": { + "category": "DEFI", + "chain": "BSC", + "contractAddress": "0x896ede222d3f7f3414e136a2791bdb08aaa25ce0", + "decimals": 18, + "name": "Vikingswap Token", + "origins": [ + "https://bscscan.com/address/0x896ede222d3f7f3414e136a2791bdb08aaa25ce0", + "https://www.coingecko.com/en/coins/viking-swap" + ], + "symbol": "VIKINGSWAP" + }, + "BABYCAKE": { + "category": "DEFI", + "chain": "BSC", + "contractAddress": "0xdb8d30b74bf098af214e862c90e647bbb1fcc58c", + "decimals": 18, + "name": "BABYCAKE DEFI reflection Token", + "origins": [ + "https://bscscan.com/token/0xdb8d30b74bf098af214e862c90e647bbb1fcc58c", + "https://www.coingecko.com/en/coins/baby-cake" + ], + "symbol": "BABYCAKE" + }, + "CAKE": { + "category": "DEFI", + "chain": "BSC", + "contractAddress": "0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82", + "decimals": 18, + "name": "Pancakeswap DEFI Token", + "origins": [ + "https://bscscan.com/token/0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82", + "https://www.coingecko.com/en/coins/pancakeswap" + ], + "symbol": "CAKE" + }, + "MOBOX": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x3203c9e46ca618c8c1ce5dc67e7e9d75f5da2377", + "decimals": 18, + "name": "MOBOX game token", + "origins": [ + "https://bscscan.com/address/0x3203c9e46ca618c8c1ce5dc67e7e9d75f5da2377", + "https://www.coingecko.com/en/coins/mobox" + ], + "symbol": "MOBOX" + }, + "NIC": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0xf9a71cba51e260e184a72d9edf888d3f99f3bac1", + "decimals": 18, + "name": "Outer Ring MMO Nickel Token", + "origins": [ + "https://bscscan.com/token/0xf9a71cba51e260e184a72d9edf888d3f99f3bac1" + ], + "symbol": "NIC" + }, + "XWG": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x6b23c89196deb721e6fd9726e6c76e4810a464bc", + "decimals": 18, + "name": "X World Games Token", + "origins": [ + "https://bscscan.com/address/0x6b23c89196deb721e6fd9726e6c76e4810a464bc", + "https://www.coingecko.com/en/coins/x-world-games" + ], + "symbol": "XWG" + }, + "GQ": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0xf700d4c708c2be1463e355f337603183d20e0808", + "decimals": 18, + "name": "Outer Ring MMO Game Token", + "origins": [ + "https://bscscan.com/address/0xf700d4c708c2be1463e355f337603183d20e0808", + "https://www.coingecko.com/en/coins/outer-ring" + ], + "symbol": "GQ" + }, + "IRON": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0xbd1945cd85a2be93a6475381c9f5edf19407a921", + "decimals": 18, + "name": "Outer Ring MMO Iron Token", + "origins": [ + "https://bscscan.com/token/0xbd1945cd85a2be93a6475381c9f5edf19407a921" + ], + "symbol": "IRON" + }, + "DAI": { + "category": "STABLECOIN", + "chain": "BSC", + "contractAddress": "0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3", + "decimals": 18, + "name": "DAI stablecoin token", + "origins": [ + "https://bscscan.com/address/0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3", + "https://www.coingecko.com/en/coins/dai" + ], + "symbol": "DAI" + }, + "CAR": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x253b7a24003684f7b4fe87e531a017c7382a3894", + "decimals": 18, + "name": "Outer Ring MMO Carbon Token", + "origins": [ + "https://bscscan.com/token/0x253b7a24003684f7b4fe87e531a017c7382a3894" + ], + "symbol": "CAR" + }, + "TEST": { + "category": "TEST", + "chain": "BSC", + "contractAddress": "0x1c3c3941acb8a9be35e50f086fae6a481f7d9df7", + "decimals": 18, + "name": "TEST token", + "origins": [ + "https://bscscan.com/token/0xMOJO" + ], + "symbol": "TEST" + }, + "ARG": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x0efcf1737b81ce89325b17eafae2686a8afe8bd4", + "decimals": 18, + "name": "Outer Ring MMO Acetylene Token", + "origins": [ + "https://bscscan.com/token/0x0efcf1737b81ce89325b17eafae2686a8afe8bd4" + ], + "symbol": "ARG" + }, + "SCK": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x227a3ef4d41d0215123f3197faa087bf71d2236a", + "decimals": 18, + "name": "Space Corsair Key", + "origins": [ + "https://bscscan.com/address/0x227a3ef4d41d0215123f3197faa087bf71d2236a", + "https://www.coingecko.com/en/coins/space-corsair-key" + ], + "symbol": "SCK" + }, + "TRON": { + "category": "SCAM", + "chain": "BSC", + "contractAddress": "0x85eac5ac2f758618dfa09bdbe0cf174e7d574d5b", + "decimals": 18, + "name": "TRON TRX token", + "origins": [ + "https://coinmarketcap.com/currencies/tron/" + ], + "symbol": "TRON" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "BSC", + "contractAddress": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "decimals": 6, + "name": "USDC stablecoin token", + "origins": [ + "https://bscscan.com/address/0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "https://www.coingecko.com/en/coins/usd-coin" + ], + "symbol": "USDC" + }, + "METIS": { + "category": "GASCURRENCY", + "chain": "BSC", + "contractAddress": "0xe552fb52a4f19e44ef5a967632dbc320b0820639", + "decimals": 18, + "name": "METIS token on BSC", + "origins": [ + "https://bscscan.com/address/0xe552fb52a4f19e44ef5a967632dbc320b0820639", + "https://www.coingecko.com/en/coins/metis-token" + ], + "symbol": "METIS" + }, + "BUSD": { + "category": "STABLECOIN", + "chain": "BSC", + "contractAddress": "0xe9e7cea3dedca5984780bafc599bd69add087d56", + "decimals": 18, + "name": "Binance stablecoin token", + "origins": [ + "https://bscscan.com/address/0xe9e7cea3dedca5984780bafc599bd69add087d56", + "https://www.coingecko.com/en/coins/binance-usd" + ], + "symbol": "BUSD" + }, + "NFTART": { + "category": "DEFI", + "chain": "BSC", + "contractAddress": "0xf7844cb890f4c339c497aeab599abdc3c874b67a", + "decimals": 18, + "name": "NFT Art Token", + "origins": [ + "https://bscscan.com/address/0xf7844cb890f4c339c497aeab599abdc3c874b67a", + "https://www.coingecko.com/en/coins/nft-art-finance" + ], + "symbol": "NFTART" + }, + "MET": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0x03697caf2e5458c7c2a8d9f8818079c2ae72f353", + "decimals": 18, + "name": "Outer Ring MMO Methane Token", + "origins": [ + "https://bscscan.com/token/0x03697caf2e5458c7c2a8d9f8818079c2ae72f353" + ], + "symbol": "MET" + }, + "SFTY": { + "category": "GAMING", + "chain": "BSC", + "contractAddress": "0xe9d6d6d7cde5c7d45927f8c37460d932e612c902", + "decimals": 18, + "name": "Stella Fantasy gaming token", + "origins": [ + "https://bscscan.com/address/0xe9d6d6d7cde5c7d45927f8c37460d932e612c902", + "https://www.coingecko.com/en/coins/stella-fantasy-token" + ], + "symbol": "SFTY" + }, + "CATGIRL": { + "category": "NFT", + "chain": "BSC", + "contractAddress": "0x79ebc9a2ce02277a4b5b3a768b1c0a4ed75bd936", + "decimals": 18, + "name": "Catgirl NFT Token", + "origins": [ + "https://bscscan.com/address/0x79ebc9a2ce02277a4b5b3a768b1c0a4ed75bd936", + "https://www.coingecko.com/en/coins/catgirl" + ], + "symbol": "CATGIRL" + } + } + }, + "type": "PUBLIC" + }, + "MOONBEAM": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://moonscan.io" + ], + "chainId": 1284, + "chainName": "Moonbeam Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Moonbeam Native Token", + "symbol": "GLMR" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": { + "SNAKESOLDIERS": { + "category": "SOCIAL", + "chain": "MOONBEAM", + "contractAddress": "0x3ab955216bdd76f51fbe02a3fe237d6612bbd09f", + "description": "ZKSyncEra Ape", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://moonscan.io/token/0x3ab955216bdd76f51fbe02a3fe237d6612bbd09f", + "https://snakesoldiers.com" + ], + "symbol": "SNAKESOLDIERS" + } + } + }, + "nodeURLs": [ + "https://rpc.api.moonbeam.network", + "https://rpc.ankr.com/moonbeam", + "https://moonbeam.public.blastapi.io", + "https://moonbeam.unitedbloc.com:3000", + "https://moonbeam.api.onfinality.io/public" + ], + "origins": [ + "https://chainlist.org/chain/1284" + ], + "priceMechanism": "EIP1559", + "shortName": "MOONBEAM", + "tokenIndex": { + "tokens": { + "mGLMR": { + "category": "DEFI", + "chain": "MOONBEAM", + "contractAddress": "0x091608f4e4a15335145be0A279483C0f8E4c7955", + "decimals": 8, + "name": "Moonwell GLMR token", + "origins": [ + "https://moonscan.io/token/0x091608f4e4a15335145be0a279483c0f8e4c7955", + "https://moonwell.fi/artemis/GLMR" + ], + "symbol": "mGLMR" + }, + "WELL": { + "category": "DEFI", + "chain": "MOONBEAM", + "contractAddress": "0x511ab53f793683763e5a8829738301368a2411e3", + "decimals": 18, + "name": "Moonwell WELL token", + "origins": [ + "https://moonscan.io/address/0x511ab53f793683763e5a8829738301368a2411e3", + "https://www.coingecko.com/en/coins/moonwell" + ], + "symbol": "WELL" + } + } + }, + "type": "PUBLIC" + }, + "ZORATEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://testnet.explorer.zora.co", + "https://goerli.etherscan.io/address/0xDb9F51790365e7dc196e7D072728df39Be958ACe" + ], + "chainId": 999, + "chainName": "Zora Goerli Testnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://bridgetozora.world/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Zora Testnet Gas Token", + "symbol": "GöETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://testnet.rpc.zora.co" + ], + "origins": [ + "https://zora.energy" + ], + "priceMechanism": "EIP1559", + "shortName": "ZORATEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "BITKUB": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://bkcscan.com" + ], + "chainId": 96, + "chainName": "Bitkub Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Bitkub Native Token", + "symbol": "KUB" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": { + "MMV_ITEM": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xd08ac40b3a0a7fb20b026a3b6cd5d7cfadc3d6f5", + "description": "Morning Moon Village game item", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://www.bkcscan.com/address/0xd08ac40b3a0a7fb20b026a3b6cd5d7cfadc3d6f5", + "https://morningmoonvillage.com/", + "https://mmv.megaland.io/" + ], + "symbol": "MMV_ITEM" + }, + "SANDX": { + "category": "NFT", + "chain": "BITKUB", + "contractAddress": "0x998c4a4f5231b10ad867bd5d99fa181495f34cd8", + "description": "SandX NFT", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://www.bkcscan.com/address/0x998c4a4f5231b10ad867bd5d99fa181495f34cd8", + "https://www.megaland.io/" + ], + "symbol": "SANDX" + } + } + }, + "nodeURLs": [ + "https://rpc.bitkubchain.io" + ], + "origins": [ + "https://support.bitkub.com/hc/en-us/articles/360061315771-How-to-connect-an-online-wallet-to-Bitkub-Chain-Metamask" + ], + "priceMechanism": "LEGACY", + "shortName": "BITKUB", + "tokenIndex": { + "tokens": { + "MMV_CABBAGESEED": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x1f8b5af0ec97c44b24366b36c40f2d4aca2c73e2", + "decimals": 18, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x1f8b5af0ec97c44b24366b36c40f2d4aca2c73e2/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_CABBAGESEED" + }, + "MMV_TOMATOSOUP": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xbE46a81D181069aC0Ff18F4F7239Df10422E6DC3", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xbE46a81D181069aC0Ff18F4F7239Df10422E6DC3/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_TOMATOSOUP" + }, + "MMV_GREENHERB": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xde496524c30c460922e7810ddc6c806c0e2c5354", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xde496524c30c460922e7810ddc6c806c0e2c5354/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_GREENHERB" + }, + "MMV_SHITAKE_MUSHROOM": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xd3b314b101b26fa2bd19df0d845a632d72c4fc44", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xd3b314b101b26fa2bd19df0d845a632d72c4fc44/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_SHITAKE_MUSHROOM" + }, + "USDT": { + "category": "STABLECOIN", + "chain": "BITKUB", + "contractAddress": "0x7d984c24d2499d840eb3b7016077164e15e5faa6", + "decimals": 18, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x7d984c24d2499d840eb3b7016077164e15e5faa6/token-transfers" + ], + "symbol": "USDT" + }, + "MMV_TOMATOSEED": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xe991151Bf43bD712beAC33e5cFF2580841c9b440", + "decimals": 18, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xe991151Bf43bD712beAC33e5cFF2580841c9b440/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_TOMATOSEED" + }, + "MMV_LEATHER_PIECE": { + "category": "DEFI", + "chain": "BITKUB", + "contractAddress": "0x15aa87eb74069d3800f8e75A93FC04fda79AA24d", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x15aa87eb74069d3800f8e75A93FC04fda79AA24d/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_LEATHER_PIECE" + }, + "MMV_HONEY": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x575d7bfdbdf255d5741571334f159d903de1544f", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x575d7bfdbdf255d5741571334f159d903de1544f/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_HONEY" + }, + "KKUB": { + "category": "DEFI", + "chain": "BITKUB", + "contractAddress": "0x67eBD850304c70d983B2d1b93ea79c7CD6c3F6b5", + "decimals": 18, + "name": "Wrapped KUB (KKUB) token", + "origins": [ + "https://www.bkcscan.com/tokens/0x67eBD850304c70d983B2d1b93ea79c7CD6c3F6b5/token-transfers" + ], + "symbol": "KKUB" + }, + "MMV_SF_CABBAGE": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xc2990515610028139f68016b321a0c36a5101104", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xc2990515610028139f68016b321a0c36a5101104/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_SF_CABBAGE" + }, + "MMV_SILVERKEY": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x73d05f935534918bbc87cb353928cb957ed03697", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x73d05f935534918bbc87cb353928cb957ed03697/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_SILVERKEY" + }, + "MMV_LUMI": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x95013dcb6a561e6c003aed9c43fb8b64008aa361", + "decimals": 18, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x95013dcb6a561e6c003aed9c43fb8b64008aa361/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_LUMI" + }, + "MMV_DRIEDAPPLE": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xb035c229903a0cff939be36b532d8c11204e6837", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xb035c229903a0cff939be36b532d8c11204e6837/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_DRIEDAPPLE" + }, + "MMV_BANANA": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x0944882cf373adc8c3de740821fb14c8669e89eb", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x0944882cf373adc8c3de740821fb14c8669e89eb/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_BANANA" + }, + "MMV_REDHERB": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x3F69C740456150268C5e23bD05a2A10Bf9e5c3CB", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x3F69C740456150268C5e23bD05a2A10Bf9e5c3CB/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_REDHERB" + }, + "MMV_HEALTHPOTION": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xbd60c8caf6e22907576d9e363ab1f91b43aaf769", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xbd60c8caf6e22907576d9e363ab1f91b43aaf769/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_HEALTHPOTION" + }, + "MMV_DIAMON_LP": { + "category": "DEFI", + "chain": "BITKUB", + "contractAddress": "0x7Bf51541208A70b784006eF7Bd6F774F4012Cd38", + "decimals": 18, + "name": "Morning Moon Village diamon LP", + "origins": [ + "https://www.bkcscan.com/tokens/0x7Bf51541208A70b784006eF7Bd6F774F4012Cd38/token-transfers" + ], + "symbol": "MMV_DIAMON_LP" + }, + "MMV_RAG": { + "category": "DEFI", + "chain": "BITKUB", + "contractAddress": "0x1F14690e6c7D02fCeB67c6b818aa2C093e16fe27", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x1F14690e6c7D02fCeB67c6b818aa2C093e16fe27/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_RAG" + }, + "MMV_KTRUMPET_MUSHROOM": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xc14f24835efe355106ab8725488f16f93c8c5f96", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xc14f24835efe355106ab8725488f16f93c8c5f96/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_KTRUMPET_MUSHROOM" + }, + "MMV_CORNSEED": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xe27aebed61be207e83fc05fbc408420c737881da", + "decimals": 18, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xe27aebed61be207e83fc05fbc408420c737881da/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_CORNSEED" + }, + "MMV_GREENAPPLE": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x417e28bd41cd45d9f996b69450f81b02821a6d64", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x417e28bd41cd45d9f996b69450f81b02821a6d64/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_GREENAPPLE" + }, + "MMV_CARROTSEED": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x7b263d648fff39142abecb07a1bb85297e09982d", + "decimals": 18, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x7b263d648fff39142abecb07a1bb85297e09982d/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_CARROTSEED" + }, + "MMV_LHEALTHPOTION": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xe66f21d817af8f99129af6023332dd7b37503b9d", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xe66f21d817af8f99129af6023332dd7b37503b9d/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_LHEALTHPOTION" + }, + "MMV_SALAD": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x2944d051dc66669e04629b827ae9e3ebcb1e48d9", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x2944d051dc66669e04629b827ae9e3ebcb1e48d9/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_SALAD" + }, + "MMV_CORNSOUP": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0x2b09ae76dfc601210407560502b340e104787b34", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0x2b09ae76dfc601210407560502b340e104787b34/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_CORNSOUP" + }, + "MMV_WBUTTON_MUSHROOM": { + "category": "GAMING", + "chain": "BITKUB", + "contractAddress": "0xcb74a1A9dB4285E97D4dE8aa4B61cd10277Ab479", + "decimals": 0, + "name": "Morning Moon Village game item", + "origins": [ + "https://www.bkcscan.com/tokens/0xcb74a1A9dB4285E97D4dE8aa4B61cd10277Ab479/token-transfers", + "https://morningmoonvillage.com/" + ], + "symbol": "MMV_WBUTTON_MUSHROOM" + } + } + }, + "type": "PUBLIC" + }, + "MOONRIVER": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://moonriver.moonscan.io" + ], + "chainId": 1285, + "chainName": "Moonbeam Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "MoonRiver Native Token", + "symbol": "MOVR" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://moonriver.unitedbloc.com:2000", + "https://moonriver.public.blastapi.io", + "https://rpc.api.moonriver.moonbeam.network", + "https://moonriver.api.onfinality.io/public" + ], + "origins": [ + "https://chainlist.org/chain/1285" + ], + "priceMechanism": "EIP1559", + "shortName": "MOONRIVER", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "TENET": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://tenetscan.io" + ], + "chainId": 1559, + "chainName": "Tenet Mainnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "TENET Gas Token", + "symbol": "TENET" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.tenet.org", + "https://tenet-evm.publicnode.com" + ], + "origins": [ + "https://ethereumpow.org/" + ], + "priceMechanism": "EIP1559", + "shortName": "TENET", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "AURORATEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.testnet.aurora.dev/" + ], + "chainId": 1313161555, + "chainName": "Aurora Testnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Aurora Token", + "symbol": "AETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://endpoints.omniatech.io/v1/aurora/testnet/public", + "https://1rpc.io/aurora" + ], + "origins": [ + "https://chainlist.org/chain/1313161555" + ], + "priceMechanism": "EIP1559", + "shortName": "AURORATEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "SHARDEUMLIBERTY2xTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.liberty20.shardeum.org" + ], + "chainId": 8081, + "chainName": "Shardeum Liberty 2.0", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://docs.shardeum.org/faucet/claim" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Shardeum Native Token", + "symbol": "SHM" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://liberty20.shardeum.org" + ], + "origins": [ + "https://docs.shardeum.org/wallets/MetaMask/add-shardeum-network" + ], + "priceMechanism": "LEGACY", + "shortName": "SHARDEUMLIBERTY2xTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "CONFLUXTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://evmtestnet.confluxscan.net" + ], + "chainId": 71, + "chainName": "Conflux Testnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://efaucet.confluxnetwork.org/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Conflux Token", + "symbol": "CFX" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://evmtestnet.confluxrpc.com" + ], + "origins": [ + "https://confluxnetwork.org/" + ], + "priceMechanism": "EIP1559", + "shortName": "CONFLUXTEST", + "tokenIndex": { + "tokens": { + "USDT": { + "category": "STABLECOIN", + "chain": "CONFLUXTEST", + "contractAddress": "0x7d682e65efc5c13bf4e394b8f376c48e6bae0355", + "decimals": 18, + "name": "Tether stable coin", + "origins": [ + "https://evmtestnet.confluxscan.net/address/0x7d682e65efc5c13bf4e394b8f376c48e6bae0355" + ], + "symbol": "USDT" + }, + "WETH": { + "category": "DEFI", + "chain": "CONFLUXTEST", + "contractAddress": "0xcd71270f82f319e0498ff98af8269c3f0d547c65", + "decimals": 18, + "name": "Wrapped ETH token", + "origins": [ + "https://evmtestnet.confluxscan.io/address/0xcd71270f82f319e0498ff98af8269c3f0d547c65" + ], + "symbol": "WETH" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "CONFLUXTEST", + "contractAddress": "0x349298b0e20df67defd6efb8f3170cf4a32722ef", + "decimals": 18, + "name": "USDC stable coin", + "origins": [ + "https://evmtestnet.confluxscan.io/address/0x349298b0e20df67defd6efb8f3170cf4a32722ef" + ], + "symbol": "USDC" + }, + "VSWAP": { + "category": "DEFI", + "chain": "CONFLUXTEST", + "contractAddress": "0x2c0230516cfcddcd2a5256400c4593deaa243259", + "decimals": 18, + "name": "Vswap token", + "origins": [ + "https://evmtestnet.confluxscan.io/address/0x2c0230516cfcddcd2a5256400c4593deaa243259", + "https://app-testnet.vswap.finance" + ], + "symbol": "VSWAP" + } + } + }, + "type": "PUBLIC" + }, + "FANTOM": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://ftmscan.com" + ], + "chainId": 250, + "chainName": "Fantom Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://faucet.fantom.network/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Fantom Native Token", + "symbol": "FTM" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.ftm.tools", + "https://fantom-mainnet.gateway.pokt.network/v1/lb/62759259ea1b320039c9e7ac", + "https://rpc.ankr.com/fantom", + "https://rpc2.fantom.network", + "https://rpcapi.fantom.network", + "https://fantom-mainnet.public.blastapi.io" + ], + "origins": [ + "https://chainlist.org/chain/250" + ], + "priceMechanism": "EIP1559", + "shortName": "FANTOM", + "tokenIndex": { + "tokens": { + "SPOOKYSWAP_FTM_MULTI_LP": { + "category": "LIQUIDITY_PROVIDER", + "chain": "FANTOM", + "contractAddress": "0x297C8990134bf1eE08aE5D8805042fbac8781201", + "decimals": 18, + "name": "Spookyswap FTM+MULTI LP token", + "origins": [ + "https://ftmscan.com/token/0x297c8990134bf1ee08ae5d8805042fbac8781201?a=0xf0803b4cf6359d64913ec6a0b8227640afe69b2a", + "https://spooky.fi/#/add/FTM/0x9Fb9a33956351cf4fa040f65A13b835A3C8764E3" + ], + "symbol": "SPOOKYSWAP_FTM_MULTI_LP" + }, + "TEST": { + "category": "TEST", + "chain": "FANTOM", + "contractAddress": "0x62b65f4b89e9a56b687ccebb57b4afeafa933894", + "decimals": 18, + "name": "TEST token", + "origins": [ + "https://polygonscan.com/token/0xMOJO" + ], + "symbol": "TEST" + }, + "STG": { + "category": "DEFI", + "chain": "FANTOM", + "contractAddress": "0x2f6f07cdcf3588944bf4c42ac74ff24bf56e7590", + "decimals": 18, + "name": "StarGate token", + "origins": [ + "https://ftmscan.com/address/0x2f6f07cdcf3588944bf4c42ac74ff24bf56e7590", + "https://www.coingecko.com/en/coins/stargate-finance" + ], + "symbol": "STG" + }, + "USDT": { + "category": "STABLECOIN", + "chain": "FANTOM", + "contractAddress": "0x049d68029688eabf473097a2fc38ef61633a3c7a", + "decimals": 18, + "name": "Tether stablecoin token", + "origins": [ + "https://ftmscan.com/address/0x049d68029688eabf473097a2fc38ef61633a3c7a", + "https://www.coingecko.com/en/coins/tether" + ], + "symbol": "USDT" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "FANTOM", + "contractAddress": "0x04068da6c83afcfa0e13ba15a6696662335d5b75", + "decimals": 6, + "name": "USDC stablecoin token", + "origins": [ + "https://ftmscan.com/address/0x04068da6c83afcfa0e13ba15a6696662335d5b75", + "https://www.coingecko.com/en/coins/usd-coin" + ], + "symbol": "USDC" + }, + "MULTI": { + "category": "DEFI", + "chain": "FANTOM", + "contractAddress": "0x9fb9a33956351cf4fa040f65a13b835a3c8764e3", + "decimals": 18, + "name": "Multichain token", + "origins": [ + "https://ftmscan.com/address/0x9fb9a33956351cf4fa040f65a13b835a3c8764e3", + "https://www.coingecko.com/en/coins/multichain" + ], + "symbol": "MULTI" + }, + "DAI": { + "category": "STABLECOIN", + "chain": "FANTOM", + "contractAddress": "0x8d11ec38a3eb5e956b052f67da8bdc9bef8abf3e", + "decimals": 18, + "name": "DAI stablecoin token", + "origins": [ + "https://ftmscan.com/address/0x8d11ec38a3eb5e956b052f67da8bdc9bef8abf3e", + "https://www.coingecko.com/en/coins/dai" + ], + "symbol": "DAI" + } + } + }, + "type": "PUBLIC" + }, + "ZKEVM": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://zkevm.polygonscan.com/" + ], + "chainId": 1101, + "chainName": "Polygon ZKEVM Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://bridge.zkevm-rpc.com/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "ETH Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://zkevm-rpc.com", + "https://rpc.polygon-zkevm.gateway.fm", + "https://rpc.ankr.com/polygon_zkevm" + ], + "origins": [ + "https://wiki.polygon.technology/docs/zkEVM/develop" + ], + "priceMechanism": "EIP1559", + "shortName": "ZKEVM", + "tokenIndex": { + "tokens": { + "GAMMA_aUSDC_DAI_LP": { + "category": "LIQUIDITY_PROVIDER", + "chain": "ZKEVM", + "contractAddress": "0xafad6e114cfbc8a19e91b8d7d04da740a7698595", + "decimals": 18, + "name": "aUSDC-DAI LP token", + "origins": [ + "https://zkevm.polygonscan.com/token/0xafad6e114cfbc8a19e91b8d7d04da740a7698595" + ], + "symbol": "GAMMA_aUSDC_DAI_LP" + }, + "USDT": { + "category": "STABLECOIN", + "chain": "ZKEVM", + "contractAddress": "0x1e4a5963abfd975d8c9021ce480b42188849d41d", + "decimals": 6, + "name": "USDT stablecoin token", + "origins": [ + "https://zkevm.polygonscan.com/token/0x1e4a5963abfd975d8c9021ce480b42188849d41d", + "https://www.coingecko.com/en/coins/tether" + ], + "symbol": "USDT" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "ZKEVM", + "contractAddress": "0xa8ce8aee21bc2a48a5ef670afcc9274c7bbbc035", + "decimals": 6, + "name": "USDC stablecoin token", + "origins": [ + "https://zkevm.polygonscan.com/token/0xa8ce8aee21bc2a48a5ef670afcc9274c7bbbc035", + "https://www.coingecko.com/en/coins/usd-coin" + ], + "symbol": "USDC" + }, + "DAI": { + "category": "STABLECOIN", + "chain": "ZKEVM", + "contractAddress": "0xc5015b9d9161dca7e18e32f6f25c4ad850731fd4", + "decimals": 18, + "name": "DAI stablecoin token", + "origins": [ + "https://zkevm.polygonscan.com/address/0xc5015b9d9161dca7e18e32f6f25c4ad850731fd4", + "https://www.coingecko.com/en/coins/dai" + ], + "symbol": "DAI" + } + } + }, + "type": "PUBLIC" + }, + "TAIKOALPHA3TEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.test.taiko.xyz" + ], + "chainId": 167005, + "chainName": "Taiko Ethereum A3 Test Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://bridge.test.taiko.xyz/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Taiko A3 Test Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.test.taiko.xyz" + ], + "origins": [ + "https://taiko.xyz" + ], + "priceMechanism": "EIP1559", + "shortName": "TAIKOALPHA3TEST", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "TAIKOALPHA2TEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.a2.taiko.xyz" + ], + "chainId": 167004, + "chainName": "Taiko Ethereum A2 Test Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://bridge.test.taiko.xyz/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Taiko A2 Test Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.a2.taiko.xyz" + ], + "origins": [ + "https://taiko.xyz" + ], + "priceMechanism": "EIP1559", + "shortName": "TAIKOALPHA2TEST", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "WEMIX": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.wemix.com" + ], + "chainId": 1111, + "chainName": "WEMIX mainnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "101000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "WEMIX", + "symbol": "WEMIX" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://api.wemix.com/" + ], + "origins": [ + "https://chainlist.org/chain/1111", + "https://medium.com/wemix-communication/metamask-wemix3-0-mainnet-setting-guide-1a249fcaf866" + ], + "priceMechanism": "EIP1559", + "shortName": "WEMIX", + "tokenIndex": { + "tokens": { + "WEMIX$": { + "category": "STABLECOIN", + "chain": "WEMIX", + "contractAddress": "0x8e81fcc2d4a3baa0ee9044e0d7e36f59c9bba9c1", + "decimals": 18, + "name": "WEMIX USD token", + "origins": [ + "https://explorer.wemix.com/token/0x8e81fcc2d4a3baa0ee9044e0d7e36f59c9bba9c1/transfers" + ], + "symbol": "WEMIX$" + }, + "KLAY": { + "category": "DEFI", + "chain": "WEMIX", + "contractAddress": "0x461d52769884ca6235B685EF2040F47d30C94EB5", + "decimals": 18, + "name": "Wrapped KLAY token", + "origins": [ + "https://explorer.wemix.com/address/0x461d52769884ca6235B685EF2040F47d30C94EB5" + ], + "symbol": "KLAY" + } + } + }, + "type": "PUBLIC" + }, + "LINEATEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.goerli.linea.build" + ], + "chainId": 59140, + "chainName": "Linea Testnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "1600000000", + "faucets": [ + "faucet-todo" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Linea Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.goerli.linea.build" + ], + "origins": [ + "https://linea.build/" + ], + "priceMechanism": "EIP1559", + "shortName": "LINEATEST", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "KOVANTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://kovan.etherscan.io" + ], + "chainId": 42, + "chainName": "Kovan Test Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "discontinued" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Kovan Test Token", + "symbol": "KOV" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://kovan.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161", + "https://kovan.poa.network" + ], + "origins": [ + "https://rpc.info/" + ], + "priceMechanism": "EIP1559", + "shortName": "KOVANTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "BOBARINKEBYTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://blockexplorer.rinkeby.boba.network" + ], + "chainId": 28, + "chainName": "Boba Rinkeby Test Token", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Boba Rinkeby Test Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rinkeby.boba.network" + ], + "origins": [ + "https://chainlist.org/chain/28" + ], + "priceMechanism": "LEGACY", + "shortName": "BOBARINKEBYTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "EVMOSTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://evm.evmos.dev/" + ], + "chainId": 9000, + "chainName": "EVMOS Testnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://faucet.evmos.dev/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "tEVMOS", + "symbol": "tEVMOS" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://eth.bd.evmos.dev:8545" + ], + "origins": [ + "https://chainlist.org/chain/9000" + ], + "priceMechanism": "EIP1559", + "shortName": "EVMOSTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "MILKOMEDAA1": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer-mainnet-algorand-rollup.a1.milkomeda.com" + ], + "chainId": 2002, + "chainName": "Milkomeda Algorand mainnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "milkALGO", + "symbol": "milkALGO" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc-mainnet-algorand-rollup.a1.milkomeda.com" + ], + "origins": [ + "https://chainlist.org/chain/2002", + "https://dcspark.github.io/milkomeda-documentation/algorand/for-end-users/configuring-metamask/", + "https://algorand-bridge.milkomeda.com/mainnet" + ], + "priceMechanism": "EIP1559", + "shortName": "MILKOMEDAA1", + "tokenIndex": { + "tokens": { + "USDC": { + "category": "STABLECOIN", + "chain": "MILKOMEDAA1", + "contractAddress": "0xBc31960A049Fe10297Ed8432Fb61DD734fEAd4ea", + "decimals": 6, + "name": "USDC stable token", + "origins": [ + "https://explorer-mainnet-algorand-rollup.a1.milkomeda.com/address/0xBc31960A049Fe10297Ed8432Fb61DD734fEAd4ea" + ], + "symbol": "USDC" + }, + "BLUES": { + "category": "DEFI", + "chain": "MILKOMEDAA1", + "contractAddress": "0xc9BAA8cfdDe8E328787E29b4B078abf2DaDc2055", + "decimals": 18, + "name": "BlueShift DEFI token", + "origins": [ + "https://explorer-mainnet-algorand-rollup.a1.milkomeda.com/address/0xc9BAA8cfdDe8E328787E29b4B078abf2DaDc2055" + ], + "symbol": "USDC" + } + } + }, + "type": "PUBLIC" + }, + "FUSESPARKTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.fusespark.io" + ], + "chainId": 123, + "chainName": "FUSE Spark Testnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "10000000000", + "faucets": [ + "https://get.fusespark.io/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "FUSE Test Token", + "symbol": "FUSE" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.fusespark.io" + ], + "origins": [ + "https://www.fuse.io/" + ], + "priceMechanism": "EIP1559", + "shortName": "FUSESPARKTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "OASISEMERALDTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.emerald.oasis.dev/" + ], + "chainId": 42261, + "chainName": "Oasis Emerald Test Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://faucet.testnet.oasis.dev/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Oasis Test Token", + "symbol": "TEST" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://testnet.emerald.oasis.dev" + ], + "origins": [ + "https://oasisprotocol.org/" + ], + "priceMechanism": "EIP1559", + "shortName": "OASISEMERALDTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "GANACHE8545_1337": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://blockexplorer.x" + ], + "chainId": 1337, + "chainName": "Ganache Test Chain, default local port 8545 and chainid 1337", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Development Test Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "http://127.0.0.1:8545" + ], + "origins": [ + "https://gsthina.medium.com/the-default-chain-id-for-ganache-metamask-is-1337-can-you-try-to-override-it-de5ad1bcb3ab" + ], + "priceMechanism": "LEGACY", + "shortName": "GANACHE8545_1337", + "tokenIndex": { + "tokens": {} + }, + "type": "LOCAL" + }, + "KAVA": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.kava.io/" + ], + "chainId": 2222, + "chainName": "KAVA Evm Mainnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-todo" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "KAVA Token", + "symbol": "KAVA" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://evm2.kava.io", + "https://evm.kava.io", + "https://kava-rpc.gateway.pokt.network", + "https://evm.kava.chainstacklabs.com", + "https://kava-evm.publicnode.com" + ], + "origins": [ + "https://kava.io", + "https://docs.kava.io/docs/ethereum/metamask/" + ], + "priceMechanism": "EIP1559", + "shortName": "KAVA", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "ETHO": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.ethoprotocol.com" + ], + "chainId": 1313114, + "chainName": "ETHO Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "ETHO Native Token", + "symbol": "ETHO" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.ethoprotocol.com" + ], + "origins": [ + "https://chainlist.org/chain/1313114" + ], + "priceMechanism": "LEGACY", + "shortName": "ETHO", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "AURORA": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://aurorascan.dev/", + "https://explorer.mainnet.aurora.dev/", + "https://explorer.aurorachain.io/" + ], + "chainId": 1313161554, + "chainName": "Aurora Mainnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Aurora Token", + "symbol": "AETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://mainnet.aurora.dev", + "https://1rpc.io/aurora", + "https://aurora.drpc.org" + ], + "origins": [ + "https://chainlist.org/chain/1313161554" + ], + "priceMechanism": "EIP1559", + "shortName": "AURORA", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "CRONOSTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://testnet.cronoscan.com/" + ], + "chainId": 338, + "chainName": "Cronos Test Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "2000000000000", + "faucets": [ + "https://cronos.org/faucet" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "CRONOS Test Token", + "symbol": "TCRO" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://evm-t3.cronos.org" + ], + "origins": [ + "https://chainlist.org/chain/338" + ], + "priceMechanism": "EIP1559", + "shortName": "CRONOSTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "OPBNB": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://mainnet.opbnbscan.com" + ], + "chainId": 204, + "chainName": "opBNB Mainnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "1000000000", + "faucets": [ + "https://opbnb-bridge.bnbchain.org/deposit" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "opBNB Gas Token", + "symbol": "BNB" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://opbnb.publicnode.com", + "https://opbnb-mainnet.nodereal.io/v1/64a9df0874fb4a93b9d0a3849de012d3", + "https://opbnb-mainnet-rpc.bnbchain.org", + "https://opbnb-mainnet.nodereal.io/v1/e9a36765eb8a40b9bd12e680a1fd2bc5" + ], + "origins": [ + "https://opbnb.bnbchain.org" + ], + "priceMechanism": "EIP1559", + "shortName": "OPBNB", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "ZORA": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.zora.energy" + ], + "chainId": 7777777, + "chainName": "Zora Mainnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://bridge.zora.energy/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Zora Gas Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.zora.energy" + ], + "origins": [ + "https://zora.energy" + ], + "priceMechanism": "EIP1559", + "shortName": "ZORA", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "RINKEBYTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://rinkeby.etherscan.io" + ], + "chainId": 4, + "chainName": "Rinkeby Test Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "discontinued" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Rinkeby Test Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.ankr.com/eth_rinkeby", + "https://rinkeby.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161\t" + ], + "origins": [ + "https://chainlist.org/chain/4" + ], + "priceMechanism": "EIP1559", + "shortName": "RINKEBYTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "SHIBUYATEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://shibuya.subscan.io" + ], + "chainId": 81, + "chainName": "ASTAR Testnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://portal.astar.network" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "SBY", + "symbol": "SBY" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://evm.shibuya.astar.network" + ], + "origins": [ + "https://chainlist.org/chain/81" + ], + "priceMechanism": "EIP1559", + "shortName": "SHIBUYATEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "ETHEREUM": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://etherscan.io" + ], + "chainId": 1, + "chainName": "Ethereum Main Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [ + "https://rpc.flashbots.net" + ], + "flashbotrelaynodeURLs": [ + "https://relay.flashbots.net" + ], + "nativeCurrency": { + "decimal": 18, + "name": "Ethereum Main Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": { + "BORED_APE": { + "category": "GAMING", + "chain": "ETHEREUM", + "contractAddress": "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", + "description": "Bored Ape NFT", + "linked_tokens": [ + "ETHEREUM:APECOIN" + ], + "mintBlock": 0, + "origins": [ + "https://etherscan.io/address/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", + "https://opensea.io/collection/boredapeyachtclub" + ], + "symbol": "BORED_APE" + }, + "ENS_DOMAIN": { + "category": "NAMESERVICE", + "chain": "ETHEREUM", + "contractAddress": "0x57f1887a8bf19b14fc0df6fd9b2acc9af147ea85", + "description": "Ethereum Name Service Domain NFT", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://etherscan.io/token/0x57f1887a8bf19b14fc0df6fd9b2acc9af147ea85", + "https://opensea.io/collection/ens" + ], + "symbol": "ENS_DOMAIN" + }, + "LUCHADORES": { + "category": "GAMING", + "chain": "ETHEREUM", + "contractAddress": "0x8b4616926705fb61e9c4eeac07cd946a5d4b0760", + "description": "Luchadores game NFT", + "linked_tokens": [ + "POLYGON:LUCHA" + ], + "mintBlock": 0, + "origins": [ + "https://etherscan.io/address/0x8b4616926705fb61e9c4eeac07cd946a5d4b0760", + "https://opensea.io/collection/luchadores-io" + ], + "symbol": "LUCHADORES" + }, + "WWW_LAND": { + "category": "GAMING", + "chain": "ETHEREUM", + "contractAddress": "0xa1d4657e0e6507d5a94d06da93e94dc7c8c44b51", + "description": "World Wide Webb game NFT", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://etherscan.io/address/0xa1d4657e0e6507d5a94d06da93e94dc7c8c44b51", + "https://opensea.io/collection/worldwidewebbland" + ], + "symbol": "WWW_LAND" + }, + "UNSTOPPABLE_DOMAIN": { + "category": "NAMESERVICE", + "chain": "ETHEREUM", + "contractAddress": "0x049aba7510f45ba5b64ea9e658e342f904db358d", + "description": "Unstoppable Domains NFT", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://etherscan.io/token/0x049aba7510f45ba5b64ea9e658e342f904db358d", + "https://opensea.io/collection/unstoppable-domains" + ], + "symbol": "UNSTOPPABLE_DOMAIN" + } + } + }, + "nodeURLs": [ + "https://mainnet.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161", + "https://eth-mainnet.public.blastapi.io", + "https://rpc.ankr.com/eth", + "https://eth-rpc.gateway.pokt.network", + "https://eth-mainnet.gateway.pokt.network/v1/5f3453978e354ab992c4da79", + "https://cloudflare-eth.com", + "https://nodes.mewapi.io/rpc/eth", + "https://rpc.mevblocker.io" + ], + "origins": [ + "https://chainlist.org/chain/1" + ], + "priceMechanism": "EIP1559", + "shortName": "ETHEREUM", + "tokenIndex": { + "tokens": { + "APECOIN": { + "category": "GAMING", + "chain": "ETHEREUM", + "contractAddress": "0x4d224452801aced8b2f0aebe155379bb5d594381", + "decimals": 18, + "name": "Bored Ape game token", + "origins": [ + "https://www.coingecko.com/en/coins/apecoin", + "https://etherscan.io/address/0x4d224452801aced8b2f0aebe155379bb5d594381" + ], + "symbol": "APECOIN" + }, + "CULT": { + "category": "MEME", + "chain": "ETHEREUM", + "contractAddress": "0xf0f9d895aca5c8678f706fb8216fa22957685a13", + "decimals": 18, + "name": "The CULT DAO token", + "origins": [ + "https://etherscan.io/address/0xf0f9d895aca5c8678f706fb8216fa22957685a13", + "https://www.coingecko.com/en/coins/cult-dao" + ], + "symbol": "CULT" + }, + "VIDYA": { + "category": "GAMING", + "chain": "ETHEREUM", + "contractAddress": "0x3d3d35bb9bec23b06ca00fe472b50e7a4c692c30", + "decimals": 18, + "name": "VIDYA token", + "origins": [ + "https://etherscan.io/address/0x3d3d35bb9bec23b06ca00fe472b50e7a4c692c30", + "https://www.coingecko.com/en/coins/vidya" + ], + "symbol": "VIDYA" + }, + "TRAC": { + "category": "SUPPLYCHAIN", + "chain": "ETHEREUM", + "contractAddress": "0xaa7a9ca87d3694b5755f213b5d04094b8d0f0a6f", + "decimals": 18, + "name": "OriginTrail token", + "origins": [ + "https://etherscan.io/address/0xaa7a9ca87d3694b5755f213b5d04094b8d0f0a6f", + "https://www.coingecko.com/en/coins/origintrail" + ], + "symbol": "TRAC" + }, + "USDT": { + "category": "STABLECOIN", + "chain": "ETHEREUM", + "contractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7", + "decimals": 6, + "name": "Tether stablecoin token", + "origins": [ + "https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7", + "https://www.coingecko.com/en/coins/tether" + ], + "symbol": "USDT" + }, + "SERUM": { + "category": "DEFI", + "chain": "ETHEREUM", + "contractAddress": "0x476c5e26a75bd202a9683ffd34359c0cc15be0ff", + "decimals": 18, + "name": "Serum token", + "origins": [ + "https://etherscan.io/address/0x476c5e26a75bd202a9683ffd34359c0cc15be0ff", + "https://www.coingecko.com/en/coins/serum" + ], + "symbol": "SERUM" + }, + "DINU": { + "category": "MEME", + "chain": "ETHEREUM", + "contractAddress": "0xbb1ee07d6c7baeb702949904080eb61f5d5e7732", + "decimals": 18, + "name": "The Dogey-Inu token", + "origins": [ + "https://etherscan.io/address/0xbb1ee07d6c7baeb702949904080eb61f5d5e7732", + "https://www.coingecko.com/en/coins/dogey-inu" + ], + "symbol": "DINU" + }, + "DAI": { + "category": "STABLECOIN", + "chain": "ETHEREUM", + "contractAddress": "0x6b175474e89094c44da98b954eedeac495271d0f", + "decimals": 18, + "name": "DAI stablecoin token", + "origins": [ + "https://etherscan.io/address/0x6b175474e89094c44da98b954eedeac495271d0f", + "https://www.coingecko.com/en/coins/dai" + ], + "symbol": "DAI" + }, + "DOBE": { + "category": "MEME", + "chain": "ETHEREUM", + "contractAddress": "0xe7ab45162f5979f09b0bda1cc7dfc97c270ea3d5", + "decimals": 18, + "name": "The Dobermann token", + "origins": [ + "https://etherscan.io/address/0xe7ab45162f5979f09b0bda1cc7dfc97c270ea3d5", + "https://www.coingecko.com/en/coins/dobermann" + ], + "symbol": "DOBE" + }, + "DOJO": { + "category": "MEME", + "chain": "ETHEREUM", + "contractAddress": "0x180dae91d6d56235453a892d2e56a3e40ba81df8", + "decimals": 18, + "name": "The DOJO token", + "origins": [ + "https://etherscan.io/address/0x180dae91d6d56235453a892d2e56a3e40ba81df8", + "https://www.coingecko.com/en/coins/dojo" + ], + "symbol": "DOJO" + }, + "FWB": { + "category": "SOCIAL", + "chain": "ETHEREUM", + "contractAddress": "0x35bd01fc9d6d5d81ca9e055db88dc49aa2c699a8", + "decimals": 18, + "name": "Friends With Benefits token", + "origins": [ + "https://etherscan.io/address/0x35bd01fc9d6d5d81ca9e055db88dc49aa2c699a8", + "https://www.coingecko.com/en/coins/friends-with-benefits-pro" + ], + "symbol": "FWB" + }, + "JINDOGE": { + "category": "MEME", + "chain": "ETHEREUM", + "contractAddress": "0x3f4cd830543db25254ec0f05eac058d4d6e86166", + "decimals": 18, + "name": "The Jindoge token", + "origins": [ + "https://etherscan.io/address/0x3f4cd830543db25254ec0f05eac058d4d6e86166", + "https://www.coingecko.com/en/coins/jindoge" + ], + "symbol": "JINDOGE" + }, + "JSHIBA": { + "category": "MEME", + "chain": "ETHEREUM", + "contractAddress": "0x1426cc6d52d1b14e2b3b1cb04d57ea42b39c4c7c", + "decimals": 18, + "name": "The Jomon Shiba token", + "origins": [ + "https://etherscan.io/address/0x1426cc6d52d1b14e2b3b1cb04d57ea42b39c4c7c", + "https://www.coingecko.com/en/coins/jomon-shiba" + ], + "symbol": "JSHIBA" + }, + "NB": { + "category": "MEME", + "chain": "ETHEREUM", + "contractAddress": "0x20be82943e8d9c682580e11d424ec15db95b4a24", + "decimals": 18, + "name": "The No Bull token", + "origins": [ + "https://etherscan.io/address/0x20be82943e8d9c682580e11d424ec15db95b4a24", + "https://www.coingecko.com/en/coins/no-bull" + ], + "symbol": "NB" + }, + "SHUSHKY": { + "category": "MEME", + "chain": "ETHEREUM", + "contractAddress": "0x236d53148f83706c3d670064809577385f923a75", + "decimals": 18, + "name": "The Siberian Husky token", + "origins": [ + "https://etherscan.io/address/0x236d53148f83706c3d670064809577385f923a75", + "https://www.coingecko.com/en/coins/siberian-husky" + ], + "symbol": "SHUSHKY" + }, + "TEST": { + "category": "TEST", + "chain": "ETHEREUM", + "contractAddress": "0x2b591e99afe9f32eaa6214f7b7629768c40eeb39", + "decimals": 18, + "name": "TEST token", + "origins": [ + "https://etherscan.io/token/0xMOJO" + ], + "symbol": "TEST" + }, + "SOS": { + "category": "NFT", + "chain": "ETHEREUM", + "contractAddress": "0x3b484b82567a09e2588a13d54d032153f0c0aee0", + "decimals": 18, + "name": "The OpenDAO SOS token", + "origins": [ + "https://etherscan.io/address/0x3b484b82567a09e2588a13d54d032153f0c0aee0", + "https://www.coingecko.com/en/coins/opendao" + ], + "symbol": "SOS" + }, + "UNIDX": { + "category": "DEFI", + "chain": "ETHEREUM", + "contractAddress": "0x95b3497bbcccc46a8f45f5cf54b0878b39f8d96c", + "decimals": 18, + "name": "UniDex token", + "origins": [ + "https://etherscan.io/address/0x95b3497bbcccc46a8f45f5cf54b0878b39f8d96c", + "https://www.coingecko.com/en/coins/unidex" + ], + "symbol": "UNIDX" + }, + "XOR": { + "category": "UNKNOWN", + "chain": "ETHEREUM", + "contractAddress": "0x40fd72257597aa14c7231a7b1aaa29fce868f677", + "decimals": 18, + "name": "The SORA token", + "origins": [ + "https://etherscan.io/address/0x40fd72257597aa14c7231a7b1aaa29fce868f677", + "https://www.coingecko.com/en/coins/sora" + ], + "symbol": "XOR" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "ETHEREUM", + "contractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "decimals": 6, + "name": "USDC stablecoin token", + "origins": [ + "https://etherscan.io/address/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "https://www.coingecko.com/en/coins/usd-coin" + ], + "symbol": "USDC" + } + } + }, + "type": "PUBLIC" + }, + "BOBABNBTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://blockexplorer.testnet.bnb.boba.network" + ], + "chainId": 9728, + "chainName": "Boba BNB Test Token", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://gateway.testnet.bnb.boba.network/wallet" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Boba BNB Test Token", + "symbol": "BOBA" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://testnet.bnb.boba.network" + ], + "origins": [ + "https://chainlist.org/chain/9728" + ], + "priceMechanism": "LEGACY", + "shortName": "BOBABNBTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "METISSTARDUSTTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://goerli.explorer.metisdevops.link" + ], + "chainId": 599, + "chainName": "Metis Stardust Testnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://goerli.faucet.metisdevops.link/", + "bridge assets from goerli https://bridge.metis.io/home" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Metis Goerli Test Token", + "symbol": "METIS" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://goerli.gateway.metisdevops.link" + ], + "origins": [ + "https://chainlist.org/chain/599" + ], + "priceMechanism": "LEGACY", + "shortName": "METISSTARDUSTTEST", + "tokenIndex": { + "tokens": { + "WETH": { + "category": "DEFI", + "chain": "METISSTARDUSTTEST", + "contractAddress": "0x420000000000000000000000000000000000000A", + "decimals": 18, + "name": "Wrapped ETH token", + "origins": [ + "https://bscscan.com/address/0x420000000000000000000000000000000000000A", + "https://www.coingecko.com/en/coins/weth" + ], + "symbol": "WETH" + } + } + }, + "type": "PUBLIC" + }, + "SHARDEUMLIBERTY1xTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.liberty10.shardeum.org" + ], + "chainId": 8080, + "chainName": "Shardeum Liberty 1.5", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://docs.shardeum.org/faucet/claim" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Shardeum Native Token", + "symbol": "SHM" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://liberty10.shardeum.org" + ], + "origins": [ + "https://docs.shardeum.org/wallets/MetaMask/add-shardeum-network" + ], + "priceMechanism": "LEGACY", + "shortName": "SHARDEUMLIBERTY1xTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "PULSECHAIN": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://scan.pulsechain.com" + ], + "chainId": 369, + "chainName": "PulseChain", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-todo" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "PulseChain Token", + "symbol": "PLS" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.pulsechain.com", + "https://rpc-pulsechain.g4mm4.io", + "https://pulsechain.publicnode.com" + ], + "origins": [ + "https://pulsechain.com/" + ], + "priceMechanism": "EIP1559", + "shortName": "PULSECHAIN", + "tokenIndex": { + "tokens": { + "PLSX": { + "category": "DEFI", + "chain": "PULSECHAIN", + "contractAddress": "0x95B303987A60C71504D99Aa1b13B4DA07b0790ab", + "decimals": 18, + "name": "Pulsechain PLSX token", + "origins": [ + "https://scan.pulsechain.com/address/0x95B303987A60C71504D99Aa1b13B4DA07b0790ab" + ], + "symbol": "PLSX" + } + } + }, + "type": "PUBLIC" + }, + "MILKOMEDAC1": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer-mainnet-cardano-evm.c1.milkomeda.com/" + ], + "chainId": 2001, + "chainName": "Milkomeda Cardano mainnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "milkADA", + "symbol": "mADA" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": { + "PAIMA_VOLCANEERS": { + "category": "GAMING", + "chain": "MILKOMEDAC1", + "contractAddress": "0xa335d662BB47409e04F06dC7Fd03cEc854530172", + "description": "Paima Volcaneers (PV)", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://explorer-mainnet-cardano-evm.c1.milkomeda.com/address/0xa335d662BB47409e04F06dC7Fd03cEc854530172" + ], + "symbol": "PAIMA_VOLCANEERS" + } + } + }, + "nodeURLs": [ + "https://rpc-mainnet-cardano-evm.c1.milkomeda.com" + ], + "origins": [ + "https://chainlist.org/chain/2001", + "https://app.blueshift.fi/#/bridge" + ], + "priceMechanism": "EIP1559", + "shortName": "MILKOMEDAC1", + "tokenIndex": { + "tokens": { + "BLUES": { + "category": "DEFI", + "chain": "MILKOMEDAC1", + "contractAddress": "0x8c008BBA2Dd56b99f4A6aB276bE3a478cB075F0C", + "decimals": 18, + "name": "Blueshift token", + "origins": [ + "https://explorer-mainnet-cardano-evm.c1.milkomeda.com/address/0x8c008BBA2Dd56b99f4A6aB276bE3a478cB075F0C" + ], + "symbol": "BLUES" + }, + "BLUESHIFT_mADA_BLUES_LP": { + "category": "LIQUIDITY_PROVIDER", + "chain": "MILKOMEDAC1", + "contractAddress": "0x4a2360fD03eD50C9496cbEB4FD3e1776FA90F04c", + "decimals": 18, + "name": "Blueshift LP 006 (mADA/BLUES) token", + "origins": [ + "https://explorer-mainnet-cardano-evm.c1.milkomeda.com/address/0x4a2360fD03eD50C9496cbEB4FD3e1776FA90F04c" + ], + "symbol": "BLUESHIFT_mADA_BLUES_LP" + }, + "WADA": { + "category": "DEFI", + "chain": "MILKOMEDAC1", + "contractAddress": "0xAE83571000aF4499798d1e3b0fA0070EB3A3E3F9", + "decimals": 18, + "name": "Wrapped ADA token", + "origins": [ + "https://explorer-mainnet-cardano-evm.c1.milkomeda.com/address/0xAE83571000aF4499798d1e3b0fA0070EB3A3E3F9" + ], + "symbol": "WADA" + } + } + }, + "type": "PUBLIC" + }, + "BORACHAIN": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://scope.boraportal.com/" + ], + "chainId": 77001, + "chainName": "Bora Chain, gaming side-chain of KLAYTN", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "BORAChain Native Token", + "symbol": "BGAS" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://public-node.api.boraportal.io/bora/mainnet" + ], + "origins": [ + "https://medium.com/@DAO_FE/1-add-rpc-network-name-borachain-mainnet-network-url-https-public-node-api-boraportal-io-b-59f422588926" + ], + "priceMechanism": "LEGACY", + "shortName": "BORACHAIN", + "tokenIndex": { + "tokens": { + "tBORA": { + "category": "GASCURRENCY", + "chain": "BORACHAIN", + "contractAddress": "0x797115bcdbD85DC865222724eD67d473CE168962", + "decimals": 18, + "name": "tBORA token", + "origins": [ + "https://scope.boraportal.com/token/0x797115bcdbd85dc865222724ed67d473ce168962" + ], + "symbol": "tBORA" + }, + "TEST": { + "category": "TEST", + "chain": "KLAYTN", + "contractAddress": "0x7769cf946c011BB3A22d20ba6bF7f0bC419c722f", + "decimals": 18, + "name": "TEST token", + "origins": [ + "https://scope.boraportal.com/token/0x7769cf946c011BB3A22d20ba6bF7f0bC419c722f" + ], + "symbol": "TEST" + }, + "BSLT": { + "category": "GAMING", + "chain": "BORACHAIN", + "contractAddress": "0xcfdbf6a1f765c295d8d557e841c1304019318525", + "decimals": 18, + "name": "ArcheWorld Blue Salt game token", + "origins": [ + "https://scope.boraportal.com/address/0xcFdbf6a1f765C295d8D557E841C1304019318525" + ], + "symbol": "BSLT" + } + } + }, + "type": "PUBLIC" + }, + "OPTIMISMGOERLITEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://optimistic.etherscan.io/" + ], + "chainId": 420, + "chainName": "Optimism Goerli Testnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://goerli.hop.exchange/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Optimism Gas Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://endpoints.omniatech.io/v1/op/goerli/public", + "https://opt-goerli.g.alchemy.com/v2/demo", + "https://goerli.optimism.io", + "https://optimism-goerli.public.blastapi.io" + ], + "origins": [ + "https://www.optimism.io/" + ], + "priceMechanism": "EIP1559", + "shortName": "OPTIMISMGOERLITEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "BOBA": { + "archivenodeURLs": [ + "https://blockexplorer.boba.network", + "https://mainnet.boba.network\t", + "https://boba-mainnet.gateway.pokt.network/v1/lb/623ad21b20354900396fed7f\t" + ], + "blockexplorerURLs": [], + "chainId": 288, + "chainName": "Boba Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://gateway.testnet.bnb.boba.network/wallet" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Boba Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://lightning-replica.boba.network", + "https://mainnet.boba.network" + ], + "origins": [ + "https://chainlist.org/chain/288" + ], + "priceMechanism": "LEGACY", + "shortName": "BOBA", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "MUMBAITEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://mumbai.polygonscan.com" + ], + "chainId": 80001, + "chainName": "Polygon Test Network", + "enforcedMinGasPriceInWEI": "31000000000", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://faucet.polygon.technology/", + "https://mumbaifaucet.com/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Polygon Test Token", + "symbol": "MATIC" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc-mumbai.maticvigil.com", + "https://rpc.ankr.com/polygon_mumbai", + "https://rpc-mumbai.maticvigil.com", + "https://polygon-testnet.public.blastapi.io" + ], + "origins": [ + "https://chainlist.org/chain/80001" + ], + "priceMechanism": "EIP1559", + "shortName": "MUMBAITEST", + "tokenIndex": { + "tokens": { + "RICOCHET_fUSDCx": { + "category": "DEFI", + "chain": "MUMBAITEST", + "contractAddress": "0x42bb40bF79730451B11f6De1CbA222F17b87Afd7", + "decimals": 18, + "name": "Ricochet fUSDC token, fUSDCx", + "origins": [ + "https://mumbai.polygonscan.com/token/0x42bb40bF79730451B11f6De1CbA222F17b87Afd7", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "RICOCHET_fUSDCx" + }, + "TST": { + "category": "TEST", + "chain": "MUMBAITEST", + "contractAddress": "0x2d7882bedcbfddce29ba99965dd3cdf7fcb10a1e", + "decimals": 18, + "name": "Official Mumbai ERC-20 TST token", + "origins": [ + "https://mumbai.polygonscan.com/address/0x2d7882bedcbfddce29ba99965dd3cdf7fcb10a1e" + ], + "symbol": "TST" + }, + "TEST": { + "category": "TEST", + "chain": "MUMBAITEST", + "contractAddress": "0xeedb61304686f4b544baa1cb19f87c30bb8d38b9", + "decimals": 18, + "name": "TEST token", + "origins": [ + "https://mumbai.polygonscan.com/token/0xMOJO" + ], + "symbol": "TEST" + }, + "fUSDC": { + "category": "DEFI", + "chain": "MUMBAITEST", + "contractAddress": "0xbe49ac1EadAc65dccf204D4Df81d650B50122aB2", + "decimals": 18, + "name": "Flux fUSDC token", + "origins": [ + "https://mumbai.polygonscan.com/token/0xbe49ac1EadAc65dccf204D4Df81d650B50122aB2", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "fUSDC" + }, + "RICOCHET_fTUSDx": { + "category": "DEFI", + "chain": "MUMBAITEST", + "contractAddress": "0x918E0d5C96cAC79674E2D38066651212be3C9C48", + "decimals": 18, + "name": "Ricochet fTUSD token, fTUSDx", + "origins": [ + "https://mumbai.polygonscan.com/token/0x918E0d5C96cAC79674E2D38066651212be3C9C48", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "RICOCHET_fTUSDx" + }, + "fDAI": { + "category": "STABLECOIN", + "chain": "MUMBAITEST", + "contractAddress": "0x15F0Ca26781C3852f8166eD2ebce5D18265cceb7", + "decimals": 18, + "name": "Flux fDAI stablecoin", + "origins": [ + "https://mumbai.polygonscan.com/token/0x15F0Ca26781C3852f8166eD2ebce5D18265cceb7", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "fDAI" + }, + "LINK": { + "category": "DEFI", + "chain": "MUMBAITEST", + "contractAddress": "0x326C977E6efc84E512bB9C30f76E30c160eD06FB", + "decimals": 18, + "name": "LINK token", + "origins": [ + "https://mumbai.polygonscan.com/token/0x326c977e6efc84e512bb9c30f76e30c160ed06fb", + "https://www.coingecko.com/en/coins/chainlink" + ], + "symbol": "LINK" + }, + "fTUSD": { + "category": "STABLECOIN", + "chain": "MUMBAITEST", + "contractAddress": "0xA794C9ee519FD31BbCE643e8D8138f735E97D1DB", + "decimals": 18, + "name": "Flux fTUSD stablecoin", + "origins": [ + "https://mumbai.polygonscan.com/token/0xA794C9ee519FD31BbCE643e8D8138f735E97D1DB", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "fTUSD" + }, + "RICOCHET_fDAIx": { + "category": "DEFI", + "chain": "MUMBAITEST", + "contractAddress": "0x15F0Ca26781C3852f8166eD2ebce5D18265cceb7", + "decimals": 18, + "name": "Ricochet fDAI token, fDAIx", + "origins": [ + "https://mumbai.polygonscan.com/token/0x15F0Ca26781C3852f8166eD2ebce5D18265cceb7", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "RICOCHET_fDAIx" + }, + "RICOCHET_MATICx": { + "category": "DEFI", + "chain": "MUMBAITEST", + "contractAddress": "0x96B82B65ACF7072eFEb00502F45757F254c2a0D4", + "decimals": 18, + "name": "Ricochet MATIC token, MATICx", + "origins": [ + "https://mumbai.polygonscan.com/token/0x96B82B65ACF7072eFEb00502F45757F254c2a0D4", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "RICOCHET_MATICx" + }, + "DERC20": { + "category": "TEST", + "chain": "MUMBAITEST", + "contractAddress": "0x2d7882bedcbfddce29ba99965dd3cdf7fcb10a1e", + "decimals": 18, + "name": "Official Mumbai ERC-20 Dummy ERC20 token", + "origins": [ + "https://mumbai.polygonscan.com/token/0xfe4f5145f6e09952a5ba9e956ed0c25e3fa4c7f1" + ], + "symbol": "DERC20" + } + } + }, + "type": "PUBLIC" + }, + "CANTO": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://tuber.build/" + ], + "chainId": 7700, + "chainName": "Canto Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-todo" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Canto Token", + "symbol": "CANTO" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://canto.gravitychain.io", + "https://canto.slingshot.finance/", + "https://canto.evm.chandrastation.com/", + "https://jsonrpc.canto.nodestake.top" + ], + "origins": [ + "https://docs.canto.io/user-guides/connecting-to-canto" + ], + "priceMechanism": "EIP1559", + "shortName": "CANTO", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "SEPOLIATEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://sepolia.etherscan.io/" + ], + "chainId": 11155111, + "chainName": "Sepolia Test Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://faucet.sepolia.dev/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Sepolia Test Token", + "symbol": "SEP" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.sepolia.org", + "https://rpc2.sepolia.org", + "https://ethereum-sepolia.blockpi.network/v1/rpc/public", + "https://eth-sepolia.public.blastapi.io", + "https://gateway.tenderly.co/public/sepolia", + "https://eth-sepolia.public.blastapi.io", + "https://endpoints.omniatech.io/v1/eth/sepolia/public", + "https://eth-sepolia-public.unifra.io", + "https://rpc.notadegen.com/sepolia" + ], + "origins": [ + "https://chainlist.org/chain/11155111" + ], + "priceMechanism": "EIP1559", + "shortName": "SEPOLIATEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "ZKEVMTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://testnet-zkevm.polygonscan.com" + ], + "chainId": 1442, + "chainName": "Polygon ZKEVM Test Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://wallet.polygon.technology/zkEVM-Bridge/bridge" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "ETH Test Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.public.zkevm-test.net" + ], + "origins": [ + "https://wiki.polygon.technology/docs/zkEVM/develop" + ], + "priceMechanism": "EIP1559", + "shortName": "ZKEVMTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "SHARDEUMSPHINX1xTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer-sphinx.shardeum.org" + ], + "chainId": 8082, + "chainName": "Shardeum Sphinx 1.x", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://docs.shardeum.org/faucet/claim" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Shardeum Native Token", + "symbol": "SHM" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://sphinx.shardeum.org" + ], + "origins": [ + "https://docs.shardeum.org/wallets/MetaMask/add-shardeum-network" + ], + "priceMechanism": "LEGACY", + "shortName": "SHARDEUMSPHINX1xTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "TENETTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://testnet.tenetscan.io" + ], + "chainId": 155, + "chainName": "Tenet Testnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://faucet.testnet.tenet.org/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "TENET Gas Token", + "symbol": "TENET" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.testnet.tenet.org" + ], + "origins": [ + "https://tenet.org" + ], + "priceMechanism": "EIP1559", + "shortName": "TENETTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "LUKSOTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.execution.testnet.lukso.network" + ], + "chainId": 4201, + "chainName": "LUKSO Testnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://faucet.testnet.lukso.network/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "LUKSO Test Token", + "symbol": "LYXt" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.testnet.lukso.network" + ], + "origins": [ + "https://lukso.network/" + ], + "priceMechanism": "EIP1559", + "shortName": "LUKSOTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "OPTIMISM": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://optimistic.etherscan.io" + ], + "chainId": 10, + "chainName": "Optimism Mainnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Optimism Gas Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://mainnet.optimism.io" + ], + "origins": [ + "https://www.optimism.io/", + "https://chainid.link/?network=optimism" + ], + "priceMechanism": "EIP1559", + "shortName": "OPTIMISM", + "tokenIndex": { + "tokens": { + "SDS": { + "category": "DEFI", + "chain": "OPTIMISM", + "contractAddress": "0x45c55bf488d3cb8640f12f63cbedc027e8261e79", + "decimals": 18, + "name": "Synthetix Debt Shares token", + "origins": [ + "https://optimistic.etherscan.io/token/0x45c55bf488d3cb8640f12f63cbedc027e8261e79" + ], + "symbol": "SDS" + }, + "SUSD": { + "category": "STABLECOIN", + "chain": "OPTIMISM", + "contractAddress": "0x8c6f28f2f1a3c87f0f938b96d27520d9751ec8d9", + "decimals": 18, + "name": "sUSD stablecoin token", + "origins": [ + "https://optimistic.etherscan.io/token/0x8c6f28f2f1a3c87f0f938b96d27520d9751ec8d9" + ], + "symbol": "SUSD" + }, + "SNX": { + "category": "DEFI", + "chain": "OPTIMISM", + "contractAddress": "0x8700daec35af8ff88c16bdf0418774cb3d7599b4", + "decimals": 18, + "name": "SNX token", + "origins": [ + "https://optimistic.etherscan.io/token/0x8700daec35af8ff88c16bdf0418774cb3d7599b4" + ], + "symbol": "SNX" + } + } + }, + "type": "PUBLIC" + }, + "SYSCOIN": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.syscoin.org" + ], + "chainId": 57, + "chainName": "SYSCoin Mainnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://faucet.syscoin.org/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "SYS", + "symbol": "SYS" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.syscoin.org", + "https://syscoin-evm.publicnode.com", + "https://rpc.ankr.com/syscoin", + "https://syscoin.public-rpc.com" + ], + "origins": [ + "https://chainlist.org/chain/57", + "https://syscoin.medium.com/setting-up-metamask-for-syscoin-nevm-ea0012d6d1c8", + "https://www.coingecko.com/en/coins/syscoin", + "https://bridge.syscoin.org" + ], + "priceMechanism": "EIP1559", + "shortName": "SYSCOIN", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "KARURA": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://karura.network" + ], + "chainId": 686, + "chainName": "KARURA Mainnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "KARURA Gas Token", + "symbol": "KAR" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.evm.karura.network", + "https://eth-rpc-karura.aca-api.network", + "https://eth-rpc-karura.aca-staging.network" + ], + "origins": [ + "https://acala.network/karura" + ], + "priceMechanism": "EIP1559", + "shortName": "KARURA", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "ARBITRUMONE": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://arb1.arbitrum.io/rpc" + ], + "chainId": 42161, + "chainName": "Arbitrum ONE mainnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "ETH", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": { + "TREASURETAG": { + "category": "GAMING", + "chain": "ARBITRUMONE", + "contractAddress": "0xe50abe4756809b51b0041bb5ab12ec4c5c67af47", + "description": "MAGIC Treasuretag NFT", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://arbiscan.io/token/0xe50abe4756809b51b0041bb5ab12ec4c5c67af47", + "https://app.treasure.lol/treasuretag" + ], + "symbol": "TREASURETAG" + } + } + }, + "nodeURLs": [ + "https://arb1.arbitrum.io/rpc", + "https://arbitrum.llamarpc.com", + "https://arbitrum.drpc.org", + "https://arbitrum-one.publicnode.com", + "https://arbitrum-one.public.blastapi.io", + "https://rpc.arb1.arbitrum.gateway.fm", + "https://1rpc.io/arb", + "https://rpc.ankr.com/arbitrum" + ], + "origins": [ + "https://chainlist.org/chain/42161" + ], + "priceMechanism": "EIP1559", + "shortName": "ARBITRUMONE", + "tokenIndex": { + "tokens": { + "BAL_MAGICUSDC_LP": { + "category": "LIQUIDITY_PROVIDER", + "chain": "ARBITRUMONE", + "contractAddress": "0xb3028ca124b80cfe6e9ca57b70ef2f0ccc41ebd4", + "decimals": 18, + "name": "Balancer 50/50 MAGIC/USDC LP token", + "origins": [ + "https://arbiscan.io/token/0xb3028ca124b80cfe6e9ca57b70ef2f0ccc41ebd4" + ], + "symbol": "BAL_MAGICUSDC_LP" + }, + "USDT": { + "category": "STABLECOIN", + "chain": "ARBITRUMONE", + "contractAddress": "0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9", + "decimals": 6, + "name": "Tether stablecoin token", + "origins": [ + "https://arbiscan.io/address/0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9", + "https://www.coingecko.com/en/coins/tether" + ], + "symbol": "USDT" + }, + "gDAI": { + "category": "STABLECOIN", + "chain": "ARBITRUMONE", + "contractAddress": "0xd85E038593d7A098614721EaE955EC2022B9B91B", + "decimals": 18, + "name": "GAINS Network DAI token", + "origins": [ + "https://arbiscan.io/address/0xd85e038593d7a098614721eae955ec2022b9b91b" + ], + "symbol": "gDAI" + }, + "DMT": { + "category": "GAMING", + "chain": "ARBITRUMONE", + "contractAddress": "0x8b0e6f19ee57089f7649a455d89d7bc6314d04e8", + "decimals": 18, + "name": "DMT gaming token", + "origins": [ + "https://arbiscan.io/token/0x8b0e6f19ee57089f7649a455d89d7bc6314d04e8", + "https://www.coingecko.com/en/coins/dream-machine-token" + ], + "symbol": "DMT" + }, + "DAI": { + "category": "STABLECOIN", + "chain": "ARBITRUMONE", + "contractAddress": "0xda10009cbd5d07dd0cecc66161fc93d7c9000da1", + "decimals": 18, + "name": "DAI stablecoin token", + "origins": [ + "https://arbiscan.io/address/0xda10009cbd5d07dd0cecc66161fc93d7c9000da1", + "https://www.coingecko.com/en/coins/dai" + ], + "symbol": "DAI" + }, + "BAL": { + "category": "DEFI", + "chain": "ARBITRUMONE", + "contractAddress": "0x040d1edc9569d4bab2d15287dc5a4f10f56a56b8", + "decimals": 18, + "name": "Balancer DEFI GOV token", + "origins": [ + "https://arbiscan.io/token/0x040d1edc9569d4bab2d15287dc5a4f10f56a56b8" + ], + "symbol": "BAL" + }, + "GNS": { + "category": "DEFI", + "chain": "ARBITRUMONE", + "contractAddress": "0x18c11fd286c5ec11c3b683caa813b77f5163a122", + "decimals": 18, + "name": "Gains token", + "origins": [ + "https://arbiscan.io/address/0x18c11fd286c5ec11c3b683caa813b77f5163a122", + "https://www.coingecko.com/en/coins/gains-network" + ], + "symbol": "GNS" + }, + "rETH": { + "category": "DEFI", + "chain": "ARBITRUMONE", + "contractAddress": "0xEC70Dcb4A1EFa46b8F2D97C310C9c4790ba5ffA8", + "decimals": 18, + "name": "Rocketpool ETH token", + "origins": [ + "https://arbiscan.io/address/0xec70dcb4a1efa46b8f2d97c310c9c4790ba5ffa8", + "https://rocketpool.net/" + ], + "symbol": "rETH" + }, + "GMX": { + "category": "DEFI", + "chain": "ARBITRUMONE", + "contractAddress": "0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a", + "decimals": 18, + "name": "GMX token", + "origins": [ + "https://arbiscan.io/address/0xfc5a1a6eb076a2c7ad06ed22c90d7e710e35ad0a", + "https://www.coingecko.com/en/coins/gmx" + ], + "symbol": "GMX" + }, + "MAGIC": { + "category": "GAMING", + "chain": "ARBITRUMONE", + "contractAddress": "0x539bde0d7dbd336b79148aa742883198bbf60342", + "decimals": 18, + "name": "MAGIC gaming token", + "origins": [ + "https://arbiscan.io/address/0x539bde0d7dbd336b79148aa742883198bbf60342", + "https://www.coingecko.com/en/coins/magic" + ], + "symbol": "MAGIC" + }, + "ARBITRUM": { + "category": "GOVERNANCE", + "chain": "ARBITRUMONE", + "contractAddress": "0x912ce59144191c1204e64559fe8253a0e49e6548", + "decimals": 18, + "name": "Arbitrum GOV token", + "origins": [ + "https://arbiscan.io/address/0x912ce59144191c1204e64559fe8253a0e49e6548" + ], + "symbol": "ARBITRUM" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "ARBITRUMONE", + "contractAddress": "0xaf88d065e77c8cc2239327c5edb3a432268e5831", + "decimals": 6, + "name": "USDC stablecoin token", + "origins": [ + "https://arbiscan.io/address/0xaf88d065e77c8cc2239327c5edb3a432268e5831", + "https://www.coingecko.com/en/coins/usd-coin" + ], + "symbol": "USDC" + }, + "USDCe": { + "category": "STABLECOIN", + "chain": "ARBITRUMONE", + "contractAddress": "0xff970a61a04b1ca14834a43f5de4533ebddb5cc8", + "decimals": 6, + "name": "Bridged USDC stablecoin token (USDC.e)", + "origins": [ + "https://arbiscan.io/address/0xff970a61a04b1ca14834a43f5de4533ebddb5cc8", + "https://www.coingecko.com/en/coins/usd-coin-ethereum-bridged" + ], + "symbol": "USDCe" + } + } + }, + "type": "PUBLIC" + }, + "KARDIACHAIN": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.kardiachain.io/" + ], + "chainId": 24, + "chainName": "KARURA Mainnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "KARDIACHAIN Gas Token", + "symbol": "KAI" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.kardiachain.io" + ], + "origins": [ + "https://kardiachain.io/" + ], + "priceMechanism": "EIP1559", + "shortName": "KARDIACHAIN", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "CANTOTEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://testnet-explorer.canto.neobase.one/" + ], + "chainId": 740, + "chainName": "Canto Test Network", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://discord.com/invite/canto, social-faucet channel" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Canto Test Token", + "symbol": "CANTO" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://eth.plexnode.wtf" + ], + "origins": [ + "https://docs.canto.io/user-guides/connecting-to-canto", + "https://chainlist.org/chain/740" + ], + "priceMechanism": "EIP1559", + "shortName": "CANTOTEST", + "tokenIndex": { + "tokens": {} + }, + "type": "BORKED" + }, + "MANTLETEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.testnet.mantle.xyz" + ], + "chainId": 5001, + "chainName": "Mantle Testnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "1000000000", + "faucets": [ + "https://faucet.testnet.mantle.xyz", + "https://bridge.testnet.mantle.xyz", + "https://goerli.etherscan.io/address/0xc1dc2d65a2243c22344e725677a3e3bebd26e604#writeProxyContract mint()" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Mantle Gas Token", + "symbol": "MNT" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.testnet.mantle.xyz" + ], + "origins": [ + "https://www.mantle.xyz/" + ], + "priceMechanism": "EIP1559", + "shortName": "MANTLETEST", + "tokenIndex": { + "tokens": { + "USDT": { + "category": "STABLECOIN", + "chain": "MANTLETEST", + "contractAddress": "0x093790D873e87B45Cee9CA70B12056C705861ecD", + "decimals": 6, + "name": "Tether stable coin", + "origins": [ + "https://explorer.testnet.mantle.xyz/token/0x093790D873e87B45Cee9CA70B12056C705861ecD" + ], + "symbol": "USDT" + }, + "WETH": { + "category": "DEFI", + "chain": "MANTLETEST", + "contractAddress": "0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111", + "decimals": 18, + "name": "Wrapped ETH token", + "origins": [ + "https://explorer.testnet.mantle.xyz/token/0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111" + ], + "symbol": "WETH" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "MANTLETEST", + "contractAddress": "0xbAF72402f98f16e77638Ce5FCC5689CD1627E8ff", + "decimals": 6, + "name": "USDC stable coin", + "origins": [ + "https://explorer.testnet.mantle.xyz/token/0xbAF72402f98f16e77638Ce5FCC5689CD1627E8ff/" + ], + "symbol": "USDC" + } + } + }, + "type": "PUBLIC" + }, + "ASTAR": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://astar.subscan.io", + "https://blockscout.com/astar" + ], + "chainId": 592, + "chainName": "ASTAR Mainnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://portal.astar.network" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "ASTR", + "symbol": "ASTR" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://astar.public.blastapi.io", + "https://evm.astar.network", + "https://1rpc.io/astr", + "https://astar-rpc.dwellir.com" + ], + "origins": [ + "https://chainlist.org/chain/592" + ], + "priceMechanism": "EIP1559", + "shortName": "ASTAR", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "CORE": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://scan.coredao.org" + ], + "chainId": 1116, + "chainName": "Core DAO Mainnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://bridge.coredao.org/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Core Gas Token", + "symbol": "CORE" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://rpc.coredao.org", + "https://rpc-core.icecreamswap.com" + ], + "origins": [ + "https://coredao.org/" + ], + "priceMechanism": "EIP1559", + "shortName": "CORE", + "tokenIndex": { + "tokens": { + "USDT": { + "category": "STABLECOIN", + "chain": "CORE", + "contractAddress": "0x900101d06a7426441ae63e9ab3b9b0f63be145f1", + "decimals": 6, + "name": "Tether stable token", + "origins": [ + "https://scan.coredao.org/token/0x900101d06a7426441ae63e9ab3b9b0f63be145f1" + ], + "symbol": "USDT" + } + } + }, + "type": "PUBLIC" + }, + "BASETEST": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://goerli.basescan.org" + ], + "chainId": 84531, + "chainName": "Base Goerli Test Network", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "https://bridge.base.org/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Base Goerli Test Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://goerli.base.org", + "https://base-goerli.public.blastapi.io", + "https://base-goerli.diamondswap.org/rpc", + "https://1rpc.io/base-goerli", + "https://base-goerli.publicnode.com" + ], + "origins": [ + "https://base.org/" + ], + "priceMechanism": "EIP1559", + "shortName": "BASETEST", + "tokenIndex": { + "tokens": {} + }, + "type": "PUBLIC" + }, + "GANACHE7545_1337": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://blockexplorer.x" + ], + "chainId": 1337, + "chainName": "Ganache Test Chain, default local port 7545 and chainid 1337", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Development Test Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "http://127.0.0.1:7545" + ], + "origins": [ + "https://gsthina.medium.com/the-default-chain-id-for-ganache-metamask-is-1337-can-you-try-to-override-it-de5ad1bcb3ab" + ], + "priceMechanism": "LEGACY", + "shortName": "GANACHE7545_1337", + "tokenIndex": { + "tokens": {} + }, + "type": "LOCAL" + }, + "MANTLE": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.mantle.xyz" + ], + "chainId": 5000, + "chainName": "Mantle Mainnet", + "fallbackGasLimitInUnits": "21000", + "fallbackGasPriceInWEI": "1000000000", + "faucets": [ + "https://bridge.mantle.xyz/" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "Mantle Gas Token", + "symbol": "MNT" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": { + "CITIZEN": { + "category": "CHAINMASCOT", + "chain": "MANTLE", + "contractAddress": "0x7cf4aC414C94E03Ecb2A7d6EA8F79087453cAEf0", + "description": "Citizen of Mantle", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://explorer.mantle.xyz/token/0x7cf4aC414C94E03Ecb2A7d6EA8F79087453cAEf0", + "https://journey.mantle.xyz/" + ], + "symbol": "CITIZEN" + } + } + }, + "nodeURLs": [ + "https://rpc.mantle.xyz", + "https://mantle.publicnode.com", + "https://mantle-mainnet.public.blastapi.io", + "https://mantle.drpc.org", + "https://rpc.ankr.com/mantle", + "https://1rpc.io/mantle" + ], + "origins": [ + "https://www.mantle.xyz/" + ], + "priceMechanism": "EIP1559", + "shortName": "MANTLE", + "tokenIndex": { + "tokens": { + "USDT": { + "category": "STABLECOIN", + "chain": "MANTLE", + "contractAddress": "0x201EBa5CC46D216Ce6DC03F6a759e8E766e956aE", + "decimals": 6, + "name": "Tether stable coin", + "origins": [ + "https://explorer.mantle.xyz/token/0x201EBa5CC46D216Ce6DC03F6a759e8E766e956aE" + ], + "symbol": "USDT" + }, + "WETH": { + "category": "DEFI", + "chain": "MANTLE", + "contractAddress": "0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111", + "decimals": 18, + "name": "Wrapped ETH token", + "origins": [ + "https://explorer.mantle.xyz/token/0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111", + "https://www.coingecko.com/en/coins/wrapped-ether-mantle-bridge" + ], + "symbol": "WETH" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "MANTLE", + "contractAddress": "0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9", + "decimals": 6, + "name": "USDC stable coin", + "origins": [ + "https://explorer.mantle.xyz/address/0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9" + ], + "symbol": "USDC" + } + } + }, + "type": "PUBLIC" + }, + "BASE": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://basescan.org" + ], + "chainId": 8453, + "chainName": "BASE Mainnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "30000000000", + "faucets": [ + "faucet-to-be-inserted" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "BASE Native Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": {} + }, + "nodeURLs": [ + "https://base.blockpi.network/v1/rpc/public", + "https://developer-access-mainnet.base.org", + "https://base-mainnet.public.blastapi.io", + "https://base.meowrpc.com", + "https://base.publicnode.com", + "https://1rpc.io/base", + "https://mainnet.base.org", + "https://rpc.notadegen.com/base", + "https://base-mainnet.diamondswap.org/rpc" + ], + "origins": [ + "https://chainlist.org/chain/8453", + "https://base.org/" + ], + "priceMechanism": "LEGACY", + "shortName": "BASE", + "tokenIndex": { + "tokens": { + "USDbC": { + "category": "STABLECOIN", + "chain": "BASE", + "contractAddress": "0xd9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca", + "decimals": 6, + "name": "USDbC stablecoin token", + "origins": [ + "https://basescan.org/address/0xd9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca" + ], + "symbol": "USDbC" + }, + "AERODOME_AERO_WETH_LP": { + "category": "LIQUIDITY_PROVIDER", + "chain": "BASE", + "contractAddress": "0x7f670f78b17dec44d5ef68a48740b6f8849cc2e6", + "decimals": 18, + "name": "Aerodome Finance AERO/WETH LP position", + "origins": [ + "https://basescan.org/token/0x7f670f78b17dec44d5ef68a48740b6f8849cc2e6", + "https://aerodrome.finance/" + ], + "symbol": "AERODOME_AERO_WETH_LP" + }, + "WETH": { + "category": "DEFI", + "chain": "BASE", + "contractAddress": "0x4200000000000000000000000000000000000006", + "decimals": 18, + "name": "Wrapped ETH token", + "origins": [ + "https://basescan.org/address/0x4200000000000000000000000000000000000006" + ], + "symbol": "WETH" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "BASE", + "contractAddress": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6, + "name": "USDC stablecoin token", + "origins": [ + "https://basescan.org/address/0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "https://www.coingecko.com/en/coins/usd-coin" + ], + "symbol": "USDC" + }, + "AERODOME_DAI_WETH_LP": { + "category": "LIQUIDITY_PROVIDER", + "chain": "BASE", + "contractAddress": "0x9287c921f5d920ceee0d07d7c58d476e46acc640", + "decimals": 18, + "name": "Aerodome Finance DAI/WETH LP position", + "origins": [ + "https://basescan.org/token/0x9287c921f5d920ceee0d07d7c58d476e46acc640", + "https://aerodrome.finance/" + ], + "symbol": "AERODOME_DAI_WETH_LP" + }, + "DAI": { + "category": "STABLECOIN", + "chain": "BASE", + "contractAddress": "0x50c5725949a6f0c72e6c4a641f24049a917db0cb", + "decimals": 18, + "name": "DAI stablecoin token", + "origins": [ + "https://basescan.org/address/0x50c5725949a6f0c72e6c4a641f24049a917db0cb", + "https://www.coingecko.com/en/coins/dai" + ], + "symbol": "DAI" + }, + "AERO": { + "category": "DEFI", + "chain": "BASE", + "contractAddress": "0x940181a94a35a4569e4529a3cdfb74e38fd98631", + "decimals": 18, + "name": "AERO DEFI token", + "origins": [ + "https://basescan.org/address/0x940181a94a35a4569e4529a3cdfb74e38fd98631" + ], + "symbol": "AERO" + } + } + }, + "type": "PUBLIC" + }, + "ZKSYNCERA": { + "archivenodeURLs": [], + "blockexplorerURLs": [ + "https://explorer.zksync.io" + ], + "chainId": 324, + "chainName": "zkSync Era Mainnet", + "fallbackGasLimitInUnits": "300000", + "fallbackGasPriceInWEI": "250000000", + "faucets": [ + "brige test funds from goerli using https://portal.zksync.io/bridge" + ], + "flashbotnodeURLs": [], + "flashbotrelaynodeURLs": [], + "nativeCurrency": { + "decimal": 18, + "name": "zkSync Token", + "symbol": "ETH" + }, + "nftindex": { + "erc1155tokens": {}, + "erc721tokens": { + "ZKAPE": { + "category": "SOCIAL", + "chain": "ZKSYNCERA", + "contractAddress": "0x5e6f0f1d604d7300c10933aa8834afa034d448ea", + "description": "ZKSyncEra Ape", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://explorer.zksync.io/address/0x5e6f0f1d604d7300c10933aa8834afa034d448ea", + "https://zkape.io", + "https://mintsquare.io/collection/zksync/0x5e6f0f1d604d7300c10933aa8834afa034d448ea" + ], + "symbol": "ZKAPE" + }, + "ERANAMESERVICE": { + "category": "NAMESERVICE", + "chain": "ZKSYNCERA", + "contractAddress": "0x935442AF47F3dc1c11F006D551E13769F12eab13", + "description": "ERA Name service", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://explorer.zksync.io/address/0x935442AF47F3dc1c11F006D551E13769F12eab13", + "https://era.name" + ], + "symbol": "ERANAMESERVICE" + } + } + }, + "nodeURLs": [ + "https://mainnet.era.zksync.io", + "https://zksync.drpc.org", + "https://zksync-era.blockpi.network/v1/rpc/public", + "https://zksync.meowrpc.com" + ], + "origins": [ + "https://chainlist.org/chain/324" + ], + "priceMechanism": "EIP1559", + "shortName": "ZKSYNCERA", + "tokenIndex": { + "tokens": { + "PERP": { + "category": "DEFI", + "chain": "ZKSYNCERA", + "contractAddress": "0x42c1c56be243c250AB24D2ecdcC77F9cCAa59601", + "decimals": 18, + "name": "PERP token", + "origins": [ + "https://explorer.zksync.io/address/0x42c1c56be243c250AB24D2ecdcC77F9cCAa59601", + "https://www.coingecko.com/en/coins/perpetual-protocol" + ], + "symbol": "PERP" + }, + "SYNCSWAP_USDC_WETH_LP": { + "category": "DEFI", + "chain": "ZKSYNCERA", + "contractAddress": "0x80115c708E12eDd42E504c1cD52Aea96C547c05c", + "decimals": 18, + "name": "Syncswap USDC/WETH LP position", + "origins": [ + "https://explorer.zksync.io/address/0x80115c708E12eDd42E504c1cD52Aea96C547c05c", + "https://syncswap.xyz" + ], + "symbol": "SYNCSWAP_USDC_WETH_LP" + }, + "YSYNC": { + "category": "DEFI", + "chain": "ZKSYNCERA", + "contractAddress": "0xE0eF1c039a36eC77339E7277ECd4D48e57b61eec", + "decimals": 18, + "name": "YSYNC token", + "origins": [ + "https://explorer.zksync.io/address/0xE0eF1c039a36eC77339E7277ECd4D48e57b61eec", + "https://syncswap.xyz" + ], + "symbol": "YSYNC" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "ZKSYNCERA", + "contractAddress": "0x3355df6D4c9C3035724Fd0e3914dE96A5a83aaf4", + "decimals": 6, + "name": "USDC stablecoin token", + "origins": [ + "https://explorer.zksync.io/address/0x3355df6D4c9C3035724Fd0e3914dE96A5a83aaf4", + "https://www.coingecko.com/en/coins/usd-coin" + ], + "symbol": "USDC" + }, + "COMBO": { + "category": "DEFI", + "chain": "ZKSYNCERA", + "contractAddress": "0xc2B13Bb90E33F1E191b8aA8F44Ce11534D5698E3", + "decimals": 18, + "name": "COMBO token", + "origins": [ + "https://explorer.zksync.io/address/0xc2B13Bb90E33F1E191b8aA8F44Ce11534D5698E3", + "https://www.coingecko.com/en/coins/furucombo" + ], + "symbol": "COMBO" + }, + "zkUSD": { + "category": "STABLECOIN", + "chain": "ZKSYNCERA", + "contractAddress": "0xfC7E56298657B002b3e656400E746b7212912757", + "decimals": 6, + "name": "zkUSD stablecoin token", + "origins": [ + "https://explorer.zksync.io/address/0xfC7E56298657B002b3e656400E746b7212912757" + ], + "symbol": "zkUSD" + }, + "ZAT": { + "category": "GAMING", + "chain": "ZKSYNCERA", + "contractAddress": "0x47EF4A5641992A72CFd57b9406c9D9cefEE8e0C4", + "decimals": 18, + "name": "zkApes token", + "origins": [ + "https://explorer.zksync.io/address/0x47EF4A5641992A72CFd57b9406c9D9cefEE8e0C4", + "https://zkape.io" + ], + "symbol": "ZAT" + }, + "MUTE": { + "category": "DEFI", + "chain": "ZKSYNCERA", + "contractAddress": "0x0e97C7a0F8B2C9885C8ac9fC6136e829CbC21d42", + "decimals": 18, + "name": "MUTE token", + "origins": [ + "https://explorer.zksync.io/address/0x0e97C7a0F8B2C9885C8ac9fC6136e829CbC21d42", + "https://www.coingecko.com/en/coins/mute" + ], + "symbol": "MUTE" + }, + "VC": { + "category": "DEFI", + "chain": "ZKSYNCERA", + "contractAddress": "0x99bBE51be7cCe6C8b84883148fD3D12aCe5787F2", + "decimals": 18, + "name": "Velocore token", + "origins": [ + "https://explorer.zksync.io/address/0x99bBE51be7cCe6C8b84883148fD3D12aCe5787F2", + "https://zksync-v2.velocore.xyz" + ], + "symbol": "VC" + } + } + }, + "type": "PUBLIC" + } + } +} diff --git a/fantomtokenindex.json b/fantomtokenindex.json new file mode 100644 index 0000000..c406374 --- /dev/null +++ b/fantomtokenindex.json @@ -0,0 +1,87 @@ +{ + "tokens": { + "SPOOKYSWAP_FTM_MULTI_LP": { + "category": "LIQUIDITY_PROVIDER", + "chain": "FANTOM", + "contractAddress": "0x297C8990134bf1eE08aE5D8805042fbac8781201", + "decimals": 18, + "name": "Spookyswap FTM+MULTI LP token", + "origins": [ + "https://ftmscan.com/token/0x297c8990134bf1ee08ae5d8805042fbac8781201?a=0xf0803b4cf6359d64913ec6a0b8227640afe69b2a", + "https://spooky.fi/#/add/FTM/0x9Fb9a33956351cf4fa040f65A13b835A3C8764E3" + ], + "symbol": "SPOOKYSWAP_FTM_MULTI_LP" + }, + "TEST": { + "category": "TEST", + "chain": "FANTOM", + "contractAddress": "0x62b65f4b89e9a56b687ccebb57b4afeafa933894", + "decimals": 18, + "name": "TEST token", + "origins": [ + "https://polygonscan.com/token/0xMOJO" + ], + "symbol": "TEST" + }, + "STG": { + "category": "DEFI", + "chain": "FANTOM", + "contractAddress": "0x2f6f07cdcf3588944bf4c42ac74ff24bf56e7590", + "decimals": 18, + "name": "StarGate token", + "origins": [ + "https://ftmscan.com/address/0x2f6f07cdcf3588944bf4c42ac74ff24bf56e7590", + "https://www.coingecko.com/en/coins/stargate-finance" + ], + "symbol": "STG" + }, + "USDT": { + "category": "STABLECOIN", + "chain": "FANTOM", + "contractAddress": "0x049d68029688eabf473097a2fc38ef61633a3c7a", + "decimals": 18, + "name": "Tether stablecoin token", + "origins": [ + "https://ftmscan.com/address/0x049d68029688eabf473097a2fc38ef61633a3c7a", + "https://www.coingecko.com/en/coins/tether" + ], + "symbol": "USDT" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "FANTOM", + "contractAddress": "0x04068da6c83afcfa0e13ba15a6696662335d5b75", + "decimals": 6, + "name": "USDC stablecoin token", + "origins": [ + "https://ftmscan.com/address/0x04068da6c83afcfa0e13ba15a6696662335d5b75", + "https://www.coingecko.com/en/coins/usd-coin" + ], + "symbol": "USDC" + }, + "MULTI": { + "category": "DEFI", + "chain": "FANTOM", + "contractAddress": "0x9fb9a33956351cf4fa040f65a13b835a3c8764e3", + "decimals": 18, + "name": "Multichain token", + "origins": [ + "https://ftmscan.com/address/0x9fb9a33956351cf4fa040f65a13b835a3c8764e3", + "https://www.coingecko.com/en/coins/multichain" + ], + "symbol": "MULTI" + }, + "DAI": { + "category": "STABLECOIN", + "chain": "FANTOM", + "contractAddress": "0x8d11ec38a3eb5e956b052f67da8bdc9bef8abf3e", + "decimals": 18, + "name": "DAI stablecoin token", + "origins": [ + "https://ftmscan.com/address/0x8d11ec38a3eb5e956b052f67da8bdc9bef8abf3e", + "https://www.coingecko.com/en/coins/dai" + ], + "symbol": "DAI" + } + } +} diff --git a/goerlitokenindex.json b/goerlitokenindex.json new file mode 100644 index 0000000..8d53a4f --- /dev/null +++ b/goerlitokenindex.json @@ -0,0 +1,92 @@ +{ + "tokens": { + "ZETA": { + "category": "DEFI", + "chain": "GOERLITEST", + "contractAddress": "0xCc7bb2D219A0FC08033E130629C2B854b7bA9195", + "decimals": 18, + "name": "ZETA swap/bridge gas token", + "origins": [ + "https://goerli.etherscan.io/token/0xCc7bb2D219A0FC08033E130629C2B854b7bA9195" + ], + "symbol": "ZETA" + }, + "MNT": { + "category": "DEFI", + "chain": "GOERLITEST", + "contractAddress": "0xc1dC2d65A2243c22344E725677A3E3BEBD26E604", + "decimals": 18, + "name": "Mantle ERC-20 token", + "origins": [ + "https://goerli.etherscan.io/token/0xc1dC2d65A2243c22344E725677A3E3BEBD26E604" + ], + "symbol": "MNT" + }, + "TSTv4": { + "category": "TEST", + "chain": "GOERLITEST", + "contractAddress": "0x499d11E0b6eAC7c0593d8Fb292DCBbF815Fb29Ae", + "decimals": 18, + "name": "Goerli ERC-20 TST token", + "origins": [ + "https://goerli.etherscan.io/token/0x499d11E0b6eAC7c0593d8Fb292DCBbF815Fb29Ae" + ], + "symbol": "TSTv4" + }, + "TEST": { + "category": "TEST", + "chain": "GOERLITEST", + "contractAddress": "0x3f152b63ec5ca5831061b2dccfb29a874c317502", + "decimals": 18, + "name": "TEST token", + "origins": [ + "https://goerli.etherscan.io/token/0xMOJO" + ], + "symbol": "TEST" + }, + "TST4": { + "category": "TEST", + "chain": "GOERLITEST", + "contractAddress": "0x3f152b63ec5ca5831061b2dccfb29a874c317502", + "decimals": 18, + "name": "Official Goerli ERC-20 TST token", + "origins": [ + "https://goerli.etherscan.io/token/0x3f152b63ec5ca5831061b2dccfb29a874c317502" + ], + "symbol": "TST4" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "GOERLITEST", + "contractAddress": "0x07865c6e87b9f70255377e024ace6630c1eaa37f", + "decimals": 6, + "name": "USDC Stable token", + "origins": [ + "https://goerli.etherscan.io/token/0x07865c6e87b9f70255377e024ace6630c1eaa37f" + ], + "symbol": "USDC" + }, + "WETH": { + "category": "DEFI", + "chain": "GOERLITEST", + "contractAddress": "0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6", + "decimals": 18, + "name": "Wrapped ETH token", + "origins": [ + "https://goerli.etherscan.io/address/0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6" + ], + "symbol": "WETH" + }, + "DAI": { + "category": "DEFI", + "chain": "GOERLITEST", + "contractAddress": "0x11fe4b6ae13d2a6055c8d9cf65c55bac32b5d844", + "decimals": 18, + "name": "DAI USD stablecoin token", + "origins": [ + "https://goerli.etherscan.io/address/0x11fe4b6ae13d2a6055c8d9cf65c55bac32b5d844" + ], + "symbol": "DAI" + } + } +} diff --git a/img/forestfishto.png b/img/forestfishto.png new file mode 100644 index 0000000..4955306 Binary files /dev/null and b/img/forestfishto.png differ diff --git a/mumbaitokenindex.json b/mumbaitokenindex.json new file mode 100644 index 0000000..70ab716 --- /dev/null +++ b/mumbaitokenindex.json @@ -0,0 +1,133 @@ +{ + "tokens": { + "RICOCHET_fUSDCx": { + "category": "DEFI", + "chain": "MUMBAITEST", + "contractAddress": "0x42bb40bF79730451B11f6De1CbA222F17b87Afd7", + "decimals": 18, + "name": "Ricochet fUSDC token, fUSDCx", + "origins": [ + "https://mumbai.polygonscan.com/token/0x42bb40bF79730451B11f6De1CbA222F17b87Afd7", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "RICOCHET_fUSDCx" + }, + "TST": { + "category": "TEST", + "chain": "MUMBAITEST", + "contractAddress": "0x2d7882bedcbfddce29ba99965dd3cdf7fcb10a1e", + "decimals": 18, + "name": "Official Mumbai ERC-20 TST token", + "origins": [ + "https://mumbai.polygonscan.com/address/0x2d7882bedcbfddce29ba99965dd3cdf7fcb10a1e" + ], + "symbol": "TST" + }, + "TEST": { + "category": "TEST", + "chain": "MUMBAITEST", + "contractAddress": "0xeedb61304686f4b544baa1cb19f87c30bb8d38b9", + "decimals": 18, + "name": "TEST token", + "origins": [ + "https://mumbai.polygonscan.com/token/0xMOJO" + ], + "symbol": "TEST" + }, + "fUSDC": { + "category": "DEFI", + "chain": "MUMBAITEST", + "contractAddress": "0xbe49ac1EadAc65dccf204D4Df81d650B50122aB2", + "decimals": 18, + "name": "Flux fUSDC token", + "origins": [ + "https://mumbai.polygonscan.com/token/0xbe49ac1EadAc65dccf204D4Df81d650B50122aB2", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "fUSDC" + }, + "RICOCHET_fTUSDx": { + "category": "DEFI", + "chain": "MUMBAITEST", + "contractAddress": "0x918E0d5C96cAC79674E2D38066651212be3C9C48", + "decimals": 18, + "name": "Ricochet fTUSD token, fTUSDx", + "origins": [ + "https://mumbai.polygonscan.com/token/0x918E0d5C96cAC79674E2D38066651212be3C9C48", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "RICOCHET_fTUSDx" + }, + "fDAI": { + "category": "STABLECOIN", + "chain": "MUMBAITEST", + "contractAddress": "0x15F0Ca26781C3852f8166eD2ebce5D18265cceb7", + "decimals": 18, + "name": "Flux fDAI stablecoin", + "origins": [ + "https://mumbai.polygonscan.com/token/0x15F0Ca26781C3852f8166eD2ebce5D18265cceb7", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "fDAI" + }, + "LINK": { + "category": "DEFI", + "chain": "MUMBAITEST", + "contractAddress": "0x326C977E6efc84E512bB9C30f76E30c160eD06FB", + "decimals": 18, + "name": "LINK token", + "origins": [ + "https://mumbai.polygonscan.com/token/0x326c977e6efc84e512bb9c30f76e30c160ed06fb", + "https://www.coingecko.com/en/coins/chainlink" + ], + "symbol": "LINK" + }, + "fTUSD": { + "category": "STABLECOIN", + "chain": "MUMBAITEST", + "contractAddress": "0xA794C9ee519FD31BbCE643e8D8138f735E97D1DB", + "decimals": 18, + "name": "Flux fTUSD stablecoin", + "origins": [ + "https://mumbai.polygonscan.com/token/0xA794C9ee519FD31BbCE643e8D8138f735E97D1DB", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "fTUSD" + }, + "RICOCHET_fDAIx": { + "category": "DEFI", + "chain": "MUMBAITEST", + "contractAddress": "0x15F0Ca26781C3852f8166eD2ebce5D18265cceb7", + "decimals": 18, + "name": "Ricochet fDAI token, fDAIx", + "origins": [ + "https://mumbai.polygonscan.com/token/0x15F0Ca26781C3852f8166eD2ebce5D18265cceb7", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "RICOCHET_fDAIx" + }, + "RICOCHET_MATICx": { + "category": "DEFI", + "chain": "MUMBAITEST", + "contractAddress": "0x96B82B65ACF7072eFEb00502F45757F254c2a0D4", + "decimals": 18, + "name": "Ricochet MATIC token, MATICx", + "origins": [ + "https://mumbai.polygonscan.com/token/0x96B82B65ACF7072eFEb00502F45757F254c2a0D4", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "RICOCHET_MATICx" + }, + "DERC20": { + "category": "TEST", + "chain": "MUMBAITEST", + "contractAddress": "0x2d7882bedcbfddce29ba99965dd3cdf7fcb10a1e", + "decimals": 18, + "name": "Official Mumbai ERC-20 Dummy ERC20 token", + "origins": [ + "https://mumbai.polygonscan.com/token/0xfe4f5145f6e09952a5ba9e956ed0c25e3fa4c7f1" + ], + "symbol": "DERC20" + } + } +} diff --git a/polygonnfttokenindex.json b/polygonnfttokenindex.json new file mode 100644 index 0000000..9a0e15b --- /dev/null +++ b/polygonnfttokenindex.json @@ -0,0 +1,206 @@ +{ + "erc1155tokens": { + "AAVEGOTCHI_INSTALLATION": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x9216c31d8146bcb3ea5a9162dc1702e8aedca355", + "description": "AAvegotchi game land installation NFT", + "linked_tokens": [ + "POLYGON:GHST", + "POLYGON:KEK", + "POLYGON:ALPHA", + "POLYGON:FOMO", + "POLYGON:FUD", + "POLYGON:GLTR" + ], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0x9216c31d8146bcb3ea5a9162dc1702e8aedca355", + "https://opensea.io/collection/gotchiverse-installations" + ], + "symbol": "AAVEGOTCHI_INSTALLATION" + } + }, + "erc721tokens": { + "UNISWAPV3_POSITION": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0xC36442b4a4522E871399CD717aBDD847Ab11FE88", + "description": "Uniswap v3 position NFT", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/token/0xc36442b4a4522e871399cd717abdd847ab11fe88" + ], + "symbol": "UNISWAPV3_POSITION" + }, + "UAPX_SONG": { + "category": "NFT", + "chain": "POLYGON", + "contractAddress": "0x86c47873dd7d2186f5bd87da4757aecf1e16ac2e", + "description": "UAPx song NFT (formerly Terra)", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0x86c47873dd7d2186f5bd87da4757aecf1e16ac2e" + ], + "symbol": "UAPX_SONG" + }, + "UAPX_SHIP": { + "category": "NFT", + "chain": "POLYGON", + "contractAddress": "0x2148da6c55c10ea3d9b33311d19a065592abd24b", + "description": "UAPx ship NFT (formerly Terra)", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0x2148da6c55c10ea3d9b33311d19a065592abd24b" + ], + "symbol": "UAPX_SHIP" + }, + "UAPX_ALIEN": { + "category": "NFT", + "chain": "POLYGON", + "contractAddress": "0xd8f000eac06cebab3b967eeb137fbcac842a1472", + "description": "UAPx alien NFT (formerly Terra)", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0xd8f000eac06cebab3b967eeb137fbcac842a1472" + ], + "symbol": "UAPX_ALIEN" + }, + "AAVEGOTCHI": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x86935f11c86623dec8a25696e1c19a8659cbf95d", + "description": "AAvegotchi game NFT", + "linked_tokens": [ + "POLYGON:GHST", + "POLYGON:KEK", + "POLYGON:ALPHA", + "POLYGON:FOMO", + "POLYGON:FUD", + "POLYGON:GLTR" + ], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/token/0x86935f11c86623dec8a25696e1c19a8659cbf95d" + ], + "symbol": "AAVEGOTCHI" + }, + "UNSTOPPABLE_DOMAIN": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0xa9a6a3626993d487d2dbda3173cf58ca1a9d9e9f", + "description": "Unstoppable domains NFT", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0xa9a6a3626993d487d2dbda3173cf58ca1a9d9e9f" + ], + "symbol": "UNSTOPPABLE_DOMAIN" + }, + "UNIOVERSE": { + "category": "NFT", + "chain": "POLYGON", + "contractAddress": "0xed55e4477b795eaa9bb4bca24df42214e1a05c18", + "description": "Unioverse Collectibles", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0xed55e4477b795eaa9bb4bca24df42214e1a05c18" + ], + "symbol": "UNIOVERSE" + }, + "AAVEGOTCHI_LAND": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x1d0360bac7299c86ec8e99d0c1c9a95fefaf2a11", + "description": "AAvegotchi game LAND NFT", + "linked_tokens": [ + "POLYGON:GHST", + "POLYGON:KEK", + "POLYGON:ALPHA", + "POLYGON:FOMO", + "POLYGON:FUD", + "POLYGON:GLTR" + ], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0x1d0360bac7299c86ec8e99d0c1c9a95fefaf2a11" + ], + "symbol": "AAVEGOTCHI_LAND" + }, + "LENSPROTOCOLPROFILE": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0xdb46d1dc155634fbc732f92e853b10b288ad5a1d", + "description": "Lens Protocol Profile NFT", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0xdb46d1dc155634fbc732f92e853b10b288ad5a1d" + ], + "symbol": "LENSPROTOCOLPROFILE" + }, + "MYCRYPTOHEROES": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x77bd275ff2b3dc007475aac9ce7f408f5a800188", + "description": "My Crypto Heroes NFT", + "linked_tokens": [], + "mintBlock": 16765971, + "origins": [ + "https://polygonscan.com/address/0x77bd275ff2b3dc007475aac9ce7f408f5a800188" + ], + "symbol": "MYCRYPTOHEROES" + }, + "SANDBOX_LAND": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x9d305a42a3975ee4c1c57555bed5919889dce63f", + "description": "The Sandbox LAND NFT", + "linked_tokens": [ + "POLYGON:SAND" + ], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0x9d305a42a3975ee4c1c57555bed5919889dce63f", + "https://opensea.io/collection/sandbox" + ], + "symbol": "SANDBOX_LAND" + }, + "TRUMP": { + "category": "SCAM", + "chain": "POLYGON", + "contractAddress": "0x24a11e702cd90f034ea44faf1e180c0c654ac5d9", + "description": "Trump Digital Trading Card NFT", + "linked_tokens": [], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0x24a11e702cd90f034ea44faf1e180c0c654ac5d9" + ], + "symbol": "TRUMP" + }, + "AAVEGOTCHI_GMI": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x3f0e22b827e51ff567d7388c2b598e2eabfa74be", + "description": "AAvegotchi GMI NFT", + "linked_tokens": [ + "POLYGON:GHST", + "POLYGON:KEK", + "POLYGON:ALPHA", + "POLYGON:FOMO", + "POLYGON:FUD", + "POLYGON:GLTR" + ], + "mintBlock": 0, + "origins": [ + "https://polygonscan.com/address/0x3f0e22b827e51ff567d7388c2b598e2eabfa74be" + ], + "symbol": "AAVEGOTCHI_GMI" + } + } +} diff --git a/polygontokenindex.json b/polygontokenindex.json new file mode 100644 index 0000000..52fa0b9 --- /dev/null +++ b/polygontokenindex.json @@ -0,0 +1,490 @@ +{ + "tokens": { + "GLTR": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x3801c3b3b5c98f88a9c9005966aa96aa440b9afc", + "decimals": 18, + "name": "GAX Liquidity Token Reward, Aavegotchi game token", + "origins": [ + "https://polygonscan.com/token/0x3801c3b3b5c98f88a9c9005966aa96aa440b9afc", + "https://www.coingecko.com/en/coins/gax-liquidity-token-reward" + ], + "symbol": "GLTR" + }, + "RICOCHET_WBTCx": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x4086eBf75233e8492F1BCDa41C7f2A8288c2fB92", + "decimals": 18, + "name": "Ricochet WBTC token, WBTCx", + "origins": [ + "https://polygonscan.com/token/0x4086eBf75233e8492F1BCDa41C7f2A8288c2fB92", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "RICOCHET_WBTCx" + }, + "RICOCHET_ETHx": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x27e1e4E6BC79D93032abef01025811B7E4727e85", + "decimals": 18, + "name": "Ricochet ETH token, ETHx", + "origins": [ + "https://polygonscan.com/token/0x27e1e4E6BC79D93032abef01025811B7E4727e85", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "RICOCHET_ETHx" + }, + "LUCHA": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x6749441fdc8650b5b5a854ed255c82ef361f1596", + "decimals": 18, + "name": "Luchadores game token", + "origins": [ + "https://polygonscan.com/address/0x6749441fdc8650b5b5a854ed255c82ef361f1596", + "https://www.coingecko.com/en/coins/lucha" + ], + "symbol": "LUCHA" + }, + "SYNAPSE": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0xf8f9efc0db77d8881500bb06ff5d6abc3070e695", + "decimals": 18, + "name": "Synapse Defi token", + "origins": [ + "https://polygonscan.com/token/0xf8f9efc0db77d8881500bb06ff5d6abc3070e695", + "https://www.coingecko.com/en/coins/synapse" + ], + "symbol": "SYNAPSE" + }, + "STG": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x2f6f07cdcf3588944bf4c42ac74ff24bf56e7590", + "decimals": 18, + "name": "StarGate token", + "origins": [ + "https://polygonscan.com/token/0x2f6f07cdcf3588944bf4c42ac74ff24bf56e7590", + "https://www.coingecko.com/en/coins/stargate-finance" + ], + "symbol": "STG" + }, + "VRSW": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x57999936fc9a9ec0751a8d146cce11901be8bed0", + "decimals": 18, + "name": "Virtuswap token", + "origins": [ + "https://polygonscan.com/token/0x57999936fc9a9ec0751a8d146cce11901be8bed0" + ], + "symbol": "VRSW" + }, + "ALPHA": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x6a3e7c3c6ef65ee26975b12293ca1aad7e1daed2", + "decimals": 18, + "name": "Aavegotchi ALPHA game token", + "origins": [ + "https://polygonscan.com/address/0x6a3e7c3c6ef65ee26975b12293ca1aad7e1daed2", + "https://www.coingecko.com/en/coins/aavegotchi-alpha" + ], + "symbol": "ALPHA" + }, + "QUICKSWAP_aWMATIC_GHST_LP": { + "category": "LIQUIDITY_PROVIDER", + "chain": "POLYGON", + "contractAddress": "0x2ef46196d7d25b5111ca1fcba206b248fee32d8d", + "decimals": 18, + "name": "WMATIC/GHST Quickswap Pool token", + "origins": [ + "https://polygonscan.com/token/0x2ef46196d7d25b5111ca1fcba206b248fee32d8d" + ], + "symbol": "QUICKSWAP_aWMATIC_GHST_LP" + }, + "USDT": { + "category": "STABLECOIN", + "chain": "POLYGON", + "contractAddress": "0xc2132d05d31c914a87c6611c10748aeb04b58e8f", + "decimals": 18, + "name": "Tether stablecoin token", + "origins": [ + "https://polygonscan.com/address/0xc2132d05d31c914a87c6611c10748aeb04b58e8f", + "https://www.coingecko.com/en/coins/tether" + ], + "symbol": "USDT" + }, + "FOMO": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x44a6e0be76e1d9620a7f76588e4509fe4fa8e8c8", + "decimals": 18, + "name": "Aavegotchi FOMO game token", + "origins": [ + "https://polygonscan.com/address/0x44a6e0be76e1d9620a7f76588e4509fe4fa8e8c8", + "https://www.coingecko.com/en/coins/aavegotchi-fomo" + ], + "symbol": "FOMO" + }, + "gDAI": { + "category": "STABLECOIN", + "chain": "POLYGON", + "contractAddress": "0x91993f2101cc758d0deb7279d41e880f7defe827", + "decimals": 18, + "name": "GAINS Network DAI token", + "origins": [ + "https://polygonscan.com/address/0x91993f2101cc758d0deb7279d41e880f7defe827" + ], + "symbol": "gDAI" + }, + "amLINK": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x0ca2e42e8c21954af73bc9af1213e4e81d6a669a", + "decimals": 18, + "name": "Aave LINK token", + "origins": [ + "https://polygonscan.com/token/0x0ca2e42e8c21954af73bc9af1213e4e81d6a669a", + "https://www.coingecko.com/en/coins/chainlink" + ], + "symbol": "amLINK" + }, + "CXDOGE": { + "category": "WRECKED", + "chain": "POLYGON", + "contractAddress": "0x9bd9ad490dd3a52f096d229af4483b94d63be618", + "decimals": 18, + "name": "CelsiusX Wrapped DOGE token (wrecked)", + "origins": [ + "https://polygonscan.com/address/0x9bd9ad490dd3a52f096d229af4483b94d63be618", + "https://www.coingecko.com/en/coins/celsiusx-wrapped-doge" + ], + "symbol": "CXDOGE" + }, + "FUD": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x403e967b044d4be25170310157cb1a4bf10bdd0f", + "decimals": 18, + "name": "Aavegotchi FUD game token", + "origins": [ + "https://polygonscan.com/address/0x403e967b044d4be25170310157cb1a4bf10bdd0f", + "https://www.coingecko.com/en/coins/aavegotchi-fud" + ], + "symbol": "FUD" + }, + "LINK": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x53e0bca35ec356bd5dddfebbd1fc0fd03fabad39", + "decimals": 18, + "name": "LINK token", + "origins": [ + "https://polygonscan.com/address/0x53e0bca35ec356bd5dddfebbd1fc0fd03fabad39", + "https://www.coingecko.com/en/coins/chainlink" + ], + "symbol": "LINK" + }, + "ROLL": { + "category": "DUST", + "chain": "POLYGON", + "contractAddress": "0xC68e83a305b0FaD69E264A1769a0A070F190D2d6", + "decimals": 18, + "name": "ROLL SCAM token", + "origins": [ + "https://polygonscan.com/token/0xc68e83a305b0fad69e264a1769a0a070f190d2d6#comments", + "https://polyroll.org/" + ], + "symbol": "ROLL" + }, + "MATICX": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0xfa68fb4628dff1028cfec22b4162fccd0d45efb6", + "decimals": 18, + "name": "Stader Liquid Staking Matic (PoS) token", + "origins": [ + "https://polygonscan.com/token/0xfa68fb4628dff1028cfec22b4162fccd0d45efb6", + "https://www.coingecko.com/en/coins/stader-maticx" + ], + "symbol": "MATICX" + }, + "SAND": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0xbbba073c31bf03b8acf7c28ef0738decf3695683", + "decimals": 18, + "name": "The Sandbox SAND game token", + "origins": [ + "https://polygonscan.com/address/0xbbba073c31bf03b8acf7c28ef0738decf3695683", + "https://www.coingecko.com/en/coins/the-sandbox" + ], + "symbol": "SAND" + }, + "RICOCHET": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x263026e7e53dbfdce5ae55ade22493f828922965", + "decimals": 18, + "name": "Ricochet reward token", + "origins": [ + "https://polygonscan.com/address/0x263026e7e53dbfdce5ae55ade22493f828922965", + "https://www.coingecko.com/en/coins/ricochet" + ], + "symbol": "RICOCHET" + }, + "GHST": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x385eeac5cb85a38a9a07a70c73e0a3271cfb54a7", + "decimals": 18, + "name": "Aavegotchi GHST game token", + "origins": [ + "https://polygonscan.com/address/0x385eeac5cb85a38a9a07a70c73e0a3271cfb54a7", + "https://www.coingecko.com/en/coins/aavegotchi" + ], + "symbol": "GHST" + }, + "MOD": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x8346ab8d5ea7a9db0209aed2d1806afa0e2c4c21", + "decimals": 18, + "name": "MOD token", + "origins": [ + "https://www.coingecko.com/en/coins/modefi", + "https://polygonscan.com/token/0x8346ab8d5ea7a9db0209aed2d1806afa0e2c4c21", + "https://modefi.io/" + ], + "symbol": "MOD" + }, + "amWMATIC": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x8df3aad3a84da6b69a4da8aec3ea40d9091b2ac4", + "decimals": 18, + "name": "Aave WMATIC token", + "origins": [ + "https://polygonscan.com/token/0x8df3aad3a84da6b69a4da8aec3ea40d9091b2ac4", + "https://www.coingecko.com/en/coins/aave-polygon-wmatic" + ], + "symbol": "amWMATIC" + }, + "dQUICK": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x958d208cdf087843e9ad98d23823d32e17d723a1", + "decimals": 18, + "name": "Dragon QUICK token", + "origins": [ + "https://polygonscan.com/token/0x958d208cdf087843e9ad98d23823d32e17d723a1", + "https://www.coingecko.com/en/exchanges/quickswap" + ], + "symbol": "dQUICK" + }, + "WETH": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x7ceb23fd6bc0add59e62ac25578270cff1b9f619", + "decimals": 18, + "name": "Wrapped ETH token", + "origins": [ + "https://polygonscan.com/token/0x7ceb23fd6bc0add59e62ac25578270cff1b9f619", + "https://www.coingecko.com/en/coins/weth" + ], + "symbol": "WETH" + }, + "RICOCHET_MATICx": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x3aD736904E9e65189c3000c7DD2c8AC8bB7cD4e3", + "decimals": 18, + "name": "Ricochet MATIC token, MATICx", + "origins": [ + "https://polygonscan.com/token/0x3aD736904E9e65189c3000c7DD2c8AC8bB7cD4e3", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "RICOCHET_MATICx" + }, + "IDEX": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x9cb74c8032b007466865f060ad2c46145d45553d", + "decimals": 18, + "name": "IDEX token", + "origins": [ + "https://polygonscan.com/token/0x9cb74c8032b007466865f060ad2c46145d45553d" + ], + "symbol": "IDEX" + }, + "RICOCHET_USDCx": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0xcaa7349cea390f89641fe306d93591f87595dc1f", + "decimals": 18, + "name": "Ricochet USDC token, USDCx", + "origins": [ + "https://polygonscan.com/token/0xcaa7349cea390f89641fe306d93591f87595dc1f", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "RICOCHET_USDCx" + }, + "TOWER": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x2bc07124d8dac638e290f401046ad584546bc47b", + "decimals": 18, + "name": "Crazy Defense Heroes game token", + "origins": [ + "https://polygonscan.com/address/0x2bc07124d8dac638e290f401046ad584546bc47b", + "https://www.coingecko.com/en/coins/tower" + ], + "symbol": "TOWER" + }, + "DAI": { + "category": "STABLECOIN", + "chain": "POLYGON", + "contractAddress": "0x8f3cf7ad23cd3cadbd9735aff958023239c6a063", + "decimals": 18, + "name": "DAI stablecoin token", + "origins": [ + "https://polygonscan.com/address/0x8f3cf7ad23cd3cadbd9735aff958023239c6a063", + "https://www.coingecko.com/en/coins/dai" + ], + "symbol": "DAI" + }, + "TITAN": { + "category": "SCAM", + "chain": "POLYGON", + "contractAddress": "0xaaa5b9e6c589642f98a1cda99b9d024b8407285a", + "decimals": 18, + "name": "IRON TITAN scam token", + "origins": [ + "https://polygonscan.com/token/0xaaa5b9e6c589642f98a1cda99b9d024b8407285a" + ], + "symbol": "TITAN" + }, + "KEK": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x42e5e06ef5b90fe15f853f59299fc96259209c5c", + "decimals": 18, + "name": "Aavegotchi KEK game token", + "origins": [ + "https://polygonscan.com/address/0x42e5e06ef5b90fe15f853f59299fc96259209c5c", + "https://www.coingecko.com/en/coins/aavegotchi-kek" + ], + "symbol": "KEK" + }, + "STARGATE_USDC_LP": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x1205f31718499dbf1fca446663b532ef87481fe1", + "decimals": 6, + "name": "StarGate USDC Pool token", + "origins": [ + "https://polygonscan.com/token/0x1205f31718499dbf1fca446663b532ef87481fe1" + ], + "symbol": "STARGATE_USDC_LP" + }, + "BGEM": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x1386617A1Bb2A6AA712AB3616bCAF1211152D1e8", + "decimals": 18, + "name": "BitGem gaming token", + "origins": [ + "https://polygonscan.com/token/0x1386617A1Bb2A6AA712AB3616bCAF1211152D1e8", + "https://boomland.io/daily" + ], + "symbol": "BGEM" + }, + "WMATIC": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270", + "decimals": 18, + "name": "WMATIC token", + "origins": [ + "https://polygonscan.com/address/0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270", + "https://www.coingecko.com/en/coins/wmatic" + ], + "symbol": "WMATIC" + }, + "rETH": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x0266f4f08d82372cf0fcbccc0ff74309089c74d1", + "decimals": 18, + "name": "Rocketpool ETH token", + "origins": [ + "https://polygonscan.com/token/0x0266f4f08d82372cf0fcbccc0ff74309089c74d1", + "https://rocketpool.net/" + ], + "symbol": "rETH" + }, + "SANDBOX_WMATIC_SAND_LP": { + "category": "LIQUIDITY_PROVIDER", + "chain": "POLYGON", + "contractAddress": "0x4ab071c42c28c4858c4bac171f06b13586b20f30", + "decimals": 18, + "name": "Sandbox WMATIC+SAND LP Token", + "origins": [ + "https://polygonscan.com/token/0x4ab071c42c28c4858c4bac171f06b13586b20f30", + "https://medium.com/sandbox-game/introducing-msand-matic-staking-at-the-sandbox-319f983d20a4" + ], + "symbol": "SANDBOX_WMATIC_SAND_LP" + }, + "TEST": { + "category": "TEST", + "chain": "POLYGON", + "contractAddress": "0x23D29D30e35C5e8D321e1dc9A8a61BFD846D4C5C", + "decimals": 18, + "name": "TEST token", + "origins": [ + "https://polygonscan.com/token/0xMOJO" + ], + "symbol": "TEST" + }, + "RICOCHET_DAIx": { + "category": "DEFI", + "chain": "POLYGON", + "contractAddress": "0x8f3cf7ad23cd3cadbd9735aff958023239c6a063", + "decimals": 18, + "name": "Ricochet DAI token, DAIx", + "origins": [ + "https://polygonscan.com/token/0x8f3cf7ad23cd3cadbd9735aff958023239c6a063", + "https://docs.superfluid.finance/superfluid/developers/networks" + ], + "symbol": "RICOCHET_DAIx" + }, + "AGHST": { + "category": "GAMING", + "chain": "POLYGON", + "contractAddress": "0x8eb270e296023e9d92081fdf967ddd7878724424", + "decimals": 18, + "name": "AAve Aavegotchi GHST game token", + "origins": [ + "https://polygonscan.com/address/0x8eb270e296023e9d92081fdf967ddd7878724424", + "https://www.coingecko.com/en/coins/aavegotchi" + ], + "symbol": "AGHST" + }, + "USDC": { + "category": "STABLECOIN", + "chain": "POLYGON", + "contractAddress": "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", + "decimals": 6, + "name": "USDC stablecoin token", + "origins": [ + "https://polygonscan.com/address/0x2791bca1f2de4661ed88a30c99a7a9449aa84174", + "https://www.coingecko.com/en/coins/usd-coin" + ], + "symbol": "USDC" + } + } +} diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..c07b2f3 --- /dev/null +++ b/pom.xml @@ -0,0 +1,236 @@ + + 4.0.0 + crypto.forestfish + forestfish + 0.0.1-SNAPSHOT + + + UTF-8 + UTF-8 + 17 + 17 + none + + + + + + maven-compiler-plugin + 3.8.1 + + 17 + 17 + + + + + + + + jitpack.io + https://jitpack.io + + + + + + github + GitHub Packages + https://maven.pkg.github.com/p00temkin/forestfish + + + + + + + + commons-codec + commons-codec + 1.16.0 + + + org.apache.commons + commons-text + 1.11.0 + + + com.google.guava + guava + 32.1.3-jre + + + org.json + json + 20231013 + + + commons-io + commons-io + 2.15.0 + + + org.apache.commons + commons-compress + 1.24.0 + + + com.fasterxml.jackson.core + jackson-databind + 2.15.3 + + + com.fasterxml.jackson.core + jackson-core + 2.15.3 + + + com.alibaba + fastjson + 2.0.42 + + + org.jsoup + jsoup + 1.16.2 + + + org.apache.commons + commons-collections4 + 4.4 + + + + + com.github.sps.pushover.net + pushover-client + 1.0.0 + + + + + org.slf4j + slf4j-api + 1.7.32 + + + ch.qos.logback + logback-classic + 1.2.11 + + + + + com.netflix.graphql.dgs + graphql-dgs-client + 7.6.0 + + + org.springframework + spring-web + 6.0.13 + + + org.springframework.boot + spring-boot-starter-web + 3.1.5 + + + org.springframework + spring-core + 6.0.13 + + + com.squareup.okio + okio + 3.6.0 + + + + + org.web3j + core + 4.10.3 + + + org.web3j + contracts + 4.10.3 + + + com.esaulpaugh + headlong + 10.0.1 + + + com.klaytn.caver + core + 1.11.1-android + + + + + org.bitcoinj + bitcoinj-core + 0.16.2 + + + + + com.github.signum-network + signumj + 1.3.0 + + + + + com.github.ipfs + java-ipfs-http-client + 1.4.4 + + + + + com.algorand + algosdk + 2.4.0 + + + com.github.ipld + java-cid + 1.3.8 + + + + + io.jsonwebtoken + jjwt-api + 0.11.5 + + + io.jsonwebtoken + jjwt-impl + 0.11.5 + runtime + + + io.jsonwebtoken + jjwt-jackson + 0.11.5 + runtime + + + com.google.code.gson + gson + 2.10.1 + + + + + junit + junit + 4.13.2 + + + + + diff --git a/src/main/java/crypto/forestfish/enums/AccountOrigin.java b/src/main/java/crypto/forestfish/enums/AccountOrigin.java new file mode 100644 index 0000000..47e3b70 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/AccountOrigin.java @@ -0,0 +1,8 @@ +package crypto.forestfish.enums; + +public enum AccountOrigin { + RECOVERY_MNEMONIC, + PRIVATEKEY, + EXISTING_LOCALWALLETFILE, + NEW_LOCALWALLETFILE +} diff --git a/src/main/java/crypto/forestfish/enums/AddressCategory.java b/src/main/java/crypto/forestfish/enums/AddressCategory.java new file mode 100644 index 0000000..24e281b --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/AddressCategory.java @@ -0,0 +1,12 @@ +package crypto.forestfish.enums; + +public enum AddressCategory { + CORE, + + EXCHANGE, + PERSONAL, + TUMBLER, + EXPOSED, + SCAM, + +} diff --git a/src/main/java/crypto/forestfish/enums/BlockchainType.java b/src/main/java/crypto/forestfish/enums/BlockchainType.java new file mode 100644 index 0000000..998aea4 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/BlockchainType.java @@ -0,0 +1,8 @@ +package crypto.forestfish.enums; + +public enum BlockchainType { + PUBLIC, + LOCAL, + ENTERPRISE, + BORKED +} diff --git a/src/main/java/crypto/forestfish/enums/CustomContractCategory.java b/src/main/java/crypto/forestfish/enums/CustomContractCategory.java new file mode 100644 index 0000000..d8fa419 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/CustomContractCategory.java @@ -0,0 +1,7 @@ +package crypto.forestfish.enums; + +public enum CustomContractCategory { + PRIVACY, + STAKING, + SCAM, +} diff --git a/src/main/java/crypto/forestfish/enums/ExceptionType.java b/src/main/java/crypto/forestfish/enums/ExceptionType.java new file mode 100644 index 0000000..e909ad7 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/ExceptionType.java @@ -0,0 +1,9 @@ +package crypto.forestfish.enums; + +public enum ExceptionType { + RECOVERABLE, + FATAL, + IGNORE, + MOVEON, + UNKNOWN +} diff --git a/src/main/java/crypto/forestfish/enums/TokenCategory.java b/src/main/java/crypto/forestfish/enums/TokenCategory.java new file mode 100644 index 0000000..2a483c9 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/TokenCategory.java @@ -0,0 +1,36 @@ +package crypto.forestfish.enums; + +public enum TokenCategory { + + // Chain + CHAINMASCOT, + + // Defi + DEFI, + GAMING, + STABLECOIN, + NFT, + GASCURRENCY, + LIQUIDITY_PROVIDER, + + // Utility + NAMESERVICE, + SUPPLYCHAIN, + MFT, + GOVERNANCE, + + // Social + SOCIAL, + GREEN, + + // Security + SCAM, + DUST, + WRECKED, + + // Misc + MISC, + MEME, + TEST, + UNKNOWN +} diff --git a/src/main/java/crypto/forestfish/enums/avm/AVMChain.java b/src/main/java/crypto/forestfish/enums/avm/AVMChain.java new file mode 100644 index 0000000..55c3bb5 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/avm/AVMChain.java @@ -0,0 +1,9 @@ +package crypto.forestfish.enums.avm; + +public enum AVMChain { + MAINNET, + TESTNET, + TESTNET_SANDBOX4001, + BETANET, + VOI_TESTNET +} diff --git a/src/main/java/crypto/forestfish/enums/avm/AVMNFTStandard.java b/src/main/java/crypto/forestfish/enums/avm/AVMNFTStandard.java new file mode 100644 index 0000000..8fa081e --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/avm/AVMNFTStandard.java @@ -0,0 +1,8 @@ +package crypto.forestfish.enums.avm; + +public enum AVMNFTStandard { + ARC3, + ARC19, + ARC69, + UNKNOWN +} diff --git a/src/main/java/crypto/forestfish/enums/avm/AVMNFTState.java b/src/main/java/crypto/forestfish/enums/avm/AVMNFTState.java new file mode 100644 index 0000000..72469fe --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/avm/AVMNFTState.java @@ -0,0 +1,6 @@ +package crypto.forestfish.enums.avm; + +public enum AVMNFTState { + MUTABLE, + IMMUTABLE, +} diff --git a/src/main/java/crypto/forestfish/enums/avm/AVMNFTType.java b/src/main/java/crypto/forestfish/enums/avm/AVMNFTType.java new file mode 100644 index 0000000..5b1c752 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/avm/AVMNFTType.java @@ -0,0 +1,6 @@ +package crypto.forestfish.enums.avm; + +public enum AVMNFTType { + PURE, + FRACTIONAL, +} diff --git a/src/main/java/crypto/forestfish/enums/avm/MainnetARC69.java b/src/main/java/crypto/forestfish/enums/avm/MainnetARC69.java new file mode 100644 index 0000000..90a9db2 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/avm/MainnetARC69.java @@ -0,0 +1,12 @@ +package crypto.forestfish.enums.avm; + +public enum MainnetARC69 { + + // Gaming + ALCH0046, // Alchemon ZIP + + // Utility + //ALGO_DOMAIN, + //UNSTOPPABLE_DOMAIN, + +} diff --git a/src/main/java/crypto/forestfish/enums/avm/MainnetASA.java b/src/main/java/crypto/forestfish/enums/avm/MainnetASA.java new file mode 100644 index 0000000..e2aa732 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/avm/MainnetASA.java @@ -0,0 +1,25 @@ +package crypto.forestfish.enums.avm; + +public enum MainnetASA { + + // Meme + COOP, + + // Green + PLANET, + + // Defi + + // LP + + // Stables + USDC, + + // MFT + OPUL, + + // Scam, dust tokens + + // Testing purposes + //TEST +} diff --git a/src/main/java/crypto/forestfish/enums/avm/TestnetASA.java b/src/main/java/crypto/forestfish/enums/avm/TestnetASA.java new file mode 100644 index 0000000..363d53b --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/avm/TestnetASA.java @@ -0,0 +1,16 @@ +package crypto.forestfish.enums.avm; + +public enum TestnetASA { + + // Defi + + // LP + + // Stables + USDC, + + // Scam, dust tokens + + // Testing purposes + //TEST +} diff --git a/src/main/java/crypto/forestfish/enums/avm/Unit.java b/src/main/java/crypto/forestfish/enums/avm/Unit.java new file mode 100644 index 0000000..e78e80a --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/avm/Unit.java @@ -0,0 +1,6 @@ +package crypto.forestfish.enums.avm; + +public enum Unit { + ALGO, + microAlgo +} diff --git a/src/main/java/crypto/forestfish/enums/evm/ArbitrumONEERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/ArbitrumONEERC20Token.java new file mode 100644 index 0000000..24cb650 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/ArbitrumONEERC20Token.java @@ -0,0 +1,34 @@ +package crypto.forestfish.enums.evm; + +public enum ArbitrumONEERC20Token { + + // Defi + GMX, + GNS, + rETH, + BAL, + AURA, + + // Governance + ARBITRUM, + + // LP + BAL_MAGICUSDC_LP, + + // Game + MAGIC, + DMT, + + // Stables + USDC, + USDCe, + USDT, + DAI, + gDAI, + + // Meme + + // Scam, dust tokens + + // Testing purposes +} diff --git a/src/main/java/crypto/forestfish/enums/evm/ArbitrumONEERC721Token.java b/src/main/java/crypto/forestfish/enums/evm/ArbitrumONEERC721Token.java new file mode 100644 index 0000000..879c341 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/ArbitrumONEERC721Token.java @@ -0,0 +1,7 @@ +package crypto.forestfish.enums.evm; + +public enum ArbitrumONEERC721Token { + + // Gaming + TREASURETAG, +} diff --git a/src/main/java/crypto/forestfish/enums/evm/AvaxERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/AvaxERC20Token.java new file mode 100644 index 0000000..eb11154 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/AvaxERC20Token.java @@ -0,0 +1,20 @@ +package crypto.forestfish.enums.evm; + +public enum AvaxERC20Token { + + // Defi + STG, + PNG, + + // LP + + // Stables + USDT, + USDC, + DAI, + + // Scam, dust tokens + + // Testing purposes + TEST +} diff --git a/src/main/java/crypto/forestfish/enums/evm/BSCBEP20Token.java b/src/main/java/crypto/forestfish/enums/evm/BSCBEP20Token.java new file mode 100644 index 0000000..346c782 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/BSCBEP20Token.java @@ -0,0 +1,51 @@ +package crypto.forestfish.enums.evm; + +public enum BSCBEP20Token { + + // Currency/gas + METIS, + + // Defi + STG, + CAKE, + BABYCAKE, + XVS, + VIKINGSWAP, + + // Game + SUPS, + MOBOX, + GQ, + PLU, + VAN, + CAR, + NIC, + MET, + ACE, + ARG, + COP, + IRON, + SCK, + CHMB, + XWG, + SFTY, + + // NFT + CATGIRL, + NFTART, + + // Liquidity, + STARGATE_BUSD_LP, + + // Stables + USDT, + USDC, + DAI, + BUSD, + + // Scam, dust tokens + TRON, + + // Testing purposes + TEST +} diff --git a/src/main/java/crypto/forestfish/enums/evm/BSCERC721Token.java b/src/main/java/crypto/forestfish/enums/evm/BSCERC721Token.java new file mode 100644 index 0000000..1af1210 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/BSCERC721Token.java @@ -0,0 +1,13 @@ +package crypto.forestfish.enums.evm; + +public enum BSCERC721Token { + + // Gaming + OUTERRINGMMO_WEAPON, + OUTERRINGMMO_ARMOR, + OUTERRINGMMO_LANDVEH, + OUTERRINGMMO_SPACEVEH, + OUTERRINGMMO_EXOCRED, + DREAMCARD, + STELLAFANTASY_ASSET +} diff --git a/src/main/java/crypto/forestfish/enums/evm/BaseERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/BaseERC20Token.java new file mode 100644 index 0000000..3d65bba --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/BaseERC20Token.java @@ -0,0 +1,24 @@ +package crypto.forestfish.enums.evm; + +public enum BaseERC20Token { + + // Defi + WETH, + AERO, + + // LP + AERODOME_DAI_WETH_LP, + AERODOME_AERO_WETH_LP, + + // Stables + DAI, + USDC, + USDbC + + // Gaming + + // Scam, dust tokens + + // Testing purposes + //TEST +} diff --git a/src/main/java/crypto/forestfish/enums/evm/BitkubERC721Token.java b/src/main/java/crypto/forestfish/enums/evm/BitkubERC721Token.java new file mode 100644 index 0000000..da5e0b2 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/BitkubERC721Token.java @@ -0,0 +1,10 @@ +package crypto.forestfish.enums.evm; + +public enum BitkubERC721Token { + + // Gaming + MMV_ITEM, + + // NFT, + SANDX, +} diff --git a/src/main/java/crypto/forestfish/enums/evm/BitkubKAP20Token.java b/src/main/java/crypto/forestfish/enums/evm/BitkubKAP20Token.java new file mode 100644 index 0000000..7c0304b --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/BitkubKAP20Token.java @@ -0,0 +1,43 @@ +package crypto.forestfish.enums.evm; + +public enum BitkubKAP20Token { + + // Defi + KKUB, + + // LP + MMV_DIAMON_LP, + + // Stables + USDT, + + // Gaming + MMV_WBUTTON_MUSHROOM, + MMV_SHITAKE_MUSHROOM, + MMV_KTRUMPET_MUSHROOM, + MMV_TOMATOSOUP, + MMV_TOMATOSEED, + MMV_SF_CABBAGE, + MMV_SILVERKEY, + MMV_SALAD, + MMV_HONEY, + MMV_GREENAPPLE, + MMV_DRIEDAPPLE, + MMV_LUMI, + MMV_CORNSOUP, + MMV_CORNSEED, + MMV_CARROTSEED, + MMV_CABBAGESEED, + MMV_BANANA, + MMV_GREENHERB, + MMV_REDHERB, + MMV_LHEALTHPOTION, + MMV_HEALTHPOTION, + MMV_LEATHER_PIECE, + MMV_RAG, + + // Scam, dust tokens + + // Testing purposes + TEST +} diff --git a/src/main/java/crypto/forestfish/enums/evm/BoraChainKIP7Token.java b/src/main/java/crypto/forestfish/enums/evm/BoraChainKIP7Token.java new file mode 100644 index 0000000..1bfa7a9 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/BoraChainKIP7Token.java @@ -0,0 +1,20 @@ +package crypto.forestfish.enums.evm; + +public enum BoraChainKIP7Token { + + // https://kips.klaytn.foundation/KIPs/kip-7 + + tBORA, + + // Game + BSLT, + + // NFT + + // Stables + + // Scam, dust tokens + + // Testing purposes + TEST +} diff --git a/src/main/java/crypto/forestfish/enums/evm/CeloERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/CeloERC20Token.java new file mode 100644 index 0000000..51e16f9 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/CeloERC20Token.java @@ -0,0 +1,19 @@ +package crypto.forestfish.enums.evm; + +public enum CeloERC20Token { + + // Defi + + // Game + + // NFT + + // Stables + cUSD, + + // Scam, dust tokens + ZEROCASINO, + + // Testing purposes + TEST +} diff --git a/src/main/java/crypto/forestfish/enums/evm/ConfluxERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/ConfluxERC20Token.java new file mode 100644 index 0000000..7e11f83 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/ConfluxERC20Token.java @@ -0,0 +1,20 @@ +package crypto.forestfish.enums.evm; + +public enum ConfluxERC20Token { + + // Defi + WCFX, + PPI, + vePPI, + + // LP + SWAPPI_CFX_PPI_LP, + + // Stables + USDT, + + // Scam, dust tokens + + // Testing purposes + //TEST +} diff --git a/src/main/java/crypto/forestfish/enums/evm/ConfluxTestnetERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/ConfluxTestnetERC20Token.java new file mode 100644 index 0000000..af5d4ee --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/ConfluxTestnetERC20Token.java @@ -0,0 +1,19 @@ +package crypto.forestfish.enums.evm; + +public enum ConfluxTestnetERC20Token { + + // Defi + VSWAP, + WETH, + + // LP + + // Stables + USDT, + USDC, + + // Scam, dust tokens + + // Testing purposes + //TEST +} diff --git a/src/main/java/crypto/forestfish/enums/evm/CoreERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/CoreERC20Token.java new file mode 100644 index 0000000..c4f2c93 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/CoreERC20Token.java @@ -0,0 +1,16 @@ +package crypto.forestfish.enums.evm; + +public enum CoreERC20Token { + + // Defi + + // LP + + // Stables + USDT, + + // Scam, dust tokens + + // Testing purposes + //TEST +} diff --git a/src/main/java/crypto/forestfish/enums/evm/EVMChain.java b/src/main/java/crypto/forestfish/enums/evm/EVMChain.java new file mode 100644 index 0000000..0c77449 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/EVMChain.java @@ -0,0 +1,120 @@ +package crypto.forestfish.enums.evm; + +public enum EVMChain { + + // Main nets + ETHEREUM, + POLYGON, + BSC, + METIS, + AURORA, + BITKUB, + FANTOM, + CRONOS, + BOBA, + MOONBEAM, + MOONRIVER, + KLAYTN, + BASE, + BORACHAIN, + CELO, + AVAX, + ETHO, + EVMOS, + ASTAR, + HARMONY, + ARBITRUMONE, + WEMIX, + MILKOMEDAA1, + MILKOMEDAC1, + SYSCOIN, + CANTO, + OASISCHAIN, + OASISEMERALD, + OASISSAPPHIRE, + ZKSYNCERA, + ZKEVM, + PULSECHAIN, + KAVA, + CONFLUX, + CORE, + FUSE, + LUKSO, + KARURA, + KARDIACHAIN, + ETHW, + LINEA, + OPTIMISM, + TARAXA, + TENET, + TOMOCHAIN, + SATOSHICHAIN, + ZORA, + SCROLL, + OPBNB, + MANTLE, + + // Test nets + SHARDEUMLIBERTY1xTEST, + SHARDEUMLIBERTY2xTEST, + SHARDEUMSPHINX1xTEST, + CRONOSTEST, + SHIBUYATEST, + EVMOSTEST, + ROPSTENTEST, + SEPOLIATEST, + MUMBAITEST, + RINKEBYTEST, + GOERLITEST, + ARBITRUMGOERLITEST, + TAIKOALPHATEST, + TAIKOALPHA2TEST, + TAIKOALPHA3TEST, + FUJITEST, + KOVANTEST, + BOBARINKEBYTEST, + BOBABNBTEST, + ZKSYNCERATEST, + BSCTEST, + METISSTARDUSTTEST, + FANTOMTEST, + MILKOMEDAA1TEST, + CANTOTEST, + OASISEMERALDTEST, + OASISSAPPHIRETEST, + BASETEST, + ETHOTEST, + ZKEVMTEST, + SATOSHICHAINTEST, + LINEATEST, + SCROLLALPHATEST, + SCROLLSEPOLIATEST, + KAVATEST, + ZETAATHENSTEST, + CONFLUXTEST, + MODETEST, + OPTIMISMGOERLITEST, + CORETEST, + FUSESPARKTEST, + LUKSOTEST, + KARURATEST, + TARAXATEST, + TENETTEST, + BITKUBTEST, + TOMOCHAINTEST, + AURORATEST, + ZORATEST, + OPBNBTEST, + MANTLETEST, + + // Beta nets + LAMINA1BETATEST, + + // Local dev envs + GANACHE8545_5777, + GANACHE7545_5777, + GANACHE8545_1337, + GANACHE7545_1337, + HARDHAT8545_31337, + HARDHAT443_31337 +} diff --git a/src/main/java/crypto/forestfish/enums/evm/EVMPriceMechanism.java b/src/main/java/crypto/forestfish/enums/evm/EVMPriceMechanism.java new file mode 100644 index 0000000..bb6362f --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/EVMPriceMechanism.java @@ -0,0 +1,6 @@ +package crypto.forestfish.enums.evm; + +public enum EVMPriceMechanism { + LEGACY, + EIP1559 +} diff --git a/src/main/java/crypto/forestfish/enums/evm/EthereumERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/EthereumERC20Token.java new file mode 100644 index 0000000..2c3e6e4 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/EthereumERC20Token.java @@ -0,0 +1,39 @@ +package crypto.forestfish.enums.evm; + +public enum EthereumERC20Token { + + // Misc + SOS, + XOR, + + // Defi, + UNIDX, + SERUM, + + // Meme + DINU, + JINDOGE, + NB, + DOJO, + SHUSHKY, + JSHIBA, + DOBE, + CULT, + + // Social + FWB, + + // Stables + USDT, + USDC, + DAI, + + // Utility + TRAC, + + // Gaming + APECOIN, + VIDYA, + + TEST, +} diff --git a/src/main/java/crypto/forestfish/enums/evm/EthereumERC721Token.java b/src/main/java/crypto/forestfish/enums/evm/EthereumERC721Token.java new file mode 100644 index 0000000..9767a32 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/EthereumERC721Token.java @@ -0,0 +1,14 @@ +package crypto.forestfish.enums.evm; + +public enum EthereumERC721Token { + + // Gaming + LUCHADORES, + WWW_LAND, + BORED_APE, + + // Utility + ENS_DOMAIN, + UNSTOPPABLE_DOMAIN, + +} diff --git a/src/main/java/crypto/forestfish/enums/evm/FantomERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/FantomERC20Token.java new file mode 100644 index 0000000..d2a1148 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/FantomERC20Token.java @@ -0,0 +1,21 @@ +package crypto.forestfish.enums.evm; + +public enum FantomERC20Token { + + // Defi + STG, + MULTI, + + // LP + SPOOKYSWAP_FTM_MULTI_LP, + + // Stables + USDT, + USDC, + DAI, + + // Scam, dust tokens + + // Testing purposes + TEST +} diff --git a/src/main/java/crypto/forestfish/enums/evm/GoerliERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/GoerliERC20Token.java new file mode 100644 index 0000000..5e506e5 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/GoerliERC20Token.java @@ -0,0 +1,21 @@ +package crypto.forestfish.enums.evm; + +public enum GoerliERC20Token { + + // Defi + WETH, + ZETA, + + // Chains + MNT, + + // Stablecoins + DAI, + USDC, + + // Testing purposes + TST4, // Goerli official test token (ERC20-Testv4) + TSTv4, + + TEST +} diff --git a/src/main/java/crypto/forestfish/enums/evm/GoerliERC721Token.java b/src/main/java/crypto/forestfish/enums/evm/GoerliERC721Token.java new file mode 100644 index 0000000..c38a4bb --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/GoerliERC721Token.java @@ -0,0 +1,7 @@ +package crypto.forestfish.enums.evm; + +public enum GoerliERC721Token { + + // NFT, + MFNFT, +} diff --git a/src/main/java/crypto/forestfish/enums/evm/KavaTestERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/KavaTestERC20Token.java new file mode 100644 index 0000000..0dccd8e --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/KavaTestERC20Token.java @@ -0,0 +1,19 @@ +package crypto.forestfish.enums.evm; + +public enum KavaTestERC20Token { + + // Defi + + // LP + + // Game + + // Stables + USDC, + + // Meme + + // Scam, dust tokens + + // Testing purposes +} diff --git a/src/main/java/crypto/forestfish/enums/evm/KlaytnKIP7Token.java b/src/main/java/crypto/forestfish/enums/evm/KlaytnKIP7Token.java new file mode 100644 index 0000000..e672c3f --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/KlaytnKIP7Token.java @@ -0,0 +1,22 @@ +package crypto.forestfish.enums.evm; + +public enum KlaytnKIP7Token { + + // https://kips.klaytn.foundation/KIPs/kip-7 + + // Defi + KSP, + + // Game + WEMIX, + BORA, + + // NFT + + // Stables + + // Scam, dust tokens + + // Testing purposes + TEST +} diff --git a/src/main/java/crypto/forestfish/enums/evm/LineaERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/LineaERC20Token.java new file mode 100644 index 0000000..bd96b58 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/LineaERC20Token.java @@ -0,0 +1,23 @@ +package crypto.forestfish.enums.evm; + +public enum LineaERC20Token { + + // Defi + WETH, + MATIC, + LVC, + veLVC, + + // LP + + // Game + + // Stables + USDC, + + // Meme + + // Scam, dust tokens + + // Testing purposes +} diff --git a/src/main/java/crypto/forestfish/enums/evm/LineaERC721Token.java b/src/main/java/crypto/forestfish/enums/evm/LineaERC721Token.java new file mode 100644 index 0000000..d865358 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/LineaERC721Token.java @@ -0,0 +1,11 @@ +package crypto.forestfish.enums.evm; + +public enum LineaERC721Token { + + // Gaming + BATTLEMON_PAXE, + BATTLEMON_LGEM, + + // LP + HRZNLP, +} diff --git a/src/main/java/crypto/forestfish/enums/evm/MantleERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/MantleERC20Token.java new file mode 100644 index 0000000..80ecae7 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/MantleERC20Token.java @@ -0,0 +1,18 @@ +package crypto.forestfish.enums.evm; + +public enum MantleERC20Token { + + // Defi + WETH, + + // LP + + // Stables + USDT, + USDC, + + // Scam, dust tokens + + // Testing purposes + //TEST +} diff --git a/src/main/java/crypto/forestfish/enums/evm/MantleERC721Token.java b/src/main/java/crypto/forestfish/enums/evm/MantleERC721Token.java new file mode 100644 index 0000000..8182c0f --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/MantleERC721Token.java @@ -0,0 +1,9 @@ +package crypto.forestfish.enums.evm; + +public enum MantleERC721Token { + + // Chain mascot + CITIZEN, + + // LP +} diff --git a/src/main/java/crypto/forestfish/enums/evm/MantleTestnetERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/MantleTestnetERC20Token.java new file mode 100644 index 0000000..e18c651 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/MantleTestnetERC20Token.java @@ -0,0 +1,18 @@ +package crypto.forestfish.enums.evm; + +public enum MantleTestnetERC20Token { + + // Defi + WETH, + + // LP + + // Stables + USDT, + USDC, + + // Scam, dust tokens + + // Testing purposes + //TEST +} diff --git a/src/main/java/crypto/forestfish/enums/evm/MetisERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/MetisERC20Token.java new file mode 100644 index 0000000..d64bd69 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/MetisERC20Token.java @@ -0,0 +1,22 @@ +package crypto.forestfish.enums.evm; + +public enum MetisERC20Token { + + // Defi + WETH, + + // Game + + // NFT + + // Liquidity, + HERMES_M_USDC_LP, + + // Stables + USDT, + USDC, + + // Scam, dust tokens + + // Testing purposes +} diff --git a/src/main/java/crypto/forestfish/enums/evm/MilkomedaA1ERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/MilkomedaA1ERC20Token.java new file mode 100644 index 0000000..728844f --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/MilkomedaA1ERC20Token.java @@ -0,0 +1,20 @@ +package crypto.forestfish.enums.evm; + +public enum MilkomedaA1ERC20Token { + + // Defi + BLUES, + + // LP + + // Game + + // Stables + USDC, + + // Meme + + // Scam, dust tokens + + // Testing purposes +} diff --git a/src/main/java/crypto/forestfish/enums/evm/MilkomedaC1ERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/MilkomedaC1ERC20Token.java new file mode 100644 index 0000000..cea6546 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/MilkomedaC1ERC20Token.java @@ -0,0 +1,21 @@ +package crypto.forestfish.enums.evm; + +public enum MilkomedaC1ERC20Token { + + // Defi + WADA, + BLUES, + + // LP + BLUESHIFT_mADA_BLUES_LP, + + // Game + + // Stables + + // Meme + + // Scam, dust tokens + + // Testing purposes +} diff --git a/src/main/java/crypto/forestfish/enums/evm/MilkomedaC1ERC721Token.java b/src/main/java/crypto/forestfish/enums/evm/MilkomedaC1ERC721Token.java new file mode 100644 index 0000000..f6c2c42 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/MilkomedaC1ERC721Token.java @@ -0,0 +1,8 @@ +package crypto.forestfish.enums.evm; + +public enum MilkomedaC1ERC721Token { + + // Gaming + PAIMA_VOLCANEERS, + +} diff --git a/src/main/java/crypto/forestfish/enums/evm/MoonbeamERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/MoonbeamERC20Token.java new file mode 100644 index 0000000..59a7889 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/MoonbeamERC20Token.java @@ -0,0 +1,17 @@ +package crypto.forestfish.enums.evm; + +public enum MoonbeamERC20Token { + + // Defi + mGLMR, + WELL, + + // LP + + // Stables + + // Scam, dust tokens + + // Testing purposes + //TEST +} diff --git a/src/main/java/crypto/forestfish/enums/evm/MoonbeamERC721Token.java b/src/main/java/crypto/forestfish/enums/evm/MoonbeamERC721Token.java new file mode 100644 index 0000000..8f2481f --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/MoonbeamERC721Token.java @@ -0,0 +1,7 @@ +package crypto.forestfish.enums.evm; + +public enum MoonbeamERC721Token { + + // Gaming + SNAKESOLDIERS +} diff --git a/src/main/java/crypto/forestfish/enums/evm/MumbaiERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/MumbaiERC20Token.java new file mode 100644 index 0000000..8c4688f --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/MumbaiERC20Token.java @@ -0,0 +1,22 @@ +package crypto.forestfish.enums.evm; + +public enum MumbaiERC20Token { + + // Defi + LINK, + RICOCHET_MATICx, + RICOCHET_fUSDCx, + RICOCHET_fTUSDx, + RICOCHET_fDAIx, + + // Stablecoins + fUSDC, + fTUSD, + fDAI, + + // Testing purposes + TST, // Mumbai official test token (PLASMA) + DERC20, // Mumbai official test token (PoS) + + TEST +} diff --git a/src/main/java/crypto/forestfish/enums/evm/OptimismERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/OptimismERC20Token.java new file mode 100644 index 0000000..86a682e --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/OptimismERC20Token.java @@ -0,0 +1,19 @@ +package crypto.forestfish.enums.evm; + +public enum OptimismERC20Token { + + // Defi + SNX, + SDS, + + // LP + + // Stables + //USDT, + SUSD, + + // Scam, dust tokens + + // Testing purposes + //TEST +} diff --git a/src/main/java/crypto/forestfish/enums/evm/PolygonERC1155Token.java b/src/main/java/crypto/forestfish/enums/evm/PolygonERC1155Token.java new file mode 100644 index 0000000..1859639 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/PolygonERC1155Token.java @@ -0,0 +1,5 @@ +package crypto.forestfish.enums.evm; + +public enum PolygonERC1155Token { + AAVEGOTCHI_INSTALLATION, +} diff --git a/src/main/java/crypto/forestfish/enums/evm/PolygonERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/PolygonERC20Token.java new file mode 100644 index 0000000..95a8520 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/PolygonERC20Token.java @@ -0,0 +1,59 @@ +package crypto.forestfish.enums.evm; + +public enum PolygonERC20Token { + + // Defi + IDEX, + TITAN, + MOD, + STG, + WETH, + rETH, + LINK, + amLINK, + amWMATIC, + WMATIC, + SYNAPSE, + RICOCHET, + RICOCHET_USDCx, + RICOCHET_MATICx, + RICOCHET_ETHx, + RICOCHET_DAIx, + RICOCHET_WBTCx, + VRSW, + dQUICK, + MATICX, + + // LP + SANDBOX_WMATIC_SAND_LP, + STARGATE_USDC_LP, + QUICKSWAP_aWMATIC_GHST_LP, + + // Game + GHST, + AGHST, + KEK, + GLTR, + ALPHA, + FOMO, + FUD, + SAND, + LUCHA, + TOWER, + BGEM, + + // Stables + USDT, + USDC, + DAI, + gDAI, + + // Meme + CXDOGE, + + // Scam, dust tokens + ROLL, + + // Testing purposes + TEST +} diff --git a/src/main/java/crypto/forestfish/enums/evm/PolygonERC721Token.java b/src/main/java/crypto/forestfish/enums/evm/PolygonERC721Token.java new file mode 100644 index 0000000..f524803 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/PolygonERC721Token.java @@ -0,0 +1,27 @@ +package crypto.forestfish.enums.evm; + +public enum PolygonERC721Token { + + // Gaming + AAVEGOTCHI, + AAVEGOTCHI_LAND, + AAVEGOTCHI_GMI, + SANDBOX_LAND, + UNIOVERSE, + MYCRYPTOHEROES, + + // Defi, + UNISWAPV3_POSITION, + + // Social + LENSPROTOCOLPROFILE, + TRUMP, + + // NFT, + UAPX_ALIEN, + UAPX_SHIP, + UAPX_SONG, + + // Utility + UNSTOPPABLE_DOMAIN, +} diff --git a/src/main/java/crypto/forestfish/enums/evm/PulsechainERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/PulsechainERC20Token.java new file mode 100644 index 0000000..e38cc3a --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/PulsechainERC20Token.java @@ -0,0 +1,19 @@ +package crypto.forestfish.enums.evm; + +public enum PulsechainERC20Token { + + // Defi + PLSX, + + // LP + + // Game + + // Stables + + // Meme + + // Scam, dust tokens + + // Testing purposes +} diff --git a/src/main/java/crypto/forestfish/enums/evm/ScrollERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/ScrollERC20Token.java new file mode 100644 index 0000000..58fbf47 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/ScrollERC20Token.java @@ -0,0 +1,22 @@ +package crypto.forestfish.enums.evm; + +public enum ScrollERC20Token { + + // Defi + //WETH, + PAPYRUS, + gPAPYRUS, + + // LP + + // Game + + // Stables + USDC, + + // Meme + + // Scam, dust tokens + + // Testing purposes +} diff --git a/src/main/java/crypto/forestfish/enums/evm/WemixERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/WemixERC20Token.java new file mode 100644 index 0000000..d54cef5 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/WemixERC20Token.java @@ -0,0 +1,20 @@ +package crypto.forestfish.enums.evm; + +public enum WemixERC20Token { + + // Defi + KLAY, + + // LP + + // Game + + // Stables + WEMIX$, + + // Meme + + // Scam, dust tokens + + // Testing purposes +} diff --git a/src/main/java/crypto/forestfish/enums/evm/ZKEVMERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/ZKEVMERC20Token.java new file mode 100644 index 0000000..c918602 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/ZKEVMERC20Token.java @@ -0,0 +1,22 @@ +package crypto.forestfish.enums.evm; + +public enum ZKEVMERC20Token { + + // Defi + + // LP + GAMMA_aUSDC_DAI_LP, + + // Game + + // Stables + USDC, + USDT, + DAI, + + // Meme + + // Scam, dust tokens + + // Testing purposes +} diff --git a/src/main/java/crypto/forestfish/enums/evm/ZKSyncEraERC721Token.java b/src/main/java/crypto/forestfish/enums/evm/ZKSyncEraERC721Token.java new file mode 100644 index 0000000..a6a33a8 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/ZKSyncEraERC721Token.java @@ -0,0 +1,10 @@ +package crypto.forestfish.enums.evm; + +public enum ZKSyncEraERC721Token { + + // Social + ZKAPE, + + // Utility + ERANAMESERVICE +} diff --git a/src/main/java/crypto/forestfish/enums/evm/ZkSyncERC20Token.java b/src/main/java/crypto/forestfish/enums/evm/ZkSyncERC20Token.java new file mode 100644 index 0000000..b120422 --- /dev/null +++ b/src/main/java/crypto/forestfish/enums/evm/ZkSyncERC20Token.java @@ -0,0 +1,26 @@ +package crypto.forestfish.enums.evm; + +public enum ZkSyncERC20Token { + + // Defi + MUTE, + COMBO, + PERP, + YSYNC, + VC, + + // LP + SYNCSWAP_USDC_WETH_LP, + + // Stables + USDC, + zkUSD, + + // Gaming + ZAT, + + // Scam, dust tokens + + // Testing purposes + //TEST +} diff --git a/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Request_authenticate.java b/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Request_authenticate.java new file mode 100644 index 0000000..1e8150e --- /dev/null +++ b/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Request_authenticate.java @@ -0,0 +1,53 @@ +package crypto.forestfish.forestfishd.api.v1; + +public class ForestFishV1Request_authenticate { + + private String version = "v1"; + private String challenge = ""; + private String signature = ""; + private String address = ""; + + public ForestFishV1Request_authenticate() { + super(); + } + + public ForestFishV1Request_authenticate(String challenge, String signature, String address) { + super(); + this.challenge = challenge; + this.signature = signature; + this.address = address; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getChallenge() { + return challenge; + } + + public void setChallenge(String challenge) { + this.challenge = challenge; + } + + public String getSignature() { + return signature; + } + + public void setSignature(String signature) { + this.signature = signature; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + +} diff --git a/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Request_knockknock.java b/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Request_knockknock.java new file mode 100644 index 0000000..3dd0910 --- /dev/null +++ b/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Request_knockknock.java @@ -0,0 +1,33 @@ +package crypto.forestfish.forestfishd.api.v1; + +public class ForestFishV1Request_knockknock { + + private String version = "v1"; + private String address = ""; + + public ForestFishV1Request_knockknock() { + super(); + } + + public ForestFishV1Request_knockknock(String _address) { + super(); + this.address = _address; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + +} diff --git a/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Response_authenticate.java b/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Response_authenticate.java new file mode 100644 index 0000000..4e43da6 --- /dev/null +++ b/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Response_authenticate.java @@ -0,0 +1,73 @@ +package crypto.forestfish.forestfishd.api.v1; + +public class ForestFishV1Response_authenticate { + + private String version = "v1"; + private String address = ""; + private boolean success = false; + private int authcode = 404; + private String authmessage = ""; + private String jwtToken = ""; + + public ForestFishV1Response_authenticate() { + super(); + } + + public ForestFishV1Response_authenticate(String _address, boolean _success, int _authcode, String _authmessage, String _jwtToken) { + super(); + this.address = _address; + this.success = _success; + this.authcode = _authcode; + this.authmessage = _authmessage; + this.jwtToken = _jwtToken; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public String getJwtToken() { + return jwtToken; + } + + public void setJwtToken(String jwtToken) { + this.jwtToken = jwtToken; + } + + public String getAuthmessage() { + return authmessage; + } + + public void setAuthmessage(String authmessage) { + this.authmessage = authmessage; + } + + public int getAuthcode() { + return authcode; + } + + public void setAuthcode(int authcode) { + this.authcode = authcode; + } + +} diff --git a/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Response_challenge.java b/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Response_challenge.java new file mode 100644 index 0000000..290483b --- /dev/null +++ b/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Response_challenge.java @@ -0,0 +1,53 @@ +package crypto.forestfish.forestfishd.api.v1; + +public class ForestFishV1Response_challenge { + + private String version = "v1"; + private String challenge = ""; + private String address = ""; + private boolean valid = false; + + public ForestFishV1Response_challenge() { + super(); + } + + public ForestFishV1Response_challenge(String address, String challenge, Boolean valid) { + super(); + this.address = address; + this.challenge = challenge; + this.valid = valid; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getChallenge() { + return challenge; + } + + public void setChallenge(String challenge) { + this.challenge = challenge; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public boolean isValid() { + return valid; + } + + public void setValid(boolean valid) { + this.valid = valid; + } + +} diff --git a/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Response_knockknock.java b/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Response_knockknock.java new file mode 100644 index 0000000..394835c --- /dev/null +++ b/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Response_knockknock.java @@ -0,0 +1,83 @@ +package crypto.forestfish.forestfishd.api.v1; + +public class ForestFishV1Response_knockknock { + + private String version = "v1"; + private String wallet = ""; + private String ip = ""; + private String cc = ""; + private String msg = ""; + private Boolean preregistered = false; + private String role = ""; + + public ForestFishV1Response_knockknock() { + super(); + } + + public ForestFishV1Response_knockknock(String _wallet, String _ip, String _cc, String _msg, Boolean _preregistered, String _role) { + super(); + this.wallet = _wallet; + this.ip = _ip; + this.cc = _cc; + this.msg = _msg; + this.preregistered = _preregistered; + this.role = _role; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public String getWallet() { + return wallet; + } + + public void setWallet(String wallet) { + this.wallet = wallet; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getCc() { + return cc; + } + + public void setCc(String cc) { + this.cc = cc; + } + + public Boolean getPreregistered() { + return preregistered; + } + + public void setPreregistered(Boolean preregistered) { + this.preregistered = preregistered; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } + +} diff --git a/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Response_protectedcontent.java b/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Response_protectedcontent.java new file mode 100644 index 0000000..7f25a4a --- /dev/null +++ b/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Response_protectedcontent.java @@ -0,0 +1,63 @@ +package crypto.forestfish.forestfishd.api.v1; + +public class ForestFishV1Response_protectedcontent { + + private String version = "v1"; + private String contentid = ""; + private String contenttype = "text/html"; + private String content = ""; + private boolean valid = false; + + public ForestFishV1Response_protectedcontent() { + super(); + } + + public ForestFishV1Response_protectedcontent(String contentid, String contenttype, String content, boolean valid) { + super(); + this.contentid = contentid; + this.contenttype = contenttype; + this.content = content; + this.valid = valid; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getContentid() { + return contentid; + } + + public void setContentid(String contentid) { + this.contentid = contentid; + } + + public String getContenttype() { + return contenttype; + } + + public void setContenttype(String contenttype) { + this.contenttype = contenttype; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public boolean isValid() { + return valid; + } + + public void setValid(boolean valid) { + this.valid = valid; + } + +} diff --git a/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Response_status.java b/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Response_status.java new file mode 100644 index 0000000..8035a5a --- /dev/null +++ b/src/main/java/crypto/forestfish/forestfishd/api/v1/ForestFishV1Response_status.java @@ -0,0 +1,29 @@ +package crypto.forestfish.forestfishd.api.v1; + +public class ForestFishV1Response_status { + + private String version = "v1"; + private String status = "up"; + + public ForestFishV1Response_status() { + super(); + } + + public ForestFishV1Response_status(String status) { + this.status = status; + } + + public String getVersion() { + return version; + } + public void setVersion(String version) { + this.version = version; + } + public String getStatus() { + return status; + } + public void setStatus(String status) { + this.status = status; + } + +} diff --git a/src/main/java/crypto/forestfish/forestfishd/model/policy/Policy.java b/src/main/java/crypto/forestfish/forestfishd/model/policy/Policy.java new file mode 100644 index 0000000..703d7e1 --- /dev/null +++ b/src/main/java/crypto/forestfish/forestfishd/model/policy/Policy.java @@ -0,0 +1,73 @@ +package crypto.forestfish.forestfishd.model.policy; + +import java.util.HashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import crypto.forestfish.enums.evm.EVMChain; + +public class Policy { + + @SuppressWarnings("unused") + private static final Logger LOGGER = LoggerFactory.getLogger(Policy.class); + + @SuppressWarnings("serial") + private HashMap blockchains_enabled = new HashMap() {{ + this.put(EVMChain.POLYGON.toString(), true); + this.put(EVMChain.ETHEREUM.toString(), true); + }}; + + // geoip access policy + @SuppressWarnings("serial") + private HashMap allowedCC = new HashMap<>() {{ + this.put("ALL", true); // no restriction + + // Examples + //this.put("LOCALHOST", true); + //this.put("RFC1918", true); + //this.put("US", true); + + }}; + + private HashMap accounts = new HashMap<>(); + + public Policy() { + super(); + } + + public HashMap getBlockchains_enabled() { + return blockchains_enabled; + } + + public void setBlockchains_enabled(HashMap blockchains_enabled) { + this.blockchains_enabled = blockchains_enabled; + } + + public HashMap getAccounts() { + return accounts; + } + + public void setAccounts(HashMap accounts) { + this.accounts = accounts; + } + + public HashMap getAllowedCC() { + return allowedCC; + } + + public void setAllowedCC(HashMap allowedCC) { + this.allowedCC = allowedCC; + } + + public void update() { + // Make sure we handle all accounts in lowercase + HashMap accounts_lc = new HashMap<>(); + for (String address: accounts.keySet()) { + Role r = accounts.get(address); + accounts_lc.put(address.toLowerCase(), r); + } + this.accounts = accounts_lc; + } + +} diff --git a/src/main/java/crypto/forestfish/forestfishd/model/policy/Role.java b/src/main/java/crypto/forestfish/forestfishd/model/policy/Role.java new file mode 100644 index 0000000..4d4d4a8 --- /dev/null +++ b/src/main/java/crypto/forestfish/forestfishd/model/policy/Role.java @@ -0,0 +1,8 @@ +package crypto.forestfish.forestfishd.model.policy; + +public enum Role { + CONSUMER, + CONTRIBUTOR, + ADMIN, + UNDEFINED +} \ No newline at end of file diff --git a/src/main/java/crypto/forestfish/objects/avm/AVMASAMutables.java b/src/main/java/crypto/forestfish/objects/avm/AVMASAMutables.java new file mode 100644 index 0000000..06cdf25 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AVMASAMutables.java @@ -0,0 +1,92 @@ +package crypto.forestfish.objects.avm; + +import com.algorand.algosdk.crypto.Address; + +public class AVMASAMutables { + + private Address manager = null; + private Address reserve = null; + private Address freeze = null; + private Address clawback = null; + + public AVMASAMutables(Address manager, Address reserve, Address freeze, Address clawback) { + super(); + this.manager = manager; + this.reserve = reserve; + this.freeze = freeze; + this.clawback = clawback; + } + + public Address getManager() { + return manager; + } + + public void setManager(Address manager) { + this.manager = manager; + } + + public Address getReserve() { + return reserve; + } + + public void setReserve(Address reserve) { + this.reserve = reserve; + } + + public Address getFreeze() { + return freeze; + } + + public void setFreeze(Address freeze) { + this.freeze = freeze; + } + + public Address getClawback() { + return clawback; + } + + public void setClawback(Address clawback) { + this.clawback = clawback; + } + + public void printStatus() { + + if (null == this.manager) { + System.out.println("manager : "); + } else { + System.out.println("manager : " + this.manager); + } + + if (null == this.reserve) { + System.out.println("reserve : "); + } else { + System.out.println("reserve : " + this.reserve); + } + + if (null == this.freeze) { + System.out.println("freeze : "); + } else { + System.out.println("freeze : " + this.freeze); + } + + if (null == this.clawback) { + System.out.println("clawback: "); + } else { + System.out.println("clawback: " + this.clawback); + } + + } + + public boolean allImmutable() { + if (true && + (null == this.manager) && + (null == this.reserve) && + (null == this.freeze) && + (null == this.clawback) && + true) { + return true; + } + return false; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AVMAccountASABalance.java b/src/main/java/crypto/forestfish/objects/avm/AVMAccountASABalance.java new file mode 100644 index 0000000..f2121e8 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AVMAccountASABalance.java @@ -0,0 +1,54 @@ +package crypto.forestfish.objects.avm; + +import java.math.BigInteger; + +import crypto.forestfish.objects.avm.model.asa.AVMASAInfo; + +public class AVMAccountASABalance { + + private boolean isEmpty = true; + private Double balanceWithDecimalNotation; + private BigInteger balance; + private AVMASAInfo asaInfo; + + public AVMAccountASABalance(BigInteger _balance, AVMASAInfo _asaInfo) { + super(); + this.balance = _balance; + this.asaInfo = _asaInfo; + this.balanceWithDecimalNotation = _balance.longValue()/Math.pow(10L, asaInfo.getDecimals()); + if (_balance.longValue() != 0L) this.isEmpty = false; + } + + public boolean isEmpty() { + return isEmpty; + } + + public void setEmpty(boolean isEmpty) { + this.isEmpty = isEmpty; + } + + public Double getBalanceWithDecimalNotation() { + return balanceWithDecimalNotation; + } + + public void setBalanceWithDecimalNotation(Double balanceWithDecimalNotation) { + this.balanceWithDecimalNotation = balanceWithDecimalNotation; + } + + public AVMASAInfo getAsaInfo() { + return asaInfo; + } + + public void setAsaInfo(AVMASAInfo asaInfo) { + this.asaInfo = asaInfo; + } + + public BigInteger getBalance() { + return balance; + } + + public void setBalance(BigInteger balance) { + this.balance = balance; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AVMAccountBalance.java b/src/main/java/crypto/forestfish/objects/avm/AVMAccountBalance.java new file mode 100644 index 0000000..6878b97 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AVMAccountBalance.java @@ -0,0 +1,71 @@ +package crypto.forestfish.objects.avm; + +import crypto.forestfish.objects.avm.model.chain.AVMCurrency; + +public class AVMAccountBalance { + + private boolean isEmpty = true; + private Long balanceInMicroAlgo; + private Double balanceInALGO; + private AVMCurrency currency; + + public AVMAccountBalance() { + super(); + } + + public AVMAccountBalance(Long _balanceInMicroAlgo, Double _balanceInALGO, AVMCurrency _currency, boolean isEmpty) { + super(); + this.balanceInMicroAlgo = _balanceInMicroAlgo; + this.balanceInALGO = _balanceInALGO; + this.currency = _currency; + this.isEmpty = isEmpty; + } + + public boolean isEmpty() { + return isEmpty; + } + + public void setEmpty(boolean isEmpty) { + this.isEmpty = isEmpty; + } + + public Long getBalanceInMicroAlgo() { + return balanceInMicroAlgo; + } + + public void setBalanceInMicroAlgo(Long balanceInMicroAlgo) { + this.balanceInMicroAlgo = balanceInMicroAlgo; + } + + public Double getBalanceInALGO() { + return balanceInALGO; + } + + public void setBalanceInALGO(Double balanceInALGO) { + this.balanceInALGO = balanceInALGO; + } + + public AVMCurrency getCurrency() { + return currency; + } + + public void setCurrency(AVMCurrency currency) { + this.currency = currency; + } + + public String getBalanceInALGOPrettyPrint() { + if (balanceInALGO < 0.001d) { + return "..." + this.balanceInALGO; + } else { + return this.balanceInALGO + ""; + } + } + + public String getBalanceInuAlgoPrettyPrint() { + if (this.getCurrency().getDecimal() == 18) { + return this.balanceInMicroAlgo + ""; + } else { + return "-"; + } + } +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AVMAccountTxSummary.java b/src/main/java/crypto/forestfish/objects/avm/AVMAccountTxSummary.java new file mode 100644 index 0000000..f843a9d --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AVMAccountTxSummary.java @@ -0,0 +1,36 @@ +package crypto.forestfish.objects.avm; + +import java.util.HashMap; + +public class AVMAccountTxSummary { + + private HashMap txtype_counts = new HashMap<>(); + private long txcount = 0L; + + public AVMAccountTxSummary() { + super(); + } + + public AVMAccountTxSummary(HashMap txtype_counts, long txcount) { + super(); + this.txtype_counts = txtype_counts; + this.txcount = txcount; + } + + public HashMap getTxtype_counts() { + return txtype_counts; + } + + public void setTxtype_counts(HashMap txtype_counts) { + this.txtype_counts = txtype_counts; + } + + public long getTxcount() { + return txcount; + } + + public void setTxcount(long txcount) { + this.txcount = txcount; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AVMChainPortfolio.java b/src/main/java/crypto/forestfish/objects/avm/AVMChainPortfolio.java new file mode 100644 index 0000000..3d137b6 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AVMChainPortfolio.java @@ -0,0 +1,127 @@ +package crypto.forestfish.objects.avm; + +import java.util.HashMap; + +public class AVMChainPortfolio { + + private String account_address; + private String chain; + private AVMAccountBalance nativeBalance; + private HashMap tokens = new HashMap<>(); + private HashMap nfttokens = new HashMap<>(); + + private Long txCount = 0L; + private Long calculatedMinimumBalance = 0L; + private Long total_apps_optedin = 0L; + private Long total_created_apps = 0L; + boolean accounts_holds_assets = false; + + public AVMChainPortfolio() { + super(); + } + + public AVMChainPortfolio(String _account_address, String chain, AVMAccountBalance _nativeBalance, Long _txCount, HashMap _tokens, HashMap _nfttokens) { + super(); + this.account_address = _account_address; + this.chain = chain; + this.nativeBalance = _nativeBalance; + this.txCount = _txCount; + this.tokens = _tokens; + this.nfttokens = _nfttokens; + } + + public AVMChainPortfolio(String _account_address, String chain, AVMAccountBalance _nativeBalance, Long _txCount, HashMap _tokens, HashMap _nfttokens, Long _calculatedMinimumBalance, Long _total_apps_optedin, Long _total_created_apps, Boolean _accounts_holds_assets) { + super(); + this.account_address = _account_address; + this.chain = chain; + this.nativeBalance = _nativeBalance; + this.txCount = _txCount; + this.tokens = _tokens; + this.nfttokens = _nfttokens; + this.calculatedMinimumBalance = _calculatedMinimumBalance; + this.total_apps_optedin = _total_apps_optedin; + this.total_created_apps = _total_created_apps; + this.accounts_holds_assets = _accounts_holds_assets; + } + + public AVMAccountBalance getNativeBalance() { + return nativeBalance; + } + + public void setNativeBalance(AVMAccountBalance nativeBalance) { + this.nativeBalance = nativeBalance; + } + + public String getChain() { + return chain; + } + + public void setChain(String chain) { + this.chain = chain; + } + + public String getAccount_address() { + return account_address; + } + + public void setAccount_address(String account_address) { + this.account_address = account_address; + } + + public HashMap getTokens() { + return tokens; + } + + public void setTokens(HashMap tokens) { + this.tokens = tokens; + } + + public HashMap getNfttokens() { + return nfttokens; + } + + public void setNfttokens(HashMap nfttokens) { + this.nfttokens = nfttokens; + } + + public Long getTxCount() { + return txCount; + } + + public void setTxCount(Long txCount) { + this.txCount = txCount; + } + + public Long getCalculatedMinimumBalance() { + return calculatedMinimumBalance; + } + + public void setCalculatedMinimumBalance(Long calculatedMinimumBalance) { + this.calculatedMinimumBalance = calculatedMinimumBalance; + } + + public Long getTotal_apps_optedin() { + return total_apps_optedin; + } + + public void setTotal_apps_optedin(Long total_apps_optedin) { + this.total_apps_optedin = total_apps_optedin; + } + + public Long getTotal_created_apps() { + return total_created_apps; + } + + public void setTotal_created_apps(Long total_created_apps) { + this.total_created_apps = total_created_apps; + } + + public boolean isAccounts_holds_assets() { + return accounts_holds_assets; + } + + public void setAccounts_holds_assets(boolean accounts_holds_assets) { + this.accounts_holds_assets = accounts_holds_assets; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AVMChainPortfolioDiff.java b/src/main/java/crypto/forestfish/objects/avm/AVMChainPortfolioDiff.java new file mode 100644 index 0000000..5998f68 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AVMChainPortfolioDiff.java @@ -0,0 +1,76 @@ +package crypto.forestfish.objects.avm; + +import java.util.HashMap; + +public class AVMChainPortfolioDiff { + + private String account_address; + private String chain; + private AVMAccountBalance nativeBalance; + private String txCount; + private HashMap asatokens = new HashMap<>(); + private HashMap arctokens = new HashMap<>(); + + public AVMChainPortfolioDiff() { + super(); + } + + public AVMChainPortfolioDiff(String account_address, String chain, AVMAccountBalance nativeBalance, String txCount, HashMap asatokens, HashMap arctokens) { + super(); + this.account_address = account_address; + this.chain = chain; + this.nativeBalance = nativeBalance; + this.txCount = txCount; + this.asatokens = asatokens; + this.arctokens = arctokens; + } + + public AVMAccountBalance getNativeBalance() { + return nativeBalance; + } + + public void setNativeBalance(AVMAccountBalance nativeBalance) { + this.nativeBalance = nativeBalance; + } + + public String getChain() { + return chain; + } + + public void setChain(String chain) { + this.chain = chain; + } + + public String getAccount_address() { + return account_address; + } + + public void setAccount_address(String account_address) { + this.account_address = account_address; + } + + public String getTxCount() { + return txCount; + } + + public void setTxCount(String txCount) { + this.txCount = txCount; + } + + public HashMap getAsatokens() { + return asatokens; + } + + public void setAsatokens(HashMap asatokens) { + this.asatokens = asatokens; + } + + public HashMap getArctokens() { + return arctokens; + } + + public void setArctokens(HashMap arctokens) { + this.arctokens = arctokens; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AVMCreateAssetResult.java b/src/main/java/crypto/forestfish/objects/avm/AVMCreateAssetResult.java new file mode 100644 index 0000000..56b5dd5 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AVMCreateAssetResult.java @@ -0,0 +1,36 @@ +package crypto.forestfish.objects.avm; + +public class AVMCreateAssetResult { + + private String txhash; + private Long assetID; + private boolean confirmed = false; + + public AVMCreateAssetResult(String txhash, Long assetID, boolean confirmed) { + super(); + this.txhash = txhash; + this.assetID = assetID; + this.confirmed = confirmed; + } + + public String getTxhash() { + return txhash; + } + + public void setTxhash(String txhash) { + this.txhash = txhash; + } + + public Long getAssetID() { + return assetID; + } + + public void setAssetID(Long assetID) { + this.assetID = assetID; + } + + @Override + public String toString() { + return "txhash=" + this.txhash + " assetid=" + this.assetID + " confirmed=" + this.confirmed; + } +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AVMIndexerException.java b/src/main/java/crypto/forestfish/objects/avm/AVMIndexerException.java new file mode 100644 index 0000000..4495915 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AVMIndexerException.java @@ -0,0 +1,76 @@ +package crypto.forestfish.objects.avm; + +import crypto.forestfish.enums.ExceptionType; + +public class AVMIndexerException { + + private boolean switchNode = false; + private boolean nodeInteraction = false; + private boolean sleepBeforeRetry = false; + private int sleepTimeInSecondsRecommended = 5; + private ExceptionType exceptionType = ExceptionType.UNKNOWN; + private boolean timeout = false; + + public AVMIndexerException() { + super(); + } + + public AVMIndexerException(ExceptionType _exceptionType, boolean _nodeInteraction, boolean _sleepBeforeRetry, int _sleepTimeInSecondsRecommended, boolean _switchNode, boolean _timeout) { + super(); + this.exceptionType = _exceptionType; + this.nodeInteraction = _nodeInteraction; + this.sleepBeforeRetry = _sleepBeforeRetry; + this.sleepTimeInSecondsRecommended = _sleepTimeInSecondsRecommended; + this.switchNode = _switchNode; + this.timeout = _timeout; + } + + public boolean isNodeInteraction() { + return nodeInteraction; + } + + public void setNodeInteraction(boolean nodeInteraction) { + this.nodeInteraction = nodeInteraction; + } + + public boolean isSleepBeforeRetry() { + return sleepBeforeRetry; + } + + public void setSleepBeforeRetry(boolean sleepBeforeRetry) { + this.sleepBeforeRetry = sleepBeforeRetry; + } + + public int getSleepTimeInSecondsRecommended() { + return sleepTimeInSecondsRecommended; + } + + public void setSleepTimeInSecondsRecommended(int sleepTimeInSecondsRecommended) { + this.sleepTimeInSecondsRecommended = sleepTimeInSecondsRecommended; + } + + public ExceptionType getExceptionType() { + return exceptionType; + } + + public void setExceptionType(ExceptionType exceptionType) { + this.exceptionType = exceptionType; + } + + public boolean isSwitchNode() { + return switchNode; + } + + public void setSwitchNode(boolean switchNode) { + this.switchNode = switchNode; + } + + public boolean isTimeout() { + return timeout; + } + + public void setTimeout(boolean timeout) { + this.timeout = timeout; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AVMIndexerExceptionActionState.java b/src/main/java/crypto/forestfish/objects/avm/AVMIndexerExceptionActionState.java new file mode 100644 index 0000000..33d9f25 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AVMIndexerExceptionActionState.java @@ -0,0 +1,36 @@ +package crypto.forestfish.objects.avm; + +import crypto.forestfish.objects.avm.connector.AVMBlockChainConnector; + +public class AVMIndexerExceptionActionState { + + private boolean newAVMBlockChainConnector = false; + private AVMBlockChainConnector connector = null; + + public AVMIndexerExceptionActionState() { + super(); + } + + public AVMIndexerExceptionActionState(boolean newAVMBlockChainConnector, AVMBlockChainConnector connector) { + super(); + this.newAVMBlockChainConnector = newAVMBlockChainConnector; + this.connector = connector; + } + + public boolean isNewAVMBlockChainConnector() { + return newAVMBlockChainConnector; + } + + public void setNewEVMBlockChainConnector(boolean newAVMBlockChainConnector) { + this.newAVMBlockChainConnector = newAVMBlockChainConnector; + } + + public AVMBlockChainConnector getConnector() { + return connector; + } + + public void setConnector(AVMBlockChainConnector connector) { + this.connector = connector; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AVMKnownAccountAddress.java b/src/main/java/crypto/forestfish/objects/avm/AVMKnownAccountAddress.java new file mode 100644 index 0000000..15a7d87 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AVMKnownAccountAddress.java @@ -0,0 +1,58 @@ +package crypto.forestfish.objects.avm; + +import java.util.ArrayList; + +import crypto.forestfish.enums.AddressCategory; + +public class AVMKnownAccountAddress { + + private String name; + private String address; + private AddressCategory category; + private ArrayList origins = new ArrayList(); + + public AVMKnownAccountAddress(String name, String address, AddressCategory category, ArrayList origins) { + super(); + this.name = name; + this.address = address; + this.category = category; + this.origins = origins; + } + + public AVMKnownAccountAddress() { + super(); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public ArrayList getOrigins() { + return origins; + } + + public void setOrigins(ArrayList origins) { + this.origins = origins; + } + + public AddressCategory getCategory() { + return category; + } + + public void setCategory(AddressCategory category) { + this.category = category; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AVMKnownCustomContractAddress.java b/src/main/java/crypto/forestfish/objects/avm/AVMKnownCustomContractAddress.java new file mode 100644 index 0000000..cb3255d --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AVMKnownCustomContractAddress.java @@ -0,0 +1,69 @@ +package crypto.forestfish.objects.avm; + +import java.util.ArrayList; + +import crypto.forestfish.enums.CustomContractCategory; +import crypto.forestfish.enums.avm.AVMChain; + +public class AVMKnownCustomContractAddress { + + private String name; + private String address; + private AVMChain chain; + private CustomContractCategory category; + private ArrayList origins = new ArrayList(); + + public AVMKnownCustomContractAddress(String name, String address, AVMChain chain, CustomContractCategory category, ArrayList origins) { + super(); + this.name = name; + this.address = address; + this.chain = chain; + this.category = category; + this.origins = origins; + } + + public AVMKnownCustomContractAddress() { + super(); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public ArrayList getOrigins() { + return origins; + } + + public void setOrigins(ArrayList origins) { + this.origins = origins; + } + + public CustomContractCategory getCategory() { + return category; + } + + public void setCategory(CustomContractCategory category) { + this.category = category; + } + + public AVMChain getChain() { + return chain; + } + + public void setChain(AVMChain chain) { + this.chain = chain; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AVMNativeValue.java b/src/main/java/crypto/forestfish/objects/avm/AVMNativeValue.java new file mode 100644 index 0000000..ee3dd7a --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AVMNativeValue.java @@ -0,0 +1,34 @@ +package crypto.forestfish.objects.avm; + +import java.math.BigDecimal; + +import crypto.forestfish.enums.avm.Unit; + +public class AVMNativeValue { + + private BigDecimal val; + private Unit unit; + + public AVMNativeValue(BigDecimal val, Unit unit) { + super(); + this.val = val; + this.unit = unit; + } + + public BigDecimal getVal() { + return val; + } + + public void setVal(BigDecimal val) { + this.val = val; + } + + public Unit getUnit() { + return unit; + } + + public void setUnit(Unit unit) { + this.unit = unit; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AVMNftAccountBalance.java b/src/main/java/crypto/forestfish/objects/avm/AVMNftAccountBalance.java new file mode 100644 index 0000000..0f6e93a --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AVMNftAccountBalance.java @@ -0,0 +1,54 @@ +package crypto.forestfish.objects.avm; + +public class AVMNftAccountBalance { + + private boolean isEmpty = true; + private String balance; + private String name = null; + private String symbol = null; + + public AVMNftAccountBalance() { + super(); + } + + public AVMNftAccountBalance(String _balance, boolean _isEmpty, String _name, String _symbol) { + super(); + this.balance = _balance; + this.isEmpty = _isEmpty; + this.name = _name; + this.symbol = _symbol; + } + + public boolean isEmpty() { + return isEmpty; + } + + public void setEmpty(boolean isEmpty) { + this.isEmpty = isEmpty; + } + + public String getBalance() { + return balance; + } + + public void setBalance(String balance) { + this.balance = balance; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSymbol() { + return symbol; + } + + public void setSymbol(String symbol) { + this.symbol = symbol; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AVMPortfolio.java b/src/main/java/crypto/forestfish/objects/avm/AVMPortfolio.java new file mode 100644 index 0000000..fe28268 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AVMPortfolio.java @@ -0,0 +1,59 @@ +package crypto.forestfish.objects.avm; + +import java.util.HashMap; + +import org.web3j.crypto.Credentials; + +import crypto.forestfish.enums.avm.AVMChain; + +public class AVMPortfolio { + + private String account_address; + private HashMap chainportfolio = new HashMap<>(); + private Credentials cred; + private Long timestamp_in_seconds; + + public AVMPortfolio() { + super(); + } + + public AVMPortfolio(String _account_address, HashMap _chainportfolio, Long _timestamp_in_seconds) { + super(); + this.account_address = _account_address; + this.chainportfolio = _chainportfolio; + this.timestamp_in_seconds = _timestamp_in_seconds; + } + + public HashMap getChainportfolio() { + return chainportfolio; + } + + public void setChainportfolio(HashMap _chainportfolio) { + this.chainportfolio = _chainportfolio; + } + + public String getAccount_address() { + return account_address; + } + + public void setAccount_address(String _account_address) { + this.account_address = _account_address; + } + + public Credentials getCred() { + return cred; + } + + public void setCred(Credentials cred) { + this.cred = cred; + } + + public Long getTimestamp_in_seconds() { + return timestamp_in_seconds; + } + + public void setTimestamp_in_seconds(Long timestamp_in_seconds) { + this.timestamp_in_seconds = timestamp_in_seconds; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AVMPortfolioDiff.java b/src/main/java/crypto/forestfish/objects/avm/AVMPortfolioDiff.java new file mode 100644 index 0000000..9ca7f5d --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AVMPortfolioDiff.java @@ -0,0 +1,39 @@ +package crypto.forestfish.objects.avm; + +import java.util.HashMap; + +import crypto.forestfish.enums.avm.AVMChain; + +public class AVMPortfolioDiff { + + private String account_address; + private HashMap chainportfolio_diff = new HashMap<>(); + + public AVMPortfolioDiff() { + super(); + } + + public AVMPortfolioDiff(String _account_address, HashMap _chainportfolio_diff) { + super(); + this.account_address = _account_address; + this.chainportfolio_diff = _chainportfolio_diff; + } + + + public String getAccount_address() { + return account_address; + } + + public void setAccount_address(String _account_address) { + this.account_address = _account_address; + } + + public HashMap getChainportfolio_diff() { + return chainportfolio_diff; + } + + public void setChainportfolio_diff(HashMap chainportfolio_diff) { + this.chainportfolio_diff = chainportfolio_diff; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AVMPortfolioDiffResult.java b/src/main/java/crypto/forestfish/objects/avm/AVMPortfolioDiffResult.java new file mode 100644 index 0000000..e0616fb --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AVMPortfolioDiffResult.java @@ -0,0 +1,34 @@ +package crypto.forestfish.objects.avm; + +public class AVMPortfolioDiffResult { + + private String portfolio_full_str; + private AVMPortfolioDiff portfolio_diff; + + public AVMPortfolioDiffResult() { + super(); + } + + public AVMPortfolioDiffResult(String _portfolio_full_str, AVMPortfolioDiff _portfolio_diff) { + super(); + this.portfolio_full_str = _portfolio_full_str; + this.portfolio_diff = _portfolio_diff; + } + + public String getPortfolio_full_str() { + return portfolio_full_str; + } + + public void setPortfolio_full_str(String portfolio_full_str) { + this.portfolio_full_str = portfolio_full_str; + } + + public AVMPortfolioDiff getPortfolio_diff() { + return portfolio_diff; + } + + public void setPortfolio_diff(AVMPortfolioDiff portfolio_diff) { + this.portfolio_diff = portfolio_diff; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AVMPortfolioSimple.java b/src/main/java/crypto/forestfish/objects/avm/AVMPortfolioSimple.java new file mode 100644 index 0000000..2c7007e --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AVMPortfolioSimple.java @@ -0,0 +1,38 @@ +package crypto.forestfish.objects.avm; + +import java.util.HashMap; + +import crypto.forestfish.enums.avm.AVMChain; + +public class AVMPortfolioSimple { + + private String account_address; + private HashMap chainportfolio = new HashMap<>(); + + public AVMPortfolioSimple() { + super(); + } + + public AVMPortfolioSimple(String _account_address, HashMap _chainportfolio) { + super(); + this.account_address = _account_address; + this.chainportfolio = _chainportfolio; + } + + public HashMap getChainportfolio() { + return chainportfolio; + } + + public void setChainportfolio(HashMap _chainportfolio) { + this.chainportfolio = _chainportfolio; + } + + public String getAccount_address() { + return account_address; + } + + public void setAccount_address(String _account_address) { + this.account_address = _account_address; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AVMProviderException.java b/src/main/java/crypto/forestfish/objects/avm/AVMProviderException.java new file mode 100644 index 0000000..d5fe592 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AVMProviderException.java @@ -0,0 +1,76 @@ +package crypto.forestfish.objects.avm; + +import crypto.forestfish.enums.ExceptionType; + +public class AVMProviderException { + + private boolean switchNode = false; + private boolean nodeInteraction = false; + private boolean sleepBeforeRetry = false; + private int sleepTimeInSecondsRecommended = 5; + private ExceptionType exceptionType = ExceptionType.UNKNOWN; + private boolean timeout = false; + + public AVMProviderException() { + super(); + } + + public AVMProviderException(ExceptionType _exceptionType, boolean _nodeInteraction, boolean _sleepBeforeRetry, int _sleepTimeInSecondsRecommended, boolean _switchNode, boolean _timeout) { + super(); + this.exceptionType = _exceptionType; + this.nodeInteraction = _nodeInteraction; + this.sleepBeforeRetry = _sleepBeforeRetry; + this.sleepTimeInSecondsRecommended = _sleepTimeInSecondsRecommended; + this.switchNode = _switchNode; + this.timeout = _timeout; + } + + public boolean isNodeInteraction() { + return nodeInteraction; + } + + public void setNodeInteraction(boolean nodeInteraction) { + this.nodeInteraction = nodeInteraction; + } + + public boolean isSleepBeforeRetry() { + return sleepBeforeRetry; + } + + public void setSleepBeforeRetry(boolean sleepBeforeRetry) { + this.sleepBeforeRetry = sleepBeforeRetry; + } + + public int getSleepTimeInSecondsRecommended() { + return sleepTimeInSecondsRecommended; + } + + public void setSleepTimeInSecondsRecommended(int sleepTimeInSecondsRecommended) { + this.sleepTimeInSecondsRecommended = sleepTimeInSecondsRecommended; + } + + public ExceptionType getExceptionType() { + return exceptionType; + } + + public void setExceptionType(ExceptionType exceptionType) { + this.exceptionType = exceptionType; + } + + public boolean isSwitchNode() { + return switchNode; + } + + public void setSwitchNode(boolean switchNode) { + this.switchNode = switchNode; + } + + public boolean isTimeout() { + return timeout; + } + + public void setTimeout(boolean timeout) { + this.timeout = timeout; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AVMProviderExceptionActionState.java b/src/main/java/crypto/forestfish/objects/avm/AVMProviderExceptionActionState.java new file mode 100644 index 0000000..a6ffd86 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AVMProviderExceptionActionState.java @@ -0,0 +1,36 @@ +package crypto.forestfish.objects.avm; + +import crypto.forestfish.objects.avm.connector.AVMBlockChainConnector; + +public class AVMProviderExceptionActionState { + + private boolean newAVMBlockChainConnector = false; + private AVMBlockChainConnector connector = null; + + public AVMProviderExceptionActionState() { + super(); + } + + public AVMProviderExceptionActionState(boolean newAVMBlockChainConnector, AVMBlockChainConnector connector) { + super(); + this.newAVMBlockChainConnector = newAVMBlockChainConnector; + this.connector = connector; + } + + public boolean isNewAVMBlockChainConnector() { + return newAVMBlockChainConnector; + } + + public void setNewEVMBlockChainConnector(boolean newAVMBlockChainConnector) { + this.newAVMBlockChainConnector = newAVMBlockChainConnector; + } + + public AVMBlockChainConnector getConnector() { + return connector; + } + + public void setConnector(AVMBlockChainConnector connector) { + this.connector = connector; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AlgoIndexerNode.java b/src/main/java/crypto/forestfish/objects/avm/AlgoIndexerNode.java new file mode 100644 index 0000000..49b81b8 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AlgoIndexerNode.java @@ -0,0 +1,59 @@ +package crypto.forestfish.objects.avm; + +public class AlgoIndexerNode { + + private String url; + private Integer port; + private String authtoken; + private String authtoken_key; + + public AlgoIndexerNode() { + super(); + } + + public AlgoIndexerNode(String _url, Integer _port, String _authtoken, String _authtoken_key) { + super(); + this.url = _url; + this.port = _port; + this.authtoken = _authtoken; + this.authtoken_key = _authtoken_key; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public Integer getPort() { + return port; + } + + public void setPort(Integer port) { + this.port = port; + } + + public String getAuthtoken() { + return authtoken; + } + + public void setAuthtoken(String authtoken) { + this.authtoken = authtoken; + } + + public String getAuthtoken_key() { + return authtoken_key; + } + + public void setAuthtoken_key(String authtoken_key) { + this.authtoken_key = authtoken_key; + } + + @Override + public String toString() { + return this.getUrl() + " token=" + this.getAuthtoken() + " token_key=" + this.getAuthtoken_key(); + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AlgoLocalWallet.java b/src/main/java/crypto/forestfish/objects/avm/AlgoLocalWallet.java new file mode 100644 index 0000000..1bce604 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AlgoLocalWallet.java @@ -0,0 +1,186 @@ +package crypto.forestfish.objects.avm; + +import java.io.File; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.algorand.algosdk.account.Account; + +import crypto.forestfish.enums.AccountOrigin; +import crypto.forestfish.utils.FilesUtils; +import crypto.forestfish.utils.JSONUtils; +import crypto.forestfish.utils.SystemUtils; + +public class AlgoLocalWallet { + + private static final Logger LOGGER = LoggerFactory.getLogger(AlgoLocalWallet.class); + + private String walletName; + private String mnemonic; + private String address; + + public AlgoLocalWallet() { + super(); + } + + public AlgoLocalWallet(String _walletName, AccountOrigin _walletOrigin, String _mnemonic, String _address) { + initiateWallet(_walletName, _walletOrigin, _mnemonic, _address); + } + + public AlgoLocalWallet(String _walletName, AccountOrigin _walletOrigin, String _address) { + initiateWallet(_walletName, _walletOrigin, "xxx", _address); + } + + private void initiateWallet(String _walletName, AccountOrigin walletOrigin, String _mnemonic, String _address) { + this.walletName = _walletName; + this.mnemonic = _mnemonic; + this.address = _address; + + File walletDirectory = new File(".avm/wallets/" + walletName); + if (!walletDirectory.exists()) walletDirectory.mkdirs(); + + if (walletDirectory.listFiles().length == 0) { + + // No existing wallet so assume mnemonic creation in scope + if (walletOrigin == AccountOrigin.RECOVERY_MNEMONIC) { + + if (_mnemonic.contains("xxx")) { + LOGGER.error("No mnemonic provided, will not attempt to create wallet" ); + SystemUtils.halt(); + } + + // Sanity check + Account generatedAccount = null; + try { + generatedAccount = new Account(_mnemonic); + if (!generatedAccount.getAddress().toString().equals(_address)) { + LOGGER.error("Mnemonic " + _mnemonic + " does not generate an account with specified address " + _address); + LOGGER.error("The mnemonic specified instead generates an account with address: " + generatedAccount.getAddress()); + SystemUtils.halt(); + } + + // All good, flush JSON to file + String json = JSONUtils.createJSONFromPOJO(this); + String outfilePath = ".avm/wallets/" + _walletName + "/algowallet.json"; + FilesUtils.writeToFileUNIX(json, outfilePath); + + } catch (Exception e) { + LOGGER.error("e: " + e.getMessage()); + SystemUtils.halt(); + } + } else if (walletOrigin == AccountOrigin.EXISTING_LOCALWALLETFILE) { + LOGGER.error("You specified using a local AVM wallet file but did not find it under .avm/wallets/" + _walletName); + SystemUtils.halt(); + } else { + System.out.println("TODO: handle walletOrigin " + walletOrigin); + SystemUtils.halt(); + } + } else { + + if (walletDirectory.listFiles().length != 1) { + LOGGER.warn("More than one wallet file? Cannot handle this atm."); + SystemUtils.halt(); + } + + LOGGER.debug("Found an existing wallet!"); + + try { + File f = walletDirectory.listFiles()[0]; + String json = FilesUtils.readAllFromFileWithPath(f.getAbsolutePath()); + AlgoLocalWallet wallet = JSONUtils.createPOJOFromJSON(json, AlgoLocalWallet.class); + + this.address = wallet.getAddress(); + this.walletName = wallet.getWalletName(); + this.mnemonic = wallet.getMnemonic(); + + if (_mnemonic.contains("xxx")) { + LOGGER.debug("No mnemonic provided, will not attempt to verify credentials for wallet with name " + _walletName); + } else { + + // Sanity check + Account generatedAccount = null; + try { + generatedAccount = new Account(_mnemonic); + if (!generatedAccount.getAddress().toString().equals(_address)) { + LOGGER.error("Mnemonic " + _mnemonic + " does not generate an account with specified address " + _address); + LOGGER.error("The mnemonic specified instead generates an account with address: " + generatedAccount.getAddress()); + SystemUtils.halt(); + } + + // check that the specified address matches the mnemonic + if (generatedAccount.getAddress().toString().equals(this.address.toString())) { + // all checks out .. + } else { + LOGGER.error("Mnemonic " + _mnemonic + " does not generate an account with specified address " + _address); + LOGGER.error("The mnemonic specified instead generates an account with address: " + generatedAccount.getAddress()); + SystemUtils.halt(); + } + + // check that the specified address matches the wallet file + if (this.address.toString().equals(this.address.toString())) { + // all checks out .. + } else { + LOGGER.error("The wallet file with name " + _walletName + " does not include an account with specified address " + _address); + LOGGER.error("The wallet file specifies an account with address: " + this.address); + SystemUtils.halt(); + } + + } catch (Exception e) { + LOGGER.error("e: " + e.getMessage()); + SystemUtils.halt(); + } + } + + LOGGER.debug("Just restored ALGO wallet with name " + this.walletName + " from " + f.getAbsolutePath()); + } catch (Exception e) { + LOGGER.warn("e: " + e.getMessage()); + SystemUtils.halt(); + } + + } + + } + + public String getMnemonic() { + return mnemonic; + } + + public void setMnemonic(String mnemonic) { + this.mnemonic = mnemonic; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getWalletName() { + return walletName; + } + + public void setWalletName(String walletName) { + this.walletName = walletName; + } + + public Account fetchAccount() { + Account generatedAccount = null; + try { + generatedAccount = new Account(this.mnemonic); + } catch (Exception e) { + LOGGER.error("e: " + e.getMessage()); + SystemUtils.halt(); + } + if (generatedAccount == null) { + LOGGER.error("Unable to generate Algorand account from this wallet"); + LOGGER.error("address: " + this.address); + LOGGER.error("mnemonic: " + this.mnemonic); + SystemUtils.halt(); + } + return generatedAccount; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/AlgoRelayNode.java b/src/main/java/crypto/forestfish/objects/avm/AlgoRelayNode.java new file mode 100644 index 0000000..a60987f --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/AlgoRelayNode.java @@ -0,0 +1,59 @@ +package crypto.forestfish.objects.avm; + +public class AlgoRelayNode { + + private String url; + private Integer port; + private String authtoken; + private String authtoken_key; + + public AlgoRelayNode() { + super(); + } + + public AlgoRelayNode(String _url, Integer _port, String _authtoken, String _authtoken_key) { + super(); + this.url = _url; + this.port = _port; + this.authtoken = _authtoken; + this.authtoken_key = _authtoken_key; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public Integer getPort() { + return port; + } + + public void setPort(Integer port) { + this.port = port; + } + + public String getAuthtoken() { + return authtoken; + } + + public void setAuthtoken(String authtoken) { + this.authtoken = authtoken; + } + + public String getAuthtoken_key() { + return authtoken_key; + } + + public void setAuthtoken_key(String authtoken_key) { + this.authtoken_key = authtoken_key; + } + + @Override + public String toString() { + return this.getUrl() + " token=" + this.getAuthtoken() + " token_key=" + this.getAuthtoken_key(); + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/connector/AVMBlockChainConnector.java b/src/main/java/crypto/forestfish/objects/avm/connector/AVMBlockChainConnector.java new file mode 100644 index 0000000..da54476 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/connector/AVMBlockChainConnector.java @@ -0,0 +1,541 @@ +package crypto.forestfish.objects.avm.connector; + +import java.io.File; +import java.util.HashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.algorand.algosdk.v2.client.common.AlgodClient; +import com.algorand.algosdk.v2.client.common.IndexerClient; + +import crypto.forestfish.enums.avm.AVMChain; +import crypto.forestfish.objects.avm.AlgoIndexerNode; +import crypto.forestfish.objects.avm.AlgoRelayNode; +import crypto.forestfish.objects.avm.model.chain.AVMChainInfo; +import crypto.forestfish.utils.*; + +public class AVMBlockChainConnector { + + private static final Logger LOGGER = LoggerFactory.getLogger(AVMBlockChainConnector.class); + + private AVMChain chain; + private AVMChainInfo chaininfo; + private AlgoRelayNode relayNode; + private AlgodClient provider_instance; + private AlgoIndexerNode indexerNode; + private IndexerClient indexer_instance; + + private HashMap deadnodes = new HashMap<>(); + + public AVMBlockChainConnector(AVMChain _chain, boolean _nodeOptimized) { + super(); + LOGGER.debug("Creating a new AVMBlockChainConnector"); + + // Basic info + this.chain = _chain; + this.chaininfo = AVMUtils.getAVMChainInfo(_chain); + + // Check if we have preferred custom network settings first + String prefPath = ".avm/networks/" + _chain.toString(); + LOGGER.debug("Checking for preferred chainInfo details at " + prefPath); + File f = new File(prefPath); + if (f.exists()) { + LOGGER.info("Found custom network config at " + prefPath); + String json = FilesUtils.readStringFromFile(prefPath); + AVMChainInfo chainInfo = JSONUtils.createPOJOFromJSON(json, AVMChainInfo.class); + this.chaininfo = chainInfo; + + for (AlgoRelayNode node: chaininfo.getNodes()) { + this.relayNode = node; + } + + for (AlgoIndexerNode node: chaininfo.getIdxnodes()) { + this.indexerNode = node; + } + + } else { + + LOGGER.debug("Getting relay node"); + if (_nodeOptimized) { + LOGGER.info("Finding optimal relay node for public AVM blockchain " + chain); + this.relayNode = selectSpeedyRelayNode(); + } else { + LOGGER.info("Finding random relay node for public AVM blockchain " + chain); + this.relayNode = selectRandomRelayNode(); + } + + LOGGER.debug("Getting indexer node"); + if (_nodeOptimized) { + LOGGER.info("Finding optimal indexer node for public AVM blockchain " + chain); + this.indexerNode = selectSpeedyIndexerNode(); + } else { + LOGGER.info("Finding random indexer node for public AVM blockchain " + chain); + this.indexerNode = selectRandomIndexerNode(); + } + + } + + LOGGER.info("------------------------------------------------"); + + if (null == this.relayNode) { + LOGGER.error("Unable to find valid algorand relay node for chain " + _chain); + SystemUtils.halt(); + } else { + LOGGER.info("Using relaynode " + this.relayNode.getUrl()); + } + this.provider_instance = new AlgodClient(this.getRelayNode().getUrl(), this.getRelayNode().getPort(), this.getRelayNode().getAuthtoken(), this.getRelayNode().getAuthtoken_key()); + + if (null == this.indexerNode) { + LOGGER.warn("Unable to find valid algorand indexer node for chain " + _chain); + } else { + LOGGER.info("Using indexer " + this.indexerNode.getUrl()); + this.indexer_instance = new IndexerClient(this.getIndexerNode().getUrl(), this.getIndexerNode().getPort(), this.getIndexerNode().getAuthtoken(), this.getIndexerNode().getAuthtoken_key()); + } + + System.out.println(""); + + } + + public AVMBlockChainConnector(AVMChain _chain, AlgoRelayNode _relaynode) { + super(); + this.chain = _chain; + this.chaininfo = AVMUtils.getAVMChainInfo(_chain); + + this.relayNode = _relaynode; + this.provider_instance = new AlgodClient(this.getRelayNode().getUrl(), this.getRelayNode().getPort(), this.getRelayNode().getAuthtoken(), this.getRelayNode().getAuthtoken_key()); + } + + public AVMBlockChainConnector(AVMChain _chain, AlgoIndexerNode _idxnode) { + super(); + this.chain = _chain; + this.chaininfo = AVMUtils.getAVMChainInfo(_chain); + + this.indexerNode = _idxnode; + this.indexer_instance = new IndexerClient(this.getIndexerNode().getUrl(), this.getIndexerNode().getPort(), this.getIndexerNode().getAuthtoken(), this.getIndexerNode().getAuthtoken_key()); + } + + public AVMBlockChainConnector(AVMChainInfo _chainInfo) { + super(); + this.chain = AVMChain.valueOf(_chainInfo.getShortName()); + this.chaininfo = AVMUtils.getAVMChainInfo(this.chain); + + if (_chainInfo.getNodes().isEmpty()) { + LOGGER.error("No nodes part of the chainInfo provided"); + SystemUtils.halt(); + } + this.relayNode = _chainInfo.getNodes().get(0); + this.provider_instance = new AlgodClient(this.getRelayNode().getUrl(), this.getRelayNode().getPort(), this.getRelayNode().getAuthtoken(), this.getRelayNode().getAuthtoken_key()); + + if (_chainInfo.getIdxnodes().isEmpty()) { + LOGGER.warn("Unable to find valid algorand indexer node for chain " + this.chain); + } else { + this.indexerNode = _chainInfo.getIdxnodes().get(0); + this.indexer_instance = new IndexerClient(this.getIndexerNode().getUrl(), this.getIndexerNode().getPort(), this.getIndexerNode().getAuthtoken(), this.getIndexerNode().getAuthtoken_key()); + } + } + + public void reinitializeConnector() { + LOGGER.info("connector re-init with relay node " + this.getRelayNode().getUrl()); + LOGGER.info("connector re-init with indexer node " + this.getIndexerNode().getUrl()); + this.indexer_instance = new IndexerClient(this.getIndexerNode().getUrl(), this.getIndexerNode().getPort(), this.getIndexerNode().getAuthtoken(), this.getIndexerNode().getAuthtoken_key()); + this.provider_instance = new AlgodClient(this.getRelayNode().getUrl(), this.getRelayNode().getPort(), this.getRelayNode().getAuthtoken(), this.getRelayNode().getAuthtoken_key()); + } + + public AlgoRelayNode selectSpeedyRelayNode() { + // verify and select node + AlgoRelayNode winner = null; + if (this.chaininfo.getNodes().size() == 1) { + winner = this.chaininfo.getNodes().get(0); + LOGGER.info("We only have one relay node candidate so lets move forward with " + winner.getUrl()); + return winner; + } else { + + LOGGER.info("We need to get 1 of these relay candidates working, gonna optimize:"); + int candindex = 1; + for (AlgoRelayNode node: this.chaininfo.getNodes()) { + LOGGER.info(" #" + candindex + ": " + node.getUrl()); + candindex++; + } + + boolean nondead_winner_found = false; + while (!nondead_winner_found) { + + HashMap candidate_blockstate = new HashMap<>(); + + long maxRoundNR = Long.MIN_VALUE; + long minDiff = Long.MAX_VALUE; + for (AlgoRelayNode candidate: this.getChaininfo().getNodes()) { + // make sure to disregard dead nodes + if (null == deadnodes.get(candidate.getUrl())) { + + AVMBlockChainConnector connector = new AVMBlockChainConnector(chain, candidate); + long init = System.currentTimeMillis(); + Long lastRound = AVMUtils.getLastRound(connector); + //System.out.println("lastRound: " + lastRound); + long resp = System.currentTimeMillis() - init; + + if ( (null != lastRound) && (lastRound>0L)) { + winner = candidate; + if (resp candidate_blockstate.keySet().size()) { + LOGGER.warn("Found dead/lagging node, rounddiff=" + diff + ": " + cand_url); + deadnodes.put(cand_url, true); + } + } + + if (null == deadnodes.get(winner.getUrl())) { + LOGGER.info("relay node URL " + winner.getUrl() + " seems best option for " + this.chain + ", response_time=" + minDiff + " ms"); + nondead_winner_found = true; + } else { + LOGGER.info("We need to re-run, found dead nodes (" + deadnodes.size() + ") in our list .."); + LOGGER.info("deadnodes: " + deadnodes.keySet()); + if (this.getChaininfo().getNodes().size() == deadnodes.size()) { + LOGGER.error("All node candidates are dead?"); + SystemUtils.halt(); + } + } + + } + + } + + } + return winner; + } + + + public AlgoIndexerNode selectSpeedyIndexerNode() { + // verify and select node + AlgoIndexerNode winner = null; + if (this.chaininfo.getIdxnodes().size() == 1) { + winner = this.chaininfo.getIdxnodes().get(0); + LOGGER.info("We only have one indexer node candidate so lets move forward with " + winner.getUrl()); + return winner; + } else { + + LOGGER.info("We need to get 1 of these indexer candidates working, gonna optimize:"); + int candindex = 1; + for (AlgoIndexerNode node: this.chaininfo.getIdxnodes()) { + LOGGER.info(" #" + candindex + ": " + node.getUrl()); + candindex++; + } + + boolean nondead_winner_found = false; + while (!nondead_winner_found) { + + HashMap candidate_blockstate = new HashMap<>(); + + long maxRoundNR = Long.MIN_VALUE; + long minDiff = Long.MAX_VALUE; + for (AlgoIndexerNode candidate: this.getChaininfo().getIdxnodes()) { + // make sure to disregard dead nodes + if (null == deadnodes.get(candidate.getUrl())) { + + AVMBlockChainConnector connector = new AVMBlockChainConnector(chain, candidate); + long init = System.currentTimeMillis(); + Long lastRound = AVMUtils.getIndexerHealthCheck(connector); + //System.out.println("lastRound: " + lastRound); + long resp = System.currentTimeMillis() - init; + + if ( (null != lastRound) && (lastRound>0L)) { + winner = candidate; + if (resp candidate_blockstate.keySet().size()) { + LOGGER.warn("Found dead/lagging node, rounddiff=" + diff + ": " + cand_url); + deadnodes.put(cand_url, true); + } + } + + if (null == deadnodes.get(winner.getUrl())) { + LOGGER.info("indexer node URL " + winner.getUrl() + " seems best option for " + this.chain + ", response_time=" + minDiff + " ms"); + nondead_winner_found = true; + } else { + LOGGER.info("We need to re-run, found dead nodes (" + deadnodes.size() + ") in our list .."); + LOGGER.info("deadnodes: " + deadnodes.keySet()); + if (this.getChaininfo().getNodes().size() == deadnodes.size()) { + LOGGER.error("All node candidates are dead?"); + SystemUtils.halt(); + } + } + + } + + } + + } + return winner; + } + + + public AlgoRelayNode selectRandomRelayNode() { + AlgoRelayNode selected = null; + if (this.chaininfo.getNodes().size() == 1) { + selected = this.chaininfo.getNodes().get(0); + LOGGER.info("We only have one relay node candidate so lets move forward with " + selected.getUrl()); + return selected; + } + LOGGER.info("We need to get 1 of these relay candidates working, gonna go random:"); + int candindex = 1; + for (AlgoRelayNode node: this.chaininfo.getNodes()) { + LOGGER.info(" #" + candindex + ": " + node.getUrl()); + candindex++; + } + boolean selection_complete = false; + int randomAttemptCounter = 0; + while (!selection_complete && (randomAttemptCounter<=10)) { + AlgoRelayNode candidate = getRandom_relaynode_candidate(); + + AVMBlockChainConnector connector = new AVMBlockChainConnector(chain, candidate); + long init = System.currentTimeMillis(); + Long lastRound = AVMUtils.getLastRound(connector); + //System.out.println("lastRound: " + lastRound); + long resp = System.currentTimeMillis() - init; + + if ( (null != lastRound) && (lastRound>0L)) { + LOGGER.info("node " + candidate.getUrl() + " looks fine for " + this.chain + ", will use it"); + LOGGER.info("lastRound='" + lastRound + "', response_time=" + resp + " ms"); + selected = candidate; + selection_complete = true; + } else { + LOGGER.info("Failed attempt using node " + candidate.getUrl() + ", randomAttemptCounter=" + randomAttemptCounter); + } + randomAttemptCounter++; + } + + return selected; + } + + public AlgoIndexerNode selectRandomIndexerNode() { + AlgoIndexerNode selected = null; + if (this.chaininfo.getIdxnodes().size() == 1) { + selected = this.chaininfo.getIdxnodes().get(0); + LOGGER.info("We only have one indexer node candidate so lets move forward with " + selected.getUrl()); + return selected; + } + LOGGER.info("We need to get 1 of these indexer candidates working, gonna go random:"); + int candindex = 1; + for (AlgoIndexerNode node: this.chaininfo.getIdxnodes()) { + LOGGER.info(" #" + candindex + ": " + node.getUrl()); + candindex++; + } + boolean selection_complete = false; + int randomAttemptCounter = 0; + while (!selection_complete && (randomAttemptCounter<=10)) { + AlgoIndexerNode candidate = getRandom_idxnode_candidate(); + AVMBlockChainConnector connector = new AVMBlockChainConnector(chain, candidate); + long init = System.currentTimeMillis(); + Long lastRound = AVMUtils.getIndexerHealthCheck(connector); + //System.out.println("lastRound: " + lastRound); + long resp = System.currentTimeMillis() - init; + + if ( (null != lastRound) && (lastRound>0L)) { + LOGGER.info("node URL " + candidate.getUrl() + " looks fine for " + this.chain + ", will use it"); + LOGGER.info("lastRound='" + lastRound + "', response_time=" + resp + " ms"); + selected = candidate; + selection_complete = true; + } else { + LOGGER.info("Failed attempt using node " + candidate.getUrl() + ", randomAttemptCounter=" + randomAttemptCounter); + } + randomAttemptCounter++; + } + return selected; + } + + public AlgoIndexerNode selectRandomIndexerNode(String _skipthisNode) { + LOGGER.info("We need to get 1 of these candidates working, gonna go random without " + _skipthisNode); + AlgoIndexerNode selected = null; + if (this.chaininfo.getIdxnodes().size() == 1) { + selected = this.chaininfo.getIdxnodes().get(0); + LOGGER.info("We only have one indexer node candidate so lets move forward with " + selected.getUrl()); + return selected; + } + LOGGER.info("We need to get 1 of these indexer candidates working, gonna go random:"); + int candindex = 1; + for (AlgoIndexerNode node: this.chaininfo.getIdxnodes()) { + if (!_skipthisNode.equals(node.getUrl())) { + LOGGER.info(" #" + candindex + ": " + node.getUrl()); + candindex++; + } + } + boolean morethan1Candidate = true; + if (this.chaininfo.getIdxnodes().size() == 1) morethan1Candidate = false; + boolean selection_complete = false; + int randomAttemptCounter = 0; + while (!selection_complete && (randomAttemptCounter<=10)) { + AlgoIndexerNode candidate = getRandom_idxnode_candidate(); + + if (morethan1Candidate && _skipthisNode.equals(candidate.getUrl())) { + // lets pick a different node + } else if (!morethan1Candidate && _skipthisNode.equals(candidate.getUrl())) { + // early exit + if (!morethan1Candidate) randomAttemptCounter = 100; + } else { + AVMBlockChainConnector connector = new AVMBlockChainConnector(chain, candidate); + long init = System.currentTimeMillis(); + Long lastRound = AVMUtils.getIndexerHealthCheck(connector); + //System.out.println("lastRound: " + lastRound); + long resp = System.currentTimeMillis() - init; + + if ( (null != lastRound) && (lastRound>0L)) { + LOGGER.info("node URL " + candidate.getUrl() + " looks fine for " + this.chain + ", will use it"); + LOGGER.info("lastRound='" + lastRound + "', response_time=" + resp + " ms"); + selected = candidate; + selection_complete = true; + } else { + LOGGER.info("Failed attempt using node " + candidate.getUrl() + ", randomAttemptCounter=" + randomAttemptCounter); + } + randomAttemptCounter++; + } + } + return selected; + } + + + private AlgoRelayNode getRandom_relaynode_candidate() { + int size = this.chaininfo.getNodes().size(); + if (size == 0) { + LOGGER.error("We have no node candidates available. We should not be instantiated at at this point .."); + SystemUtils.halt(); + } else if (size == 1) { + return this.chaininfo.getNodes().get(0); + } else { + int selection = NumUtils.randomNumWithinRangeAsInt(1, size); + int index = 1; + for (AlgoRelayNode node: this.chaininfo.getNodes()) { + if (selection == index) return node; + index++; + } + return this.chaininfo.getNodes().get(0); + } + LOGGER.error("We have no node candidates available. We should not be instantiated at at this point .."); + SystemUtils.halt(); + return null; + } + + private AlgoIndexerNode getRandom_idxnode_candidate() { + int size = this.chaininfo.getNodes().size(); + if (size == 0) { + LOGGER.error("We have no node candidates available. We should not be instantiated at at this point .."); + SystemUtils.halt(); + } else if (size == 1) { + return this.chaininfo.getIdxnodes().get(0); + } else { + int selection = NumUtils.randomNumWithinRangeAsInt(1, size); + int index = 1; + for (AlgoIndexerNode node: this.chaininfo.getIdxnodes()) { + if (selection == index) return node; + index++; + } + return this.chaininfo.getIdxnodes().get(0); + } + LOGGER.error("We have no node candidates available. We should not be instantiated at at this point .."); + SystemUtils.halt(); + return null; + } + + public AVMChain getChain() { + return chain; + } + + public void setChain(AVMChain chain) { + this.chain = chain; + } + + public AVMChainInfo getChaininfo() { + return chaininfo; + } + + public void setChaininfo(AVMChainInfo chaininfo) { + this.chaininfo = chaininfo; + } + + public AlgodClient getProvider_instance() { + return provider_instance; + } + + public void setProvider_instance(AlgodClient provider_instance) { + this.provider_instance = provider_instance; + } + + public HashMap getDeadnodes() { + return deadnodes; + } + + public void setDeadnodes(HashMap deadnodes) { + this.deadnodes = deadnodes; + } + + public AlgoRelayNode getRelayNode() { + return relayNode; + } + + public void setRelayNode(AlgoRelayNode relayNode) { + this.relayNode = relayNode; + } + + public AlgoIndexerNode getIndexerNode() { + return indexerNode; + } + + public void setIndexerNode(AlgoIndexerNode indexerNode) { + this.indexerNode = indexerNode; + } + + public IndexerClient getIndexer_instance() { + return indexer_instance; + } + + public void setIndexer_instance(IndexerClient indexer_instance) { + this.indexer_instance = indexer_instance; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/connector/AVMBlockChainUltraConnector.java b/src/main/java/crypto/forestfish/objects/avm/connector/AVMBlockChainUltraConnector.java new file mode 100644 index 0000000..4080801 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/connector/AVMBlockChainUltraConnector.java @@ -0,0 +1,80 @@ +package crypto.forestfish.objects.avm.connector; + +import java.util.HashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import crypto.forestfish.enums.BlockchainType; +import crypto.forestfish.enums.avm.AVMChain; +import crypto.forestfish.objects.avm.model.chain.AVMChainInfo; +import crypto.forestfish.utils.AVMUtils; +import crypto.forestfish.utils.SystemUtils; + +public class AVMBlockChainUltraConnector { + + private static final Logger LOGGER = LoggerFactory.getLogger(AVMBlockChainUltraConnector.class); + + private HashMap connectors = new HashMap<>(); + private BlockchainType chainType; + + public AVMBlockChainUltraConnector(BlockchainType _chainType) { + super(); + + this.chainType = _chainType; + + //Initiate an rpc connection to every public blockchain we known of + for (AVMChain chain: AVMChain.values()) { + AVMChainInfo chainInfo = AVMUtils.getAVMChainInfo(chain); + if (chainInfo == null) { + LOGGER.error("No chainInfo for chain " + chain + "?"); + SystemUtils.halt(); + } + if (BlockchainType.valueOf(chainInfo.getType()) == chainType) { + AVMBlockChainConnector connector = new AVMBlockChainConnector(chain, true); + connectors.put(chain, connector); + } + } + + } + + public AVMBlockChainUltraConnector(BlockchainType _chainType, HashMap _chainlimit) { + super(); + + this.chainType = _chainType; + + if (_chainlimit.keySet().isEmpty()) { + LOGGER.error("Empty chain limitation passed as argument"); + SystemUtils.halt(); + } + + //Initiate an rpc connection to every public blockchain we known of + for (AVMChain chain: AVMChain.values()) { + if (null != _chainlimit.get(chain.toString())) { + AVMChainInfo chainInfo = AVMUtils.getAVMChainInfo(chain); + if (BlockchainType.valueOf(chainInfo.getType()) == chainType) { + AVMBlockChainConnector connector = new AVMBlockChainConnector(chain, true); + connectors.put(chain, connector); + } + } + } + + } + + public HashMap getConnectors() { + return connectors; + } + + public void setConnectors(HashMap connectors) { + this.connectors = connectors; + } + + public BlockchainType getChainType() { + return chainType; + } + + public void setChainType(BlockchainType chainType) { + this.chainType = chainType; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/model/asa/ASAContentOnchainReply.java b/src/main/java/crypto/forestfish/objects/avm/model/asa/ASAContentOnchainReply.java new file mode 100644 index 0000000..26e308b --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/model/asa/ASAContentOnchainReply.java @@ -0,0 +1,43 @@ +package crypto.forestfish.objects.avm.model.asa; + +public class ASAContentOnchainReply { + + private Long index; + private ASAParamsOnchain params; + + public ASAContentOnchainReply() { + super(); + } + + public Long getIndex() { + return index; + } + + public void setIndex(Long index) { + this.index = index; + } + + public ASAParamsOnchain getParams() { + return params; + } + + public void setParams(ASAParamsOnchain params) { + this.params = params; + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("index=" + this.getIndex()); + if (null != this.getParams().getUnit_name()) sb.append(" unit-name=" + this.getParams().getUnit_name()); + if (null != this.getParams().getName()) sb.append(" name=" + this.getParams().getName()); + sb.append(" total=" + this.getParams().getTotal()); + sb.append(" decimals=" + this.getParams().getDecimals()); + sb.append(" default_frozen=" + this.getParams().getDefault_frozen()); + sb.append(" creator=" + this.getParams().getCreator()); + if (null != this.getParams().getUrl()) sb.append(" url=" + this.getParams().getUrl()); + if (null != this.getParams().getMetadata_hash()) sb.append(" metadata_hash=" + this.getParams().getMetadata_hash()); + return sb.toString(); + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/model/asa/ASAIndex.java b/src/main/java/crypto/forestfish/objects/avm/model/asa/ASAIndex.java new file mode 100644 index 0000000..c0e154d --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/model/asa/ASAIndex.java @@ -0,0 +1,26 @@ +package crypto.forestfish.objects.avm.model.asa; + +import java.util.HashMap; + +public class ASAIndex { + + private HashMap tokens = new HashMap<>(); + + public ASAIndex() { + super(); + } + + public ASAIndex(HashMap tokens) { + super(); + this.tokens = tokens; + } + + public HashMap getTokens() { + return tokens; + } + + public void setTokens(HashMap tokens) { + this.tokens = tokens; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/model/asa/ASAParamsOnchain.java b/src/main/java/crypto/forestfish/objects/avm/model/asa/ASAParamsOnchain.java new file mode 100644 index 0000000..502a431 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/model/asa/ASAParamsOnchain.java @@ -0,0 +1,165 @@ +package crypto.forestfish.objects.avm.model.asa; + +import java.math.BigInteger; + +import com.fasterxml.jackson.annotation.JsonAlias; + +public class ASAParamsOnchain { + + private String clawback; + private String creator; + private Integer decimals; + + @JsonAlias("default-frozen") + private Boolean default_frozen; + + private String freeze; + private String manager; + + @JsonAlias("metadata-hash") + private String metadata_hash; + + private String name; + + @JsonAlias("name-b64") + private String name_b64; + + private String reserve; + private BigInteger total; + + @JsonAlias("unit-name") + private String unit_name; + + @JsonAlias("unit-name-b64") + private String unit_name_b64; + + private String url; + + @JsonAlias("url-b64") + private String url_b64; + + public ASAParamsOnchain() { + super(); + } + + public String getClawback() { + return clawback; + } + + public void setClawback(String clawback) { + this.clawback = clawback; + } + + public String getCreator() { + return creator; + } + + public void setCreator(String creator) { + this.creator = creator; + } + + public Integer getDecimals() { + return decimals; + } + + public void setDecimals(Integer decimals) { + this.decimals = decimals; + } + + public Boolean getDefault_frozen() { + return default_frozen; + } + + public void setDefault_frozen(Boolean default_frozen) { + this.default_frozen = default_frozen; + } + + public String getFreeze() { + return freeze; + } + + public void setFreeze(String freeze) { + this.freeze = freeze; + } + + public String getManager() { + return manager; + } + + public void setManager(String manager) { + this.manager = manager; + } + + public String getMetadata_hash() { + return metadata_hash; + } + + public void setMetadata_hash(String metadata_hash) { + this.metadata_hash = metadata_hash; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getName_b64() { + return name_b64; + } + + public void setName_b64(String name_b64) { + this.name_b64 = name_b64; + } + + public String getReserve() { + return reserve; + } + + public void setReserve(String reserve) { + this.reserve = reserve; + } + + public String getUnit_name() { + return unit_name; + } + + public void setUnit_name(String unit_name) { + this.unit_name = unit_name; + } + + public String getUnit_name_b64() { + return unit_name_b64; + } + + public void setUnit_name_b64(String unit_name_b64) { + this.unit_name_b64 = unit_name_b64; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getUrl_b64() { + return url_b64; + } + + public void setUrl_b64(String url_b64) { + this.url_b64 = url_b64; + } + + public BigInteger getTotal() { + return total; + } + + public void setTotal(BigInteger total) { + this.total = total; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/model/asa/AVMASAInfo.java b/src/main/java/crypto/forestfish/objects/avm/model/asa/AVMASAInfo.java new file mode 100644 index 0000000..b4fec4f --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/model/asa/AVMASAInfo.java @@ -0,0 +1,86 @@ +package crypto.forestfish.objects.avm.model.asa; + +import java.util.ArrayList; + +public class AVMASAInfo { + + private String symbol; + private Long id; + private String name; + private Integer decimals; + private String chain; + private ArrayList origins = new ArrayList(); + private String category; + + public AVMASAInfo() { + super(); + } + + public AVMASAInfo(String _symbol, Long _id, String _name, Integer _decimals, String _category, String _chain, ArrayList _origins) { + super(); + this.symbol = _symbol; + this.id = _id; + this.name = _name; + this.decimals = _decimals; + this.category = _category; + this.chain = _chain; + this.origins = _origins; + } + + public String getSymbol() { + return symbol; + } + + public void setSymbol(String symbol) { + this.symbol = symbol; + } + + public ArrayList getOrigins() { + return origins; + } + + public void setOrigins(ArrayList origins) { + this.origins = origins; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getDecimals() { + return decimals; + } + + public void setDecimals(Integer decimals) { + this.decimals = decimals; + } + + public String getChain() { + return chain; + } + + public void setChain(String chain) { + this.chain = chain; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/model/chain/AVMChainIndex.java b/src/main/java/crypto/forestfish/objects/avm/model/chain/AVMChainIndex.java new file mode 100644 index 0000000..7f8c61d --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/model/chain/AVMChainIndex.java @@ -0,0 +1,28 @@ +package crypto.forestfish.objects.avm.model.chain; + +import java.util.HashMap; + +import crypto.forestfish.enums.avm.AVMChain; + +public class AVMChainIndex { + + private HashMap networks = new HashMap<>(); + + public AVMChainIndex() { + super(); + } + + public AVMChainIndex(HashMap networks) { + super(); + this.networks = networks; + } + + public HashMap getNetworks() { + return networks; + } + + public void setNetworks(HashMap networks) { + this.networks = networks; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/model/chain/AVMChainInfo.java b/src/main/java/crypto/forestfish/objects/avm/model/chain/AVMChainInfo.java new file mode 100644 index 0000000..f88c829 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/model/chain/AVMChainInfo.java @@ -0,0 +1,151 @@ +package crypto.forestfish.objects.avm.model.chain; + +import java.util.ArrayList; + +import crypto.forestfish.objects.avm.AlgoIndexerNode; +import crypto.forestfish.objects.avm.AlgoRelayNode; +import crypto.forestfish.objects.avm.model.asa.ASAIndex; +import crypto.forestfish.objects.avm.model.nft.AVMNFTIndex; + +public class AVMChainInfo { + + private String shortName; + private String chainName; + private String type; + private String genesisID; + private String genesisHash; + private AVMCurrency nativeCurrency = null; + private ArrayList nodes = new ArrayList(); + private ArrayList idxnodes = new ArrayList(); + private ArrayList blockexplorerURLs = new ArrayList(); + private ArrayList faucets = new ArrayList(); + private ArrayList origins = new ArrayList(); + private ASAIndex tokenIndex; + private AVMNFTIndex nftindex; + + public AVMChainInfo() { + super(); + } + + public AVMChainInfo(String _shortName, String _chainName, String _type, String _genesisID, String _genesisHash, AVMCurrency _nativeCurrency, ArrayList _nodes, ArrayList _idxnodes, ArrayList _blockexplorerURLs, ArrayList _faucets, ArrayList _origins, ASAIndex _tokenIndex, AVMNFTIndex _nftindex) { + super(); + this.shortName = _shortName; + this.chainName = _chainName; + this.type = _type; + this.genesisID = _genesisID; + this.genesisHash = _genesisHash; + this.nativeCurrency = _nativeCurrency; + this.nodes = _nodes; + this.idxnodes = _idxnodes; + this.blockexplorerURLs = _blockexplorerURLs; + this.faucets = _faucets; + this.origins = _origins; + this.tokenIndex = _tokenIndex; + this.nftindex = _nftindex; + } + + public String getShortName() { + return shortName; + } + + public void setShortName(String shortName) { + this.shortName = shortName; + } + + public String getChainName() { + return chainName; + } + + public void setChainName(String chainName) { + this.chainName = chainName; + } + + public AVMCurrency getNativeCurrency() { + return nativeCurrency; + } + + public void setNativeCurrency(AVMCurrency nativeCurrency) { + this.nativeCurrency = nativeCurrency; + } + + public ArrayList getBlockexplorerURLs() { + return blockexplorerURLs; + } + + public void setBlockexplorerURLs(ArrayList blockexplorerURLs) { + this.blockexplorerURLs = blockexplorerURLs; + } + + public ArrayList getOrigins() { + return origins; + } + + public void setOrigins(ArrayList origins) { + this.origins = origins; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public AVMNFTIndex getNftindex() { + return nftindex; + } + + public void setNftindex(AVMNFTIndex nftindex) { + this.nftindex = nftindex; + } + + public ArrayList getFaucets() { + return faucets; + } + + public void setFaucets(ArrayList faucets) { + this.faucets = faucets; + } + + public ASAIndex getTokenIndex() { + return tokenIndex; + } + + public void setTokenIndex(ASAIndex tokenIndex) { + this.tokenIndex = tokenIndex; + } + + public String getGenesisHash() { + return genesisHash; + } + + public void setGenesisHash(String genesisHash) { + this.genesisHash = genesisHash; + } + + public String getGenesisID() { + return genesisID; + } + + public void setGenesisID(String genesisID) { + this.genesisID = genesisID; + } + + public ArrayList getNodes() { + return nodes; + } + + public void setNodes(ArrayList nodes) { + this.nodes = nodes; + } + + public ArrayList getIdxnodes() { + return idxnodes; + } + + public void setIdxnodes(ArrayList idxnodes) { + this.idxnodes = idxnodes; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/model/chain/AVMCurrency.java b/src/main/java/crypto/forestfish/objects/avm/model/chain/AVMCurrency.java new file mode 100644 index 0000000..59aa7ed --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/model/chain/AVMCurrency.java @@ -0,0 +1,43 @@ +package crypto.forestfish.objects.avm.model.chain; + +public class AVMCurrency { + private String name = null; + private String symbol = null; + private Integer decimal = 18; + + public AVMCurrency() { + super(); + } + + public AVMCurrency(String _name, String _symbol, Integer _decimal) { + super(); + this.name = _name; + this.symbol = _symbol; + this.decimal = _decimal; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSymbol() { + return symbol; + } + + public void setSymbol(String symbol) { + this.symbol = symbol; + } + + public Integer getDecimal() { + return decimal; + } + + public void setDecimal(Integer decimal) { + this.decimal = decimal; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/model/nft/ARC19Asset.java b/src/main/java/crypto/forestfish/objects/avm/model/nft/ARC19Asset.java new file mode 100644 index 0000000..353e10e --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/model/nft/ARC19Asset.java @@ -0,0 +1,213 @@ +package crypto.forestfish.objects.avm.model.nft; + +import java.math.BigInteger; + +import com.algorand.algosdk.crypto.Address; + +import crypto.forestfish.enums.avm.AVMNFTType; + +public class ARC19Asset { + + private Long assetID; // only set when minted + + // https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0019.md + // https://developer.algorand.org/docs/get-details/transactions/transactions/#asset-parameters + private String unitName; // Unit name (un) + private String assetName; // Asset Name (an) + private String assetURL; // Asset URL RFC-3986 (au) + private String assetMetadataHash; // Asset Metadata Hash (am) + + private BigInteger totalNrUnits; // Total Number of Units (t) + private Integer decimals; // Number of Digits after the Decimal Points (dc) + + private boolean defaultFrozen = false; + + private Address manager = null; // (m) + private Address reserve = null; // (r) + private Address freeze = null; // (f) + private Address clawback = null; // (c) + + // Calculated + private AVMNFTType type; // Calculated based on t+dc + + public ARC19Asset() { + super(); + } + + public ARC19Asset(Long _assetID, String _unitName, String _assetName, String _assetURL, BigInteger _totalNrUnits, Integer _decimals) { + super(); + this.assetID = _assetID; + this.unitName = _unitName; + this.assetName = _assetName; + this.assetURL = _assetURL; + this.totalNrUnits = _totalNrUnits; + this.decimals = _decimals; + + this.update(); + } + + public ARC19Asset(String _unitName, String _assetName, String _assetURL, BigInteger _totalNrUnits, Integer _decimals) { + super(); + this.unitName = _unitName; + this.assetName = _assetName; + this.assetURL = _assetURL; + this.totalNrUnits = _totalNrUnits; + this.decimals = _decimals; + + this.update(); + } + + public ARC19Asset(Long _assetID, String _unitName, String _assetName, String _assetURL, BigInteger _totalNrUnits, Integer _decimals, boolean _defaultFrozen, Address _manager, Address _reserve, Address _freeze, Address _clawback) { + super(); + this.assetID = _assetID; + this.unitName = _unitName; + this.assetName = _assetName; + this.assetURL = _assetURL; + this.totalNrUnits = _totalNrUnits; + this.decimals = _decimals; + this.defaultFrozen = _defaultFrozen; + this.manager = _manager; + this.reserve = _reserve; + this.freeze = _freeze; + this.clawback = _clawback; + + this.update(); + } + + public ARC19Asset(String _unitName, String _assetName, String _assetURL, BigInteger _totalNrUnits, Integer _decimals, boolean _defaultFrozen, Address _manager, Address _reserve, Address _freeze, Address _clawback) { + super(); + this.unitName = _unitName; + this.assetName = _assetName; + this.assetURL = _assetURL; + this.totalNrUnits = _totalNrUnits; + this.decimals = _decimals; + this.defaultFrozen = _defaultFrozen; + this.manager = _manager; + this.reserve = _reserve; + this.freeze = _freeze; + this.clawback = _clawback; + + this.update(); + } + + public void update() { + + // type + if ((this.totalNrUnits.compareTo(BigInteger.ONE) == 0) && (this.decimals.equals(0))) this.type = AVMNFTType.PURE; + + } + + public boolean sanityCheck() { + return true; + } + + public String getUnitName() { + return unitName; + } + + public void setUnitName(String unitName) { + this.unitName = unitName; + } + + public String getAssetName() { + return assetName; + } + + public void setAssetName(String assetName) { + this.assetName = assetName; + } + + public String getAssetURL() { + return assetURL; + } + + public void setAssetURL(String assetURL) { + this.assetURL = assetURL; + } + + public String getAssetMetadataHash() { + return assetMetadataHash; + } + + public void setAssetMetadataHash(String assetMetadataHash) { + this.assetMetadataHash = assetMetadataHash; + } + + public BigInteger getTotalNrUnits() { + return totalNrUnits; + } + + public void setTotalNrUnits(BigInteger totalNrUnits) { + this.totalNrUnits = totalNrUnits; + } + + public Integer getDecimals() { + return decimals; + } + + public void setDecimals(Integer decimals) { + this.decimals = decimals; + } + + public boolean isDefaultFrozen() { + return defaultFrozen; + } + + public void setDefaultFrozen(boolean defaultFrozen) { + this.defaultFrozen = defaultFrozen; + } + + public Address getManager() { + return manager; + } + + public void setManager(Address manager) { + this.manager = manager; + } + + public Address getReserve() { + return reserve; + } + + public void setReserve(Address reserve) { + this.reserve = reserve; + } + + public Address getFreeze() { + return freeze; + } + + public void setFreeze(Address freeze) { + this.freeze = freeze; + } + + public Address getClawback() { + return clawback; + } + + public void setClawback(Address clawback) { + this.clawback = clawback; + } + + public AVMNFTType getType() { + return type; + } + + public void setType(AVMNFTType type) { + this.type = type; + } + + public Long getAssetID() { + return assetID; + } + + public void setAssetID(Long assetID) { + this.assetID = assetID; + } + + @Override + public String toString() { + return "standard=ARC19 assetID=" + this.assetID + " unitName=" + this.unitName + " assetName=\"" + this.assetName + "\" assetURL=" + this.assetURL + " reserve=" + this.reserve.toString(); + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/model/nft/ARC19Info.java b/src/main/java/crypto/forestfish/objects/avm/model/nft/ARC19Info.java new file mode 100644 index 0000000..0af9d8a --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/model/nft/ARC19Info.java @@ -0,0 +1,133 @@ +package crypto.forestfish.objects.avm.model.nft; + +import java.util.ArrayList; + +import crypto.forestfish.enums.avm.AVMNFTStandard; +import crypto.forestfish.enums.avm.AVMNFTState; +import crypto.forestfish.enums.avm.AVMNFTType; + +public class ARC19Info { + + private String unitName; + private String creatorAddress; + private AVMNFTStandard standard; + private AVMNFTType type; + private AVMNFTState state; + private String description; + private String chain; + private ArrayList origins = new ArrayList(); + private String category; + private ArrayList linked_asa = new ArrayList(); + + public ARC19Info() { + super(); + } + + public ARC19Info(String _unitName, String _creatorAddress, AVMNFTStandard _standard, AVMNFTType _type, AVMNFTState _state, String _description, String _category, String _chain, ArrayList _origins) { + super(); + this.unitName = _unitName; + this.creatorAddress = _creatorAddress; + this.standard = _standard; + this.type = _type; + this.state = _state; + this.description = _description; + this.category = _category; + this.chain = _chain; + this.origins = _origins; + } + + public ARC19Info(String _unitName, String _creatorAddress, AVMNFTStandard _standard, AVMNFTType _type, AVMNFTState _state, String _description, String _category, String _chain, ArrayList _origins, ArrayList _linked_asa) { + super(); + this.unitName = _unitName; + this.creatorAddress = _creatorAddress; + this.standard = _standard; + this.type = _type; + this.state = _state; + this.description = _description; + this.category = _category; + this.chain = _chain; + this.origins = _origins; + this.linked_asa = _linked_asa; + } + + public ArrayList getOrigins() { + return origins; + } + + public void setOrigins(ArrayList origins) { + this.origins = origins; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getChain() { + return chain; + } + + public void setChain(String chain) { + this.chain = chain; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public ArrayList getLinked_asa() { + return linked_asa; + } + + public void setLinked_asa(ArrayList linked_asa) { + this.linked_asa = linked_asa; + } + + public String getUnitName() { + return unitName; + } + + public void setUnitName(String unitName) { + this.unitName = unitName; + } + + public String getCreatorAddress() { + return creatorAddress; + } + + public void setCreatorAddress(String creatorAddress) { + this.creatorAddress = creatorAddress; + } + + public AVMNFTStandard getStandard() { + return standard; + } + + public void setStandard(AVMNFTStandard standard) { + this.standard = standard; + } + + public AVMNFTType getType() { + return type; + } + + public void setType(AVMNFTType type) { + this.type = type; + } + + public AVMNFTState getState() { + return state; + } + + public void setState(AVMNFTState state) { + this.state = state; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/model/nft/ARC3Asset.java b/src/main/java/crypto/forestfish/objects/avm/model/nft/ARC3Asset.java new file mode 100644 index 0000000..76bde25 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/model/nft/ARC3Asset.java @@ -0,0 +1,255 @@ +package crypto.forestfish.objects.avm.model.nft; + +import java.math.BigInteger; + +import com.algorand.algosdk.crypto.Address; + +import crypto.forestfish.enums.avm.AVMNFTType; +import crypto.forestfish.utils.StringsUtils; + +public class ARC3Asset { + + private Long assetID; // only set when minted + + // https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0003.md + // https://developer.algorand.org/docs/get-details/transactions/transactions/#asset-parameters + private String unitName; // Unit name (un) + private String assetName; // Asset Name (an) + private String assetURL; // Asset URL RFC-3986 (au) + private byte[] assetMetadataHash; // Asset Metadata Hash (am) + private String assetMetadataHashSTR; // Asset Metadata Hash (am) + + private BigInteger totalNrUnits; // Total Number of Units (t) + private Integer decimals; // Number of Digits after the Decimal Points (dc) + + private boolean defaultFrozen = false; // (df) + + private Address manager = null; // (m) + private Address reserve = null; // (r) + private Address freeze = null; // (f) + private Address clawback = null; // (c) + + // Calculated + private AVMNFTType type = AVMNFTType.FRACTIONAL; // Calculated based on t+dc + private String assetNameBase64 = null; + private String unitNameBase64 = null; + private String urlBase64 = null; + + public ARC3Asset() { + super(); + } + + public ARC3Asset(Long _assetID, String _unitName, String _assetName, String _assetURL, BigInteger _totalNrUnits, Integer _decimals) { + super(); + this.assetID = _assetID; + this.unitName = _unitName; + this.assetName = _assetName; + this.assetURL = _assetURL; + this.totalNrUnits = _totalNrUnits; + this.decimals = _decimals; + + this.update(); + } + + public ARC3Asset(String _unitName, String _assetName, String _assetURL, BigInteger _totalNrUnits, Integer _decimals) { + super(); + this.unitName = _unitName; + this.assetName = _assetName; + this.assetURL = _assetURL; + this.totalNrUnits = _totalNrUnits; + this.decimals = _decimals; + + this.update(); + } + + public ARC3Asset(Long _assetID, String _unitName, String _assetName, String _assetURL, BigInteger _totalNrUnits, Integer _decimals, boolean _defaultFrozen, String _assetMetadataHashSTR, Address _manager, Address _reserve, Address _freeze, Address _clawback) { + super(); + this.assetID = _assetID; + this.unitName = _unitName; + this.assetName = _assetName; + this.assetURL = _assetURL; + this.totalNrUnits = _totalNrUnits; + this.decimals = _decimals; + this.defaultFrozen = _defaultFrozen; + this.assetMetadataHashSTR = _assetMetadataHashSTR; + this.manager = _manager; + this.reserve = _reserve; + this.freeze = _freeze; + this.clawback = _clawback; + + this.update(); + } + + public ARC3Asset(String _unitName, String _assetName, String _assetURL, BigInteger _totalNrUnits, Integer _decimals, boolean _defaultFrozen, Address _manager, Address _reserve, Address _freeze, Address _clawback) { + super(); + this.unitName = _unitName; + this.assetName = _assetName; + this.assetURL = _assetURL; + this.totalNrUnits = _totalNrUnits; + this.decimals = _decimals; + this.defaultFrozen = _defaultFrozen; + this.manager = _manager; + this.reserve = _reserve; + this.freeze = _freeze; + this.clawback = _clawback; + + this.update(); + } + + public void update() { + + // base64 + this.assetNameBase64 = StringsUtils.encodeStringToBase64(this.assetName); + this.unitNameBase64 = StringsUtils.encodeStringToBase64(this.unitName); + this.urlBase64 = StringsUtils.encodeStringToBase64(this.assetURL); + + // type + if ((this.totalNrUnits.compareTo(BigInteger.ONE) == 0) && (this.decimals.equals(0))) this.type = AVMNFTType.PURE; + + } + + public boolean sanityCheck() { + return true; + } + + public String getUnitName() { + return unitName; + } + + public void setUnitName(String unitName) { + this.unitName = unitName; + } + + public String getAssetName() { + return assetName; + } + + public void setAssetName(String assetName) { + this.assetName = assetName; + } + + public String getAssetURL() { + return assetURL; + } + + public void setAssetURL(String assetURL) { + this.assetURL = assetURL; + } + + public BigInteger getTotalNrUnits() { + return totalNrUnits; + } + + public void setTotalNrUnits(BigInteger totalNrUnits) { + this.totalNrUnits = totalNrUnits; + } + + public Integer getDecimals() { + return decimals; + } + + public void setDecimals(Integer decimals) { + this.decimals = decimals; + } + + public boolean isDefaultFrozen() { + return defaultFrozen; + } + + public void setDefaultFrozen(boolean defaultFrozen) { + this.defaultFrozen = defaultFrozen; + } + + public Address getManager() { + return manager; + } + + public void setManager(Address manager) { + this.manager = manager; + } + + public Address getReserve() { + return reserve; + } + + public void setReserve(Address reserve) { + this.reserve = reserve; + } + + public Address getFreeze() { + return freeze; + } + + public void setFreeze(Address freeze) { + this.freeze = freeze; + } + + public Address getClawback() { + return clawback; + } + + public void setClawback(Address clawback) { + this.clawback = clawback; + } + + public AVMNFTType getType() { + return type; + } + + public void setType(AVMNFTType type) { + this.type = type; + } + + public String getAssetNameBase64() { + return assetNameBase64; + } + + public void setAssetNameBase64(String assetNameBase64) { + this.assetNameBase64 = assetNameBase64; + } + + public String getUnitNameBase64() { + return unitNameBase64; + } + + public void setUnitNameBase64(String unitNameBase64) { + this.unitNameBase64 = unitNameBase64; + } + + public String getUrlBase64() { + return urlBase64; + } + + public void setUrlBase64(String urlBase64) { + this.urlBase64 = urlBase64; + } + + public Long getAssetID() { + return assetID; + } + + public void setAssetID(Long assetID) { + this.assetID = assetID; + } + + public byte[] getAssetMetadataHash() { + return assetMetadataHash; + } + + public void setAssetMetadataHash(byte[] assetMetadataHash) { + this.assetMetadataHash = assetMetadataHash; + } + + public String getAssetMetadataHashSTR() { + return assetMetadataHashSTR; + } + + public void setAssetMetadataHashSTR(String assetMetadataHashSTR) { + this.assetMetadataHashSTR = assetMetadataHashSTR; + } + + @Override + public String toString() { + return "standard=ARC3 assetID=" + this.assetID + " unitName=" + this.unitName + " assetName=\"" + this.assetName + "\" assetURL=" + this.assetURL; + } +} diff --git a/src/main/java/crypto/forestfish/objects/avm/model/nft/ARC3Info.java b/src/main/java/crypto/forestfish/objects/avm/model/nft/ARC3Info.java new file mode 100644 index 0000000..39471cc --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/model/nft/ARC3Info.java @@ -0,0 +1,133 @@ +package crypto.forestfish.objects.avm.model.nft; + +import java.util.ArrayList; + +import crypto.forestfish.enums.avm.AVMNFTStandard; +import crypto.forestfish.enums.avm.AVMNFTState; +import crypto.forestfish.enums.avm.AVMNFTType; + +public class ARC3Info { + + private String unitName; + private String creatorAddress; + private AVMNFTStandard standard; + private AVMNFTType type; + private AVMNFTState state; + private String description; + private String chain; + private ArrayList origins = new ArrayList(); + private String category; + private ArrayList linked_tokens = new ArrayList(); + + public ARC3Info() { + super(); + } + + public ARC3Info(String _unitName, String _creatorAddress, AVMNFTStandard _standard, AVMNFTType _type, AVMNFTState _state, String _description, String _category, String _chain, ArrayList _origins) { + super(); + this.unitName = _unitName; + this.creatorAddress = _creatorAddress; + this.standard = _standard; + this.type = _type; + this.state = _state; + this.description = _description; + this.category = _category; + this.chain = _chain; + this.origins = _origins; + } + + public ARC3Info(String _unitName, String _creatorAddress, AVMNFTStandard _standard, AVMNFTType _type, AVMNFTState _state, String _description, String _category, String _chain, ArrayList _origins, ArrayList _linked_tokens) { + super(); + this.unitName = _unitName; + this.creatorAddress = _creatorAddress; + this.standard = _standard; + this.type = _type; + this.state = _state; + this.description = _description; + this.category = _category; + this.chain = _chain; + this.origins = _origins; + this.linked_tokens = _linked_tokens; + } + + public ArrayList getOrigins() { + return origins; + } + + public void setOrigins(ArrayList origins) { + this.origins = origins; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getChain() { + return chain; + } + + public void setChain(String chain) { + this.chain = chain; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public ArrayList getLinked_tokens() { + return linked_tokens; + } + + public void setLinked_tokens(ArrayList linked_tokens) { + this.linked_tokens = linked_tokens; + } + + public String getUnitName() { + return unitName; + } + + public void setUnitName(String unitName) { + this.unitName = unitName; + } + + public String getCreatorAddress() { + return creatorAddress; + } + + public void setCreatorAddress(String creatorAddress) { + this.creatorAddress = creatorAddress; + } + + public AVMNFTStandard getStandard() { + return standard; + } + + public void setStandard(AVMNFTStandard standard) { + this.standard = standard; + } + + public AVMNFTType getType() { + return type; + } + + public void setType(AVMNFTType type) { + this.type = type; + } + + public AVMNFTState getState() { + return state; + } + + public void setState(AVMNFTState state) { + this.state = state; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/model/nft/ARC69Asset.java b/src/main/java/crypto/forestfish/objects/avm/model/nft/ARC69Asset.java new file mode 100644 index 0000000..5e6d926 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/model/nft/ARC69Asset.java @@ -0,0 +1,213 @@ +package crypto.forestfish.objects.avm.model.nft; + +import java.math.BigInteger; + +import com.algorand.algosdk.crypto.Address; + +import crypto.forestfish.enums.avm.AVMNFTType; + +public class ARC69Asset { + + private Long assetID; // only set when minted + + // https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0003.md + // https://developer.algorand.org/docs/get-details/transactions/transactions/#asset-parameters + private String unitName; // Unit name (un) + private String assetName; // Asset Name (an) + private String assetURL; // Asset URL RFC-3986 (au) + private String assetMetadataHash; // Asset Metadata Hash (am) + + private BigInteger totalNrUnits; // Total Number of Units (t) + private Integer decimals; // Number of Digits after the Decimal Points (dc) + + private boolean defaultFrozen = false; + + private Address manager = null; // (m) + private Address reserve = null; // (r) + private Address freeze = null; // (f) + private Address clawback = null; // (c) + + // Calculated + private AVMNFTType type; // Calculated based on t+dc + + public ARC69Asset() { + super(); + } + + public ARC69Asset(Long _assetID, String _unitName, String _assetName, String _assetURL, BigInteger _totalNrUnits, Integer _decimals) { + super(); + this.assetID = _assetID; + this.unitName = _unitName; + this.assetName = _assetName; + this.assetURL = _assetURL; + this.totalNrUnits = _totalNrUnits; + this.decimals = _decimals; + + this.update(); + } + + public ARC69Asset(String _unitName, String _assetName, String _assetURL, BigInteger _totalNrUnits, Integer _decimals) { + super(); + this.unitName = _unitName; + this.assetName = _assetName; + this.assetURL = _assetURL; + this.totalNrUnits = _totalNrUnits; + this.decimals = _decimals; + + this.update(); + } + + public ARC69Asset(Long _assetID, String _unitName, String _assetName, String _assetURL, BigInteger _totalNrUnits, Integer _decimals, boolean _defaultFrozen, Address _manager, Address _reserve, Address _freeze, Address _clawback) { + super(); + this.assetID = _assetID; + this.unitName = _unitName; + this.assetName = _assetName; + this.assetURL = _assetURL; + this.totalNrUnits = _totalNrUnits; + this.decimals = _decimals; + this.defaultFrozen = _defaultFrozen; + this.manager = _manager; + this.reserve = _reserve; + this.freeze = _freeze; + this.clawback = _clawback; + + this.update(); + } + + public ARC69Asset(String _unitName, String _assetName, String _assetURL, BigInteger _totalNrUnits, Integer _decimals, boolean _defaultFrozen, Address _manager, Address _reserve, Address _freeze, Address _clawback) { + super(); + this.unitName = _unitName; + this.assetName = _assetName; + this.assetURL = _assetURL; + this.totalNrUnits = _totalNrUnits; + this.decimals = _decimals; + this.defaultFrozen = _defaultFrozen; + this.manager = _manager; + this.reserve = _reserve; + this.freeze = _freeze; + this.clawback = _clawback; + + this.update(); + } + + public void update() { + + // type + if ((this.totalNrUnits.compareTo(BigInteger.ONE) == 0) && (this.decimals.equals(0))) this.type = AVMNFTType.PURE; + + } + + public boolean sanityCheck() { + return true; + } + + public String getUnitName() { + return unitName; + } + + public void setUnitName(String unitName) { + this.unitName = unitName; + } + + public String getAssetName() { + return assetName; + } + + public void setAssetName(String assetName) { + this.assetName = assetName; + } + + public String getAssetURL() { + return assetURL; + } + + public void setAssetURL(String assetURL) { + this.assetURL = assetURL; + } + + public String getAssetMetadataHash() { + return assetMetadataHash; + } + + public void setAssetMetadataHash(String assetMetadataHash) { + this.assetMetadataHash = assetMetadataHash; + } + + public BigInteger getTotalNrUnits() { + return totalNrUnits; + } + + public void setTotalNrUnits(BigInteger totalNrUnits) { + this.totalNrUnits = totalNrUnits; + } + + public Integer getDecimals() { + return decimals; + } + + public void setDecimals(Integer decimals) { + this.decimals = decimals; + } + + public boolean isDefaultFrozen() { + return defaultFrozen; + } + + public void setDefaultFrozen(boolean defaultFrozen) { + this.defaultFrozen = defaultFrozen; + } + + public Address getManager() { + return manager; + } + + public void setManager(Address manager) { + this.manager = manager; + } + + public Address getReserve() { + return reserve; + } + + public void setReserve(Address reserve) { + this.reserve = reserve; + } + + public Address getFreeze() { + return freeze; + } + + public void setFreeze(Address freeze) { + this.freeze = freeze; + } + + public Address getClawback() { + return clawback; + } + + public void setClawback(Address clawback) { + this.clawback = clawback; + } + + public AVMNFTType getType() { + return type; + } + + public void setType(AVMNFTType type) { + this.type = type; + } + + public Long getAssetID() { + return assetID; + } + + public void setAssetID(Long assetID) { + this.assetID = assetID; + } + + @Override + public String toString() { + return "standard=ARC69 assetID=" + this.assetID + " unitName=" + this.unitName + " assetName=\"" + this.assetName + "\" assetURL=" + this.assetURL; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/model/nft/ARC69Info.java b/src/main/java/crypto/forestfish/objects/avm/model/nft/ARC69Info.java new file mode 100644 index 0000000..9db8d1f --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/model/nft/ARC69Info.java @@ -0,0 +1,133 @@ +package crypto.forestfish.objects.avm.model.nft; + +import java.util.ArrayList; + +import crypto.forestfish.enums.avm.AVMNFTStandard; +import crypto.forestfish.enums.avm.AVMNFTState; +import crypto.forestfish.enums.avm.AVMNFTType; + +public class ARC69Info { + + private String unitName; + private String creatorAddress; + private AVMNFTStandard standard; + private AVMNFTType type; + private AVMNFTState state; + private String description; + private String chain; + private ArrayList origins = new ArrayList(); + private String category; + private ArrayList linked_asa = new ArrayList(); + + public ARC69Info() { + super(); + } + + public ARC69Info(String _unitName, String _creatorAddress, AVMNFTStandard _standard, AVMNFTType _type, AVMNFTState _state, String _description, String _category, String _chain, ArrayList _origins) { + super(); + this.unitName = _unitName; + this.creatorAddress = _creatorAddress; + this.standard = _standard; + this.type = _type; + this.state = _state; + this.description = _description; + this.category = _category; + this.chain = _chain; + this.origins = _origins; + } + + public ARC69Info(String _unitName, String _creatorAddress, AVMNFTStandard _standard, AVMNFTType _type, AVMNFTState _state, String _description, String _category, String _chain, ArrayList _origins, ArrayList _linked_asa) { + super(); + this.unitName = _unitName; + this.creatorAddress = _creatorAddress; + this.standard = _standard; + this.type = _type; + this.state = _state; + this.description = _description; + this.category = _category; + this.chain = _chain; + this.origins = _origins; + this.linked_asa = _linked_asa; + } + + public ArrayList getOrigins() { + return origins; + } + + public void setOrigins(ArrayList origins) { + this.origins = origins; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getChain() { + return chain; + } + + public void setChain(String chain) { + this.chain = chain; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public ArrayList getLinked_asa() { + return linked_asa; + } + + public void setLinked_asa(ArrayList linked_asa) { + this.linked_asa = linked_asa; + } + + public String getUnitName() { + return unitName; + } + + public void setUnitName(String unitName) { + this.unitName = unitName; + } + + public String getCreatorAddress() { + return creatorAddress; + } + + public void setCreatorAddress(String creatorAddress) { + this.creatorAddress = creatorAddress; + } + + public AVMNFTStandard getStandard() { + return standard; + } + + public void setStandard(AVMNFTStandard standard) { + this.standard = standard; + } + + public AVMNFTType getType() { + return type; + } + + public void setType(AVMNFTType type) { + this.type = type; + } + + public AVMNFTState getState() { + return state; + } + + public void setState(AVMNFTState state) { + this.state = state; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/model/nft/ASAVerificationStatus.java b/src/main/java/crypto/forestfish/objects/avm/model/nft/ASAVerificationStatus.java new file mode 100644 index 0000000..f82fcfc --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/model/nft/ASAVerificationStatus.java @@ -0,0 +1,97 @@ +package crypto.forestfish.objects.avm.model.nft; + +import java.util.ArrayList; + +public class ASAVerificationStatus { + + private boolean verified; + private ArrayList verified_properties = new ArrayList(); + private ArrayList major_issues = new ArrayList(); + private ArrayList warnings = new ArrayList(); + private int score_out_of_10 = 10; + + public ASAVerificationStatus(boolean _verified, ArrayList _verified_properties, ArrayList _major_issues, ArrayList _warnings, int _score_out_of_10) { + super(); + this.verified = _verified; + this.verified_properties = _verified_properties; + this.major_issues = _major_issues; + this.warnings = _warnings; + this.score_out_of_10 = _score_out_of_10; + } + + public boolean isVerified() { + return verified; + } + + public void setVerified(boolean verified) { + this.verified = verified; + } + + public ArrayList getVerified_properties() { + return verified_properties; + } + + public void setVerified_properties(ArrayList verified_properties) { + this.verified_properties = verified_properties; + } + + public ArrayList getMajor_issues() { + return major_issues; + } + + public void setMajor_issues(ArrayList major_issues) { + this.major_issues = major_issues; + } + + public ArrayList getWarnings() { + return warnings; + } + + public void setWarnings(ArrayList warnings) { + this.warnings = warnings; + } + + public int getScore_out_of_10() { + return score_out_of_10; + } + + public void setScore_out_of_10(int score_out_of_10) { + this.score_out_of_10 = score_out_of_10; + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + + sb.append("Verified : " + this.isVerified() + "\n"); + sb.append("Score [0-10] : " + this.getScore_out_of_10() + "\n"); + sb.append("-----------------------------------\n"); + + int i = 1; + if (!major_issues.isEmpty()) { + sb.append("Major issues: \n"); + for (String issue: major_issues) { + sb.append(" [#" + i + "] " + issue + "\n"); + i++; + } + } + + int x = 1; + if (!warnings.isEmpty()) { + sb.append("Warnings: \n"); + for (String warning: warnings) { + sb.append(" [#" + x + "] " + warning + "\n"); + x++; + } + } + + if (!verified_properties.isEmpty()) { + sb.append("Verified parameters: \n"); + for (String v: verified_properties) { + sb.append(" [+] " + v + "\n"); + } + } + + return sb.toString(); + } +} diff --git a/src/main/java/crypto/forestfish/objects/avm/model/nft/AVMNFTIndex.java b/src/main/java/crypto/forestfish/objects/avm/model/nft/AVMNFTIndex.java new file mode 100644 index 0000000..6b7790e --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/model/nft/AVMNFTIndex.java @@ -0,0 +1,36 @@ +package crypto.forestfish.objects.avm.model.nft; + +import java.util.HashMap; + +public class AVMNFTIndex { + + private HashMap arc3s = new HashMap<>(); + private HashMap arc69s = new HashMap<>(); + + public AVMNFTIndex() { + super(); + } + + public AVMNFTIndex(HashMap _arc3s, HashMap _arc69s) { + super(); + this.arc3s = _arc3s; + this.arc69s = _arc69s; + } + + public HashMap getArc3s() { + return arc3s; + } + + public void setArc3s(HashMap arc3s) { + this.arc3s = arc3s; + } + + public HashMap getArc69s() { + return arc69s; + } + + public void setArc69s(HashMap arc69s) { + this.arc69s = arc69s; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/model/nft/metadata/ARC3MetaData.java b/src/main/java/crypto/forestfish/objects/avm/model/nft/metadata/ARC3MetaData.java new file mode 100644 index 0000000..2b5d809 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/model/nft/metadata/ARC3MetaData.java @@ -0,0 +1,264 @@ +package crypto.forestfish.objects.avm.model.nft.metadata; + +import java.util.HashMap; + +public class ARC3MetaData { + + /** + * https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0003.md + */ + private String name; + private String description; + private Integer decimals; + private String background_color; + + private String image; // Supports {id} + private String image_integrity; + private String image_mimetype; + + private String external_url; // Supports {id} + private String external_url_integrity; + private String external_url_mimetype; + + private String animation_url; + private String animation_url_integrity; + private String animation_url_mimetype; + + private String extra_metadata; + + private HashMap properties; + // Common properties keys: + // - String file_url [file_url_integrity, file_url_mimetype] + + private HashMap localization; + // Required localization keys: + // - String uri (supports {locale}) + // - String default + // - ArrayList locales + // - HashMap integrity + + /** + * https://docs.opensea.io/docs/metadata-standards + _integrity/_mimetype for uri properties + */ + //private String name; + //private String description; + //private String background_color; + + //private String image; // Supports {id} + //private String image_integrity; + //private String image_mimetype; + + private String image_data; + private String image_data_integrity; + private String image_data_mimetype; + + //private String external_url; // Supports {id} + //private String external_url_integrity; + //private String external_url_mimetype; + + //private String animation_url; + //private String animation_url_integrity; + //private String animation_url_mimetype; + + public ARC3MetaData() { + super(); + } + + // Pure constructor + public ARC3MetaData(String _name, String _description, Integer _decimals, String _background_color, + String _image, String _external_url, String _animation_url, + HashMap _properties) { + super(); + this.name = _name; + this.description = _description; + this.decimals = _decimals; + this.background_color = _background_color; + this.image = _image; + this.external_url = _external_url; + this.animation_url = _animation_url; + this.properties = _properties; + } + + // Full constructor + public ARC3MetaData(String _name, String _description, Integer _decimals, String _background_color, + String _image, String _image_mimetype, String _image_integrity, + String _image_data, String _image_data_mimetype, String _image_data_integrity, + String _external_url, String _external_url_mimetype, String _external_url_integrity, + String _animation_url, String _animation_url_mimetype, String _animation_url_integrity, + HashMap _properties, HashMap _localization) { + super(); + this.decimals = _decimals; + this.properties = _properties; + this.name = _name; + this.description = _description; + this.background_color = _background_color; + this.image = _image; + this.image_mimetype = _image_mimetype; + this.image_integrity = _image_integrity; + this.image_data = _image_data; + this.image_data_mimetype = _image_data_mimetype; + this.image_data_integrity = _image_data_integrity; + this.external_url = _external_url; + this.external_url_mimetype = _external_url_mimetype; + this.external_url_integrity = _external_url_integrity; + this.animation_url = _animation_url; + this.animation_url_mimetype = _animation_url_mimetype; + this.animation_url_integrity = _animation_url_integrity; + this.localization = _localization; + } + + + + public String getExtra_metadata() { + return extra_metadata; + } + + public void setExtra_metadata(String extra_metadata) { + this.extra_metadata = extra_metadata; + } + + public Integer getDecimals() { + return decimals; + } + + public void setDecimals(Integer decimals) { + this.decimals = decimals; + } + + public HashMap getLocalization() { + return localization; + } + + public void setLocalization(HashMap localization) { + this.localization = localization; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getBackground_color() { + return background_color; + } + + public void setBackground_color(String background_color) { + this.background_color = background_color; + } + + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } + + public String getImage_integrity() { + return image_integrity; + } + + public void setImage_integrity(String image_integrity) { + this.image_integrity = image_integrity; + } + + public String getImage_mimetype() { + return image_mimetype; + } + + public void setImage_mimetype(String image_mimetype) { + this.image_mimetype = image_mimetype; + } + + public String getImage_data() { + return image_data; + } + + public void setImage_data(String image_data) { + this.image_data = image_data; + } + + public String getImage_data_integrity() { + return image_data_integrity; + } + + public void setImage_data_integrity(String image_data_integrity) { + this.image_data_integrity = image_data_integrity; + } + + public String getImage_data_mimetype() { + return image_data_mimetype; + } + + public void setImage_data_mimetype(String image_data_mimetype) { + this.image_data_mimetype = image_data_mimetype; + } + + public String getExternal_url() { + return external_url; + } + + public void setExternal_url(String external_url) { + this.external_url = external_url; + } + + public String getExternal_url_integrity() { + return external_url_integrity; + } + + public void setExternal_url_integrity(String external_url_integrity) { + this.external_url_integrity = external_url_integrity; + } + + public String getExternal_url_mimetype() { + return external_url_mimetype; + } + + public void setExternal_url_mimetype(String external_url_mimetype) { + this.external_url_mimetype = external_url_mimetype; + } + + public String getAnimation_url() { + return animation_url; + } + + public void setAnimation_url(String animation_url) { + this.animation_url = animation_url; + } + + public String getAnimation_url_integrity() { + return animation_url_integrity; + } + + public void setAnimation_url_integrity(String animation_url_integrity) { + this.animation_url_integrity = animation_url_integrity; + } + + public String getAnimation_url_mimetype() { + return animation_url_mimetype; + } + + public void setAnimation_url_mimetype(String animation_url_mimetype) { + this.animation_url_mimetype = animation_url_mimetype; + } + + public HashMap getProperties() { + return properties; + } + + public void setProperties(HashMap properties) { + this.properties = properties; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/model/nft/metadata/ARC69ARC19MetaData.java b/src/main/java/crypto/forestfish/objects/avm/model/nft/metadata/ARC69ARC19MetaData.java new file mode 100644 index 0000000..eccf58e --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/model/nft/metadata/ARC69ARC19MetaData.java @@ -0,0 +1,166 @@ +package crypto.forestfish.objects.avm.model.nft.metadata; + +import java.util.HashMap; + +public class ARC69ARC19MetaData { + + /** + * https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0069.md + */ + private String standard = "arc69"; + private String description; + + private String external_url; // Supports {id} + private String media_url; // Supports {id} + private String mime_type; // (au) + private Integer decimals; + + private HashMap properties; + // Common properties keys: + // - String file_url + + /** + * https://docs.opensea.io/docs/metadata-standards + */ + private String name; + //private String description; + private String background_color; + + private String image; // Supports {id} + private String image_data; + //private String external_url; // Supports {id} + private String animation_url; // Supports {id} + + // deprecated but can be supported, ARC69 is limited to 1024 so skip by default + //private ArrayList attributes; + + public ARC69ARC19MetaData() { + super(); + } + + // Pure constructor + public ARC69ARC19MetaData(String _description, String _external_url, String _media_url, String _mime_type, Integer _decimals, HashMap _properties) { + super(); + this.description = _description; + this.external_url = _external_url; + this.media_url = _media_url; + this.mime_type = _mime_type; + this.decimals = _decimals; + this.properties = _properties; + } + + // Full constructor + public ARC69ARC19MetaData(String _name, String _description, Integer _decimals, String _background_color, + String _image, String _image_data, String _external_url, String _animation_url, String _media_url, String _mime_type, + HashMap _properties) { + super(); + this.name = _name; + this.description = _description; + this.decimals = _decimals; + this.background_color = _background_color; + this.image = _image; + this.image_data = _image_data; + this.external_url = _external_url; + this.animation_url = _animation_url; + this.media_url = _media_url; + this.mime_type = _mime_type; + this.properties = _properties; + } + + public String getStandard() { + return standard; + } + + public void setStandard(String standard) { + this.standard = standard; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getExternal_url() { + return external_url; + } + + public void setExternal_url(String external_url) { + this.external_url = external_url; + } + + public String getMedia_url() { + return media_url; + } + + public void setMedia_url(String media_url) { + this.media_url = media_url; + } + + public String getMime_type() { + return mime_type; + } + + public void setMime_type(String mime_type) { + this.mime_type = mime_type; + } + + public Integer getDecimals() { + return decimals; + } + + public void setDecimals(Integer decimals) { + this.decimals = decimals; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getBackground_color() { + return background_color; + } + + public void setBackground_color(String background_color) { + this.background_color = background_color; + } + + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } + + public String getImage_data() { + return image_data; + } + + public void setImage_data(String image_data) { + this.image_data = image_data; + } + + public String getAnimation_url() { + return animation_url; + } + + public void setAnimation_url(String animation_url) { + this.animation_url = animation_url; + } + + public HashMap getProperties() { + return properties; + } + + public void setProperties(HashMap properties) { + this.properties = properties; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/avm/model/nft/metadata/MetaDataEntry.java b/src/main/java/crypto/forestfish/objects/avm/model/nft/metadata/MetaDataEntry.java new file mode 100644 index 0000000..9b0adeb --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/avm/model/nft/metadata/MetaDataEntry.java @@ -0,0 +1,51 @@ +package crypto.forestfish.objects.avm.model.nft.metadata; + +public class MetaDataEntry { + + private String metajson; + private Long tx_roundTime; + private Long tx_confirmedRound; + private String tx_id; + + public MetaDataEntry() { + super(); + } + + public MetaDataEntry(String metajson) { + super(); + this.metajson = metajson; + } + + public String getMetajson() { + return metajson; + } + + public void setMetajson(String metajson) { + this.metajson = metajson; + } + + public Long getTx_roundTime() { + return tx_roundTime; + } + + public void setTx_roundTime(Long tx_roundTime) { + this.tx_roundTime = tx_roundTime; + } + + public Long getTx_confirmedRound() { + return tx_confirmedRound; + } + + public void setTx_confirmedRound(Long tx_confirmedRound) { + this.tx_confirmedRound = tx_confirmedRound; + } + + public String getTx_id() { + return tx_id; + } + + public void setTx_id(String tx_id) { + this.tx_id = tx_id; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/burst/BurstBlockChain.java b/src/main/java/crypto/forestfish/objects/burst/BurstBlockChain.java new file mode 100644 index 0000000..6ffab8a --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/burst/BurstBlockChain.java @@ -0,0 +1,50 @@ +package crypto.forestfish.objects.burst; + +public class BurstBlockChain { + + private String name = null; + private String tokenName = null; + private String nodeURL = null; + private String blockexplorerURL = null; + + public BurstBlockChain(String name, String tokenName, String nodeURL, String blockexplorerURL) { + super(); + this.name = name; + this.tokenName = tokenName; + this.nodeURL = nodeURL; + this.blockexplorerURL = blockexplorerURL; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getTokenName() { + return tokenName; + } + + public void setTokenName(String tokenName) { + this.tokenName = tokenName; + } + + public String getNodeURL() { + return nodeURL; + } + + public void setNodeURL(String nodeURL) { + this.nodeURL = nodeURL; + } + + public String getBlockexplorerURL() { + return blockexplorerURL; + } + + public void setBlockexplorerURL(String blockexplorerURL) { + this.blockexplorerURL = blockexplorerURL; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/embedded/BlockchainDetailsGeneric.java b/src/main/java/crypto/forestfish/objects/embedded/BlockchainDetailsGeneric.java new file mode 100644 index 0000000..70be11d --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/embedded/BlockchainDetailsGeneric.java @@ -0,0 +1,2221 @@ +package crypto.forestfish.objects.embedded; + +import java.util.ArrayList; +import java.util.HashMap; + +public class BlockchainDetailsGeneric { + + @SuppressWarnings("serial") + public static HashMap bip39Words = new HashMap() {{ + this.put("abandon", true); + this.put("ability", true); + this.put("able", true); + this.put("about", true); + this.put("above", true); + this.put("absent", true); + this.put("absorb", true); + this.put("abstract", true); + this.put("absurd", true); + this.put("abuse", true); + this.put("access", true); + this.put("accident", true); + this.put("account", true); + this.put("accuse", true); + this.put("achieve", true); + this.put("acid", true); + this.put("acoustic", true); + this.put("acquire", true); + this.put("across", true); + this.put("act", true); + this.put("action", true); + this.put("actor", true); + this.put("actress", true); + this.put("actual", true); + this.put("adapt", true); + this.put("add", true); + this.put("addict", true); + this.put("address", true); + this.put("adjust", true); + this.put("admit", true); + this.put("adult", true); + this.put("advance", true); + this.put("advice", true); + this.put("aerobic", true); + this.put("affair", true); + this.put("afford", true); + this.put("afraid", true); + this.put("again", true); + this.put("age", true); + this.put("agent", true); + this.put("agree", true); + this.put("ahead", true); + this.put("aim", true); + this.put("air", true); + this.put("airport", true); + this.put("aisle", true); + this.put("alarm", true); + this.put("album", true); + this.put("alcohol", true); + this.put("alert", true); + this.put("alien", true); + this.put("all", true); + this.put("alley", true); + this.put("allow", true); + this.put("almost", true); + this.put("alone", true); + this.put("alpha", true); + this.put("already", true); + this.put("also", true); + this.put("alter", true); + this.put("always", true); + this.put("amateur", true); + this.put("amazing", true); + this.put("among", true); + this.put("amount", true); + this.put("amused", true); + this.put("analyst", true); + this.put("anchor", true); + this.put("ancient", true); + this.put("anger", true); + this.put("angle", true); + this.put("angry", true); + this.put("animal", true); + this.put("ankle", true); + this.put("announce", true); + this.put("annual", true); + this.put("another", true); + this.put("answer", true); + this.put("antenna", true); + this.put("antique", true); + this.put("anxiety", true); + this.put("any", true); + this.put("apart", true); + this.put("apology", true); + this.put("appear", true); + this.put("apple", true); + this.put("approve", true); + this.put("april", true); + this.put("arch", true); + this.put("arctic", true); + this.put("area", true); + this.put("arena", true); + this.put("argue", true); + this.put("arm", true); + this.put("armed", true); + this.put("armor", true); + this.put("army", true); + this.put("around", true); + this.put("arrange", true); + this.put("arrest", true); + this.put("arrive", true); + this.put("arrow", true); + this.put("art", true); + this.put("artefact", true); + this.put("artist", true); + this.put("artwork", true); + this.put("ask", true); + this.put("aspect", true); + this.put("assault", true); + this.put("asset", true); + this.put("assist", true); + this.put("assume", true); + this.put("asthma", true); + this.put("athlete", true); + this.put("atom", true); + this.put("attack", true); + this.put("attend", true); + this.put("attitude", true); + this.put("attract", true); + this.put("auction", true); + this.put("audit", true); + this.put("august", true); + this.put("aunt", true); + this.put("author", true); + this.put("auto", true); + this.put("autumn", true); + this.put("average", true); + this.put("avocado", true); + this.put("avoid", true); + this.put("awake", true); + this.put("aware", true); + this.put("away", true); + this.put("awesome", true); + this.put("awful", true); + this.put("awkward", true); + this.put("axis", true); + this.put("baby", true); + this.put("bachelor", true); + this.put("bacon", true); + this.put("badge", true); + this.put("bag", true); + this.put("balance", true); + this.put("balcony", true); + this.put("ball", true); + this.put("bamboo", true); + this.put("banana", true); + this.put("banner", true); + this.put("bar", true); + this.put("barely", true); + this.put("bargain", true); + this.put("barrel", true); + this.put("base", true); + this.put("basic", true); + this.put("basket", true); + this.put("battle", true); + this.put("beach", true); + this.put("bean", true); + this.put("beauty", true); + this.put("because", true); + this.put("become", true); + this.put("beef", true); + this.put("before", true); + this.put("begin", true); + this.put("behave", true); + this.put("behind", true); + this.put("believe", true); + this.put("below", true); + this.put("belt", true); + this.put("bench", true); + this.put("benefit", true); + this.put("best", true); + this.put("betray", true); + this.put("better", true); + this.put("between", true); + this.put("beyond", true); + this.put("bicycle", true); + this.put("bid", true); + this.put("bike", true); + this.put("bind", true); + this.put("biology", true); + this.put("bird", true); + this.put("birth", true); + this.put("bitter", true); + this.put("black", true); + this.put("blade", true); + this.put("blame", true); + this.put("blanket", true); + this.put("blast", true); + this.put("bleak", true); + this.put("bless", true); + this.put("blind", true); + this.put("blood", true); + this.put("blossom", true); + this.put("blouse", true); + this.put("blue", true); + this.put("blur", true); + this.put("blush", true); + this.put("board", true); + this.put("boat", true); + this.put("body", true); + this.put("boil", true); + this.put("bomb", true); + this.put("bone", true); + this.put("bonus", true); + this.put("book", true); + this.put("boost", true); + this.put("border", true); + this.put("boring", true); + this.put("borrow", true); + this.put("boss", true); + this.put("bottom", true); + this.put("bounce", true); + this.put("box", true); + this.put("boy", true); + this.put("bracket", true); + this.put("brain", true); + this.put("brand", true); + this.put("brass", true); + this.put("brave", true); + this.put("bread", true); + this.put("breeze", true); + this.put("brick", true); + this.put("bridge", true); + this.put("brief", true); + this.put("bright", true); + this.put("bring", true); + this.put("brisk", true); + this.put("broccoli", true); + this.put("broken", true); + this.put("bronze", true); + this.put("broom", true); + this.put("brother", true); + this.put("brown", true); + this.put("brush", true); + this.put("bubble", true); + this.put("buddy", true); + this.put("budget", true); + this.put("buffalo", true); + this.put("build", true); + this.put("bulb", true); + this.put("bulk", true); + this.put("bullet", true); + this.put("bundle", true); + this.put("bunker", true); + this.put("burden", true); + this.put("burger", true); + this.put("burst", true); + this.put("bus", true); + this.put("business", true); + this.put("busy", true); + this.put("butter", true); + this.put("buyer", true); + this.put("buzz", true); + this.put("cabbage", true); + this.put("cabin", true); + this.put("cable", true); + this.put("cactus", true); + this.put("cage", true); + this.put("cake", true); + this.put("call", true); + this.put("calm", true); + this.put("camera", true); + this.put("camp", true); + this.put("can", true); + this.put("canal", true); + this.put("cancel", true); + this.put("candy", true); + this.put("cannon", true); + this.put("canoe", true); + this.put("canvas", true); + this.put("canyon", true); + this.put("capable", true); + this.put("capital", true); + this.put("captain", true); + this.put("car", true); + this.put("carbon", true); + this.put("card", true); + this.put("cargo", true); + this.put("carpet", true); + this.put("carry", true); + this.put("cart", true); + this.put("case", true); + this.put("cash", true); + this.put("casino", true); + this.put("castle", true); + this.put("casual", true); + this.put("cat", true); + this.put("catalog", true); + this.put("catch", true); + this.put("category", true); + this.put("cattle", true); + this.put("caught", true); + this.put("cause", true); + this.put("caution", true); + this.put("cave", true); + this.put("ceiling", true); + this.put("celery", true); + this.put("cement", true); + this.put("census", true); + this.put("century", true); + this.put("cereal", true); + this.put("certain", true); + this.put("chair", true); + this.put("chalk", true); + this.put("champion", true); + this.put("change", true); + this.put("chaos", true); + this.put("chapter", true); + this.put("charge", true); + this.put("chase", true); + this.put("chat", true); + this.put("cheap", true); + this.put("check", true); + this.put("cheese", true); + this.put("chef", true); + this.put("cherry", true); + this.put("chest", true); + this.put("chicken", true); + this.put("chief", true); + this.put("child", true); + this.put("chimney", true); + this.put("choice", true); + this.put("choose", true); + this.put("chronic", true); + this.put("chuckle", true); + this.put("chunk", true); + this.put("churn", true); + this.put("cigar", true); + this.put("cinnamon", true); + this.put("circle", true); + this.put("citizen", true); + this.put("city", true); + this.put("civil", true); + this.put("claim", true); + this.put("clap", true); + this.put("clarify", true); + this.put("claw", true); + this.put("clay", true); + this.put("clean", true); + this.put("clerk", true); + this.put("clever", true); + this.put("click", true); + this.put("client", true); + this.put("cliff", true); + this.put("climb", true); + this.put("clinic", true); + this.put("clip", true); + this.put("clock", true); + this.put("clog", true); + this.put("close", true); + this.put("cloth", true); + this.put("cloud", true); + this.put("clown", true); + this.put("club", true); + this.put("clump", true); + this.put("cluster", true); + this.put("clutch", true); + this.put("coach", true); + this.put("coast", true); + this.put("coconut", true); + this.put("code", true); + this.put("coffee", true); + this.put("coil", true); + this.put("coin", true); + this.put("collect", true); + this.put("color", true); + this.put("column", true); + this.put("combine", true); + this.put("come", true); + this.put("comfort", true); + this.put("comic", true); + this.put("common", true); + this.put("company", true); + this.put("concert", true); + this.put("conduct", true); + this.put("confirm", true); + this.put("congress", true); + this.put("connect", true); + this.put("consider", true); + this.put("control", true); + this.put("convince", true); + this.put("cook", true); + this.put("cool", true); + this.put("copper", true); + this.put("copy", true); + this.put("coral", true); + this.put("core", true); + this.put("corn", true); + this.put("correct", true); + this.put("cost", true); + this.put("cotton", true); + this.put("couch", true); + this.put("country", true); + this.put("couple", true); + this.put("course", true); + this.put("cousin", true); + this.put("cover", true); + this.put("coyote", true); + this.put("crack", true); + this.put("cradle", true); + this.put("craft", true); + this.put("cram", true); + this.put("crane", true); + this.put("crash", true); + this.put("crater", true); + this.put("crawl", true); + this.put("crazy", true); + this.put("cream", true); + this.put("credit", true); + this.put("creek", true); + this.put("crew", true); + this.put("cricket", true); + this.put("crime", true); + this.put("crisp", true); + this.put("critic", true); + this.put("crop", true); + this.put("cross", true); + this.put("crouch", true); + this.put("crowd", true); + this.put("crucial", true); + this.put("cruel", true); + this.put("cruise", true); + this.put("crumble", true); + this.put("crunch", true); + this.put("crush", true); + this.put("cry", true); + this.put("crystal", true); + this.put("cube", true); + this.put("culture", true); + this.put("cup", true); + this.put("cupboard", true); + this.put("curious", true); + this.put("current", true); + this.put("curtain", true); + this.put("curve", true); + this.put("cushion", true); + this.put("custom", true); + this.put("cute", true); + this.put("cycle", true); + this.put("dad", true); + this.put("damage", true); + this.put("damp", true); + this.put("dance", true); + this.put("danger", true); + this.put("daring", true); + this.put("dash", true); + this.put("daughter", true); + this.put("dawn", true); + this.put("day", true); + this.put("deal", true); + this.put("debate", true); + this.put("debris", true); + this.put("decade", true); + this.put("december", true); + this.put("decide", true); + this.put("decline", true); + this.put("decorate", true); + this.put("decrease", true); + this.put("deer", true); + this.put("defense", true); + this.put("define", true); + this.put("defy", true); + this.put("degree", true); + this.put("delay", true); + this.put("deliver", true); + this.put("demand", true); + this.put("demise", true); + this.put("denial", true); + this.put("dentist", true); + this.put("deny", true); + this.put("depart", true); + this.put("depend", true); + this.put("deposit", true); + this.put("depth", true); + this.put("deputy", true); + this.put("derive", true); + this.put("describe", true); + this.put("desert", true); + this.put("design", true); + this.put("desk", true); + this.put("despair", true); + this.put("destroy", true); + this.put("detail", true); + this.put("detect", true); + this.put("develop", true); + this.put("device", true); + this.put("devote", true); + this.put("diagram", true); + this.put("dial", true); + this.put("diamond", true); + this.put("diary", true); + this.put("dice", true); + this.put("diesel", true); + this.put("diet", true); + this.put("differ", true); + this.put("digital", true); + this.put("dignity", true); + this.put("dilemma", true); + this.put("dinner", true); + this.put("dinosaur", true); + this.put("direct", true); + this.put("dirt", true); + this.put("disagree", true); + this.put("discover", true); + this.put("disease", true); + this.put("dish", true); + this.put("dismiss", true); + this.put("disorder", true); + this.put("display", true); + this.put("distance", true); + this.put("divert", true); + this.put("divide", true); + this.put("divorce", true); + this.put("dizzy", true); + this.put("doctor", true); + this.put("document", true); + this.put("dog", true); + this.put("doll", true); + this.put("dolphin", true); + this.put("domain", true); + this.put("donate", true); + this.put("donkey", true); + this.put("donor", true); + this.put("door", true); + this.put("dose", true); + this.put("double", true); + this.put("dove", true); + this.put("draft", true); + this.put("dragon", true); + this.put("drama", true); + this.put("drastic", true); + this.put("draw", true); + this.put("dream", true); + this.put("dress", true); + this.put("drift", true); + this.put("drill", true); + this.put("drink", true); + this.put("drip", true); + this.put("drive", true); + this.put("drop", true); + this.put("drum", true); + this.put("dry", true); + this.put("duck", true); + this.put("dumb", true); + this.put("dune", true); + this.put("during", true); + this.put("dust", true); + this.put("dutch", true); + this.put("duty", true); + this.put("dwarf", true); + this.put("dynamic", true); + this.put("eager", true); + this.put("eagle", true); + this.put("early", true); + this.put("earn", true); + this.put("earth", true); + this.put("easily", true); + this.put("east", true); + this.put("easy", true); + this.put("echo", true); + this.put("ecology", true); + this.put("economy", true); + this.put("edge", true); + this.put("edit", true); + this.put("educate", true); + this.put("effort", true); + this.put("egg", true); + this.put("eight", true); + this.put("either", true); + this.put("elbow", true); + this.put("elder", true); + this.put("electric", true); + this.put("elegant", true); + this.put("element", true); + this.put("elephant", true); + this.put("elevator", true); + this.put("elite", true); + this.put("else", true); + this.put("embark", true); + this.put("embody", true); + this.put("embrace", true); + this.put("emerge", true); + this.put("emotion", true); + this.put("employ", true); + this.put("empower", true); + this.put("empty", true); + this.put("enable", true); + this.put("enact", true); + this.put("end", true); + this.put("endless", true); + this.put("endorse", true); + this.put("enemy", true); + this.put("energy", true); + this.put("enforce", true); + this.put("engage", true); + this.put("engine", true); + this.put("enhance", true); + this.put("enjoy", true); + this.put("enlist", true); + this.put("enough", true); + this.put("enrich", true); + this.put("enroll", true); + this.put("ensure", true); + this.put("enter", true); + this.put("entire", true); + this.put("entry", true); + this.put("envelope", true); + this.put("episode", true); + this.put("equal", true); + this.put("equip", true); + this.put("era", true); + this.put("erase", true); + this.put("erode", true); + this.put("erosion", true); + this.put("error", true); + this.put("erupt", true); + this.put("escape", true); + this.put("essay", true); + this.put("essence", true); + this.put("estate", true); + this.put("eternal", true); + this.put("ethics", true); + this.put("evidence", true); + this.put("evil", true); + this.put("evoke", true); + this.put("evolve", true); + this.put("exact", true); + this.put("example", true); + this.put("excess", true); + this.put("exchange", true); + this.put("excite", true); + this.put("exclude", true); + this.put("excuse", true); + this.put("execute", true); + this.put("exercise", true); + this.put("exhaust", true); + this.put("exhibit", true); + this.put("exile", true); + this.put("exist", true); + this.put("exit", true); + this.put("exotic", true); + this.put("expand", true); + this.put("expect", true); + this.put("expire", true); + this.put("explain", true); + this.put("expose", true); + this.put("express", true); + this.put("extend", true); + this.put("extra", true); + this.put("eye", true); + this.put("eyebrow", true); + this.put("fabric", true); + this.put("face", true); + this.put("faculty", true); + this.put("fade", true); + this.put("faint", true); + this.put("faith", true); + this.put("fall", true); + this.put("false", true); + this.put("fame", true); + this.put("family", true); + this.put("famous", true); + this.put("fan", true); + this.put("fancy", true); + this.put("fantasy", true); + this.put("farm", true); + this.put("fashion", true); + this.put("fat", true); + this.put("fatal", true); + this.put("father", true); + this.put("fatigue", true); + this.put("fault", true); + this.put("favorite", true); + this.put("feature", true); + this.put("february", true); + this.put("federal", true); + this.put("fee", true); + this.put("feed", true); + this.put("feel", true); + this.put("female", true); + this.put("fence", true); + this.put("festival", true); + this.put("fetch", true); + this.put("fever", true); + this.put("few", true); + this.put("fiber", true); + this.put("fiction", true); + this.put("field", true); + this.put("figure", true); + this.put("file", true); + this.put("film", true); + this.put("filter", true); + this.put("final", true); + this.put("find", true); + this.put("fine", true); + this.put("finger", true); + this.put("finish", true); + this.put("fire", true); + this.put("firm", true); + this.put("first", true); + this.put("fiscal", true); + this.put("fish", true); + this.put("fit", true); + this.put("fitness", true); + this.put("fix", true); + this.put("flag", true); + this.put("flame", true); + this.put("flash", true); + this.put("flat", true); + this.put("flavor", true); + this.put("flee", true); + this.put("flight", true); + this.put("flip", true); + this.put("float", true); + this.put("flock", true); + this.put("floor", true); + this.put("flower", true); + this.put("fluid", true); + this.put("flush", true); + this.put("fly", true); + this.put("foam", true); + this.put("focus", true); + this.put("fog", true); + this.put("foil", true); + this.put("fold", true); + this.put("follow", true); + this.put("food", true); + this.put("foot", true); + this.put("force", true); + this.put("forest", true); + this.put("forget", true); + this.put("fork", true); + this.put("fortune", true); + this.put("forum", true); + this.put("forward", true); + this.put("fossil", true); + this.put("foster", true); + this.put("found", true); + this.put("fox", true); + this.put("fragile", true); + this.put("frame", true); + this.put("frequent", true); + this.put("fresh", true); + this.put("friend", true); + this.put("fringe", true); + this.put("frog", true); + this.put("front", true); + this.put("frost", true); + this.put("frown", true); + this.put("frozen", true); + this.put("fruit", true); + this.put("fuel", true); + this.put("fun", true); + this.put("funny", true); + this.put("furnace", true); + this.put("fury", true); + this.put("future", true); + this.put("gadget", true); + this.put("gain", true); + this.put("galaxy", true); + this.put("gallery", true); + this.put("game", true); + this.put("gap", true); + this.put("garage", true); + this.put("garbage", true); + this.put("garden", true); + this.put("garlic", true); + this.put("garment", true); + this.put("gas", true); + this.put("gasp", true); + this.put("gate", true); + this.put("gather", true); + this.put("gauge", true); + this.put("gaze", true); + this.put("general", true); + this.put("genius", true); + this.put("genre", true); + this.put("gentle", true); + this.put("genuine", true); + this.put("gesture", true); + this.put("ghost", true); + this.put("giant", true); + this.put("gift", true); + this.put("giggle", true); + this.put("ginger", true); + this.put("giraffe", true); + this.put("girl", true); + this.put("give", true); + this.put("glad", true); + this.put("glance", true); + this.put("glare", true); + this.put("glass", true); + this.put("glide", true); + this.put("glimpse", true); + this.put("globe", true); + this.put("gloom", true); + this.put("glory", true); + this.put("glove", true); + this.put("glow", true); + this.put("glue", true); + this.put("goat", true); + this.put("goddess", true); + this.put("gold", true); + this.put("good", true); + this.put("goose", true); + this.put("gorilla", true); + this.put("gospel", true); + this.put("gossip", true); + this.put("govern", true); + this.put("gown", true); + this.put("grab", true); + this.put("grace", true); + this.put("grain", true); + this.put("grant", true); + this.put("grape", true); + this.put("grass", true); + this.put("gravity", true); + this.put("great", true); + this.put("green", true); + this.put("grid", true); + this.put("grief", true); + this.put("grit", true); + this.put("grocery", true); + this.put("group", true); + this.put("grow", true); + this.put("grunt", true); + this.put("guard", true); + this.put("guess", true); + this.put("guide", true); + this.put("guilt", true); + this.put("guitar", true); + this.put("gun", true); + this.put("gym", true); + this.put("habit", true); + this.put("hair", true); + this.put("half", true); + this.put("hammer", true); + this.put("hamster", true); + this.put("hand", true); + this.put("happy", true); + this.put("harbor", true); + this.put("hard", true); + this.put("harsh", true); + this.put("harvest", true); + this.put("hat", true); + this.put("have", true); + this.put("hawk", true); + this.put("hazard", true); + this.put("head", true); + this.put("health", true); + this.put("heart", true); + this.put("heavy", true); + this.put("hedgehog", true); + this.put("height", true); + this.put("hello", true); + this.put("helmet", true); + this.put("help", true); + this.put("hen", true); + this.put("hero", true); + this.put("hidden", true); + this.put("high", true); + this.put("hill", true); + this.put("hint", true); + this.put("hip", true); + this.put("hire", true); + this.put("history", true); + this.put("hobby", true); + this.put("hockey", true); + this.put("hold", true); + this.put("hole", true); + this.put("holiday", true); + this.put("hollow", true); + this.put("home", true); + this.put("honey", true); + this.put("hood", true); + this.put("hope", true); + this.put("horn", true); + this.put("horror", true); + this.put("horse", true); + this.put("hospital", true); + this.put("host", true); + this.put("hotel", true); + this.put("hour", true); + this.put("hover", true); + this.put("hub", true); + this.put("huge", true); + this.put("human", true); + this.put("humble", true); + this.put("humor", true); + this.put("hundred", true); + this.put("hungry", true); + this.put("hunt", true); + this.put("hurdle", true); + this.put("hurry", true); + this.put("hurt", true); + this.put("husband", true); + this.put("hybrid", true); + this.put("ice", true); + this.put("icon", true); + this.put("idea", true); + this.put("identify", true); + this.put("idle", true); + this.put("ignore", true); + this.put("ill", true); + this.put("illegal", true); + this.put("illness", true); + this.put("image", true); + this.put("imitate", true); + this.put("immense", true); + this.put("immune", true); + this.put("impact", true); + this.put("impose", true); + this.put("improve", true); + this.put("impulse", true); + this.put("inch", true); + this.put("include", true); + this.put("income", true); + this.put("increase", true); + this.put("index", true); + this.put("indicate", true); + this.put("indoor", true); + this.put("industry", true); + this.put("infant", true); + this.put("inflict", true); + this.put("inform", true); + this.put("inhale", true); + this.put("inherit", true); + this.put("initial", true); + this.put("inject", true); + this.put("injury", true); + this.put("inmate", true); + this.put("inner", true); + this.put("innocent", true); + this.put("input", true); + this.put("inquiry", true); + this.put("insane", true); + this.put("insect", true); + this.put("inside", true); + this.put("inspire", true); + this.put("install", true); + this.put("intact", true); + this.put("interest", true); + this.put("into", true); + this.put("invest", true); + this.put("invite", true); + this.put("involve", true); + this.put("iron", true); + this.put("island", true); + this.put("isolate", true); + this.put("issue", true); + this.put("item", true); + this.put("ivory", true); + this.put("jacket", true); + this.put("jaguar", true); + this.put("jar", true); + this.put("jazz", true); + this.put("jealous", true); + this.put("jeans", true); + this.put("jelly", true); + this.put("jewel", true); + this.put("job", true); + this.put("join", true); + this.put("joke", true); + this.put("journey", true); + this.put("joy", true); + this.put("judge", true); + this.put("juice", true); + this.put("jump", true); + this.put("jungle", true); + this.put("junior", true); + this.put("junk", true); + this.put("just", true); + this.put("kangaroo", true); + this.put("keen", true); + this.put("keep", true); + this.put("ketchup", true); + this.put("key", true); + this.put("kick", true); + this.put("kid", true); + this.put("kidney", true); + this.put("kind", true); + this.put("kingdom", true); + this.put("kiss", true); + this.put("kit", true); + this.put("kitchen", true); + this.put("kite", true); + this.put("kitten", true); + this.put("kiwi", true); + this.put("knee", true); + this.put("knife", true); + this.put("knock", true); + this.put("know", true); + this.put("lab", true); + this.put("label", true); + this.put("labor", true); + this.put("ladder", true); + this.put("lady", true); + this.put("lake", true); + this.put("lamp", true); + this.put("language", true); + this.put("laptop", true); + this.put("large", true); + this.put("later", true); + this.put("latin", true); + this.put("laugh", true); + this.put("laundry", true); + this.put("lava", true); + this.put("law", true); + this.put("lawn", true); + this.put("lawsuit", true); + this.put("layer", true); + this.put("lazy", true); + this.put("leader", true); + this.put("leaf", true); + this.put("learn", true); + this.put("leave", true); + this.put("lecture", true); + this.put("left", true); + this.put("leg", true); + this.put("legal", true); + this.put("legend", true); + this.put("leisure", true); + this.put("lemon", true); + this.put("lend", true); + this.put("length", true); + this.put("lens", true); + this.put("leopard", true); + this.put("lesson", true); + this.put("letter", true); + this.put("level", true); + this.put("liar", true); + this.put("liberty", true); + this.put("library", true); + this.put("license", true); + this.put("life", true); + this.put("lift", true); + this.put("light", true); + this.put("like", true); + this.put("limb", true); + this.put("limit", true); + this.put("link", true); + this.put("lion", true); + this.put("liquid", true); + this.put("list", true); + this.put("little", true); + this.put("live", true); + this.put("lizard", true); + this.put("load", true); + this.put("loan", true); + this.put("lobster", true); + this.put("local", true); + this.put("lock", true); + this.put("logic", true); + this.put("lonely", true); + this.put("long", true); + this.put("loop", true); + this.put("lottery", true); + this.put("loud", true); + this.put("lounge", true); + this.put("love", true); + this.put("loyal", true); + this.put("lucky", true); + this.put("luggage", true); + this.put("lumber", true); + this.put("lunar", true); + this.put("lunch", true); + this.put("luxury", true); + this.put("lyrics", true); + this.put("machine", true); + this.put("mad", true); + this.put("magic", true); + this.put("magnet", true); + this.put("maid", true); + this.put("mail", true); + this.put("main", true); + this.put("major", true); + this.put("make", true); + this.put("mammal", true); + this.put("man", true); + this.put("manage", true); + this.put("mandate", true); + this.put("mango", true); + this.put("mansion", true); + this.put("manual", true); + this.put("maple", true); + this.put("marble", true); + this.put("march", true); + this.put("margin", true); + this.put("marine", true); + this.put("market", true); + this.put("marriage", true); + this.put("mask", true); + this.put("mass", true); + this.put("master", true); + this.put("match", true); + this.put("material", true); + this.put("math", true); + this.put("matrix", true); + this.put("matter", true); + this.put("maximum", true); + this.put("maze", true); + this.put("meadow", true); + this.put("mean", true); + this.put("measure", true); + this.put("meat", true); + this.put("mechanic", true); + this.put("medal", true); + this.put("media", true); + this.put("melody", true); + this.put("melt", true); + this.put("member", true); + this.put("memory", true); + this.put("mention", true); + this.put("menu", true); + this.put("mercy", true); + this.put("merge", true); + this.put("merit", true); + this.put("merry", true); + this.put("mesh", true); + this.put("message", true); + this.put("metal", true); + this.put("method", true); + this.put("middle", true); + this.put("midnight", true); + this.put("milk", true); + this.put("million", true); + this.put("mimic", true); + this.put("mind", true); + this.put("minimum", true); + this.put("minor", true); + this.put("minute", true); + this.put("miracle", true); + this.put("mirror", true); + this.put("misery", true); + this.put("miss", true); + this.put("mistake", true); + this.put("mix", true); + this.put("mixed", true); + this.put("mixture", true); + this.put("mobile", true); + this.put("model", true); + this.put("modify", true); + this.put("mom", true); + this.put("moment", true); + this.put("monitor", true); + this.put("monkey", true); + this.put("monster", true); + this.put("month", true); + this.put("moon", true); + this.put("moral", true); + this.put("more", true); + this.put("morning", true); + this.put("mosquito", true); + this.put("mother", true); + this.put("motion", true); + this.put("motor", true); + this.put("mountain", true); + this.put("mouse", true); + this.put("move", true); + this.put("movie", true); + this.put("much", true); + this.put("muffin", true); + this.put("mule", true); + this.put("multiply", true); + this.put("muscle", true); + this.put("museum", true); + this.put("mushroom", true); + this.put("music", true); + this.put("must", true); + this.put("mutual", true); + this.put("myself", true); + this.put("mystery", true); + this.put("myth", true); + this.put("naive", true); + this.put("name", true); + this.put("napkin", true); + this.put("narrow", true); + this.put("nasty", true); + this.put("nation", true); + this.put("nature", true); + this.put("near", true); + this.put("neck", true); + this.put("need", true); + this.put("negative", true); + this.put("neglect", true); + this.put("neither", true); + this.put("nephew", true); + this.put("nerve", true); + this.put("nest", true); + this.put("net", true); + this.put("network", true); + this.put("neutral", true); + this.put("never", true); + this.put("news", true); + this.put("next", true); + this.put("nice", true); + this.put("night", true); + this.put("noble", true); + this.put("noise", true); + this.put("nominee", true); + this.put("noodle", true); + this.put("normal", true); + this.put("north", true); + this.put("nose", true); + this.put("notable", true); + this.put("note", true); + this.put("nothing", true); + this.put("notice", true); + this.put("novel", true); + this.put("now", true); + this.put("nuclear", true); + this.put("number", true); + this.put("nurse", true); + this.put("nut", true); + this.put("oak", true); + this.put("obey", true); + this.put("object", true); + this.put("oblige", true); + this.put("obscure", true); + this.put("observe", true); + this.put("obtain", true); + this.put("obvious", true); + this.put("occur", true); + this.put("ocean", true); + this.put("october", true); + this.put("odor", true); + this.put("off", true); + this.put("offer", true); + this.put("office", true); + this.put("often", true); + this.put("oil", true); + this.put("okay", true); + this.put("old", true); + this.put("olive", true); + this.put("olympic", true); + this.put("omit", true); + this.put("once", true); + this.put("one", true); + this.put("onion", true); + this.put("online", true); + this.put("only", true); + this.put("open", true); + this.put("opera", true); + this.put("opinion", true); + this.put("oppose", true); + this.put("option", true); + this.put("orange", true); + this.put("orbit", true); + this.put("orchard", true); + this.put("order", true); + this.put("ordinary", true); + this.put("organ", true); + this.put("orient", true); + this.put("original", true); + this.put("orphan", true); + this.put("ostrich", true); + this.put("other", true); + this.put("outdoor", true); + this.put("outer", true); + this.put("output", true); + this.put("outside", true); + this.put("oval", true); + this.put("oven", true); + this.put("over", true); + this.put("own", true); + this.put("owner", true); + this.put("oxygen", true); + this.put("oyster", true); + this.put("ozone", true); + this.put("pact", true); + this.put("paddle", true); + this.put("page", true); + this.put("pair", true); + this.put("palace", true); + this.put("palm", true); + this.put("panda", true); + this.put("panel", true); + this.put("panic", true); + this.put("panther", true); + this.put("paper", true); + this.put("parade", true); + this.put("parent", true); + this.put("park", true); + this.put("parrot", true); + this.put("party", true); + this.put("pass", true); + this.put("patch", true); + this.put("path", true); + this.put("patient", true); + this.put("patrol", true); + this.put("pattern", true); + this.put("pause", true); + this.put("pave", true); + this.put("payment", true); + this.put("peace", true); + this.put("peanut", true); + this.put("pear", true); + this.put("peasant", true); + this.put("pelican", true); + this.put("pen", true); + this.put("penalty", true); + this.put("pencil", true); + this.put("people", true); + this.put("pepper", true); + this.put("perfect", true); + this.put("permit", true); + this.put("person", true); + this.put("pet", true); + this.put("phone", true); + this.put("photo", true); + this.put("phrase", true); + this.put("physical", true); + this.put("piano", true); + this.put("picnic", true); + this.put("picture", true); + this.put("piece", true); + this.put("pig", true); + this.put("pigeon", true); + this.put("pill", true); + this.put("pilot", true); + this.put("pink", true); + this.put("pioneer", true); + this.put("pipe", true); + this.put("pistol", true); + this.put("pitch", true); + this.put("pizza", true); + this.put("place", true); + this.put("planet", true); + this.put("plastic", true); + this.put("plate", true); + this.put("play", true); + this.put("please", true); + this.put("pledge", true); + this.put("pluck", true); + this.put("plug", true); + this.put("plunge", true); + this.put("poem", true); + this.put("poet", true); + this.put("point", true); + this.put("polar", true); + this.put("pole", true); + this.put("police", true); + this.put("pond", true); + this.put("pony", true); + this.put("pool", true); + this.put("popular", true); + this.put("portion", true); + this.put("position", true); + this.put("possible", true); + this.put("post", true); + this.put("potato", true); + this.put("pottery", true); + this.put("poverty", true); + this.put("powder", true); + this.put("power", true); + this.put("practice", true); + this.put("praise", true); + this.put("predict", true); + this.put("prefer", true); + this.put("prepare", true); + this.put("present", true); + this.put("pretty", true); + this.put("prevent", true); + this.put("price", true); + this.put("pride", true); + this.put("primary", true); + this.put("print", true); + this.put("priority", true); + this.put("prison", true); + this.put("private", true); + this.put("prize", true); + this.put("problem", true); + this.put("process", true); + this.put("produce", true); + this.put("profit", true); + this.put("program", true); + this.put("project", true); + this.put("promote", true); + this.put("proof", true); + this.put("property", true); + this.put("prosper", true); + this.put("protect", true); + this.put("proud", true); + this.put("provide", true); + this.put("public", true); + this.put("pudding", true); + this.put("pull", true); + this.put("pulp", true); + this.put("pulse", true); + this.put("pumpkin", true); + this.put("punch", true); + this.put("pupil", true); + this.put("puppy", true); + this.put("purchase", true); + this.put("purity", true); + this.put("purpose", true); + this.put("purse", true); + this.put("push", true); + this.put("put", true); + this.put("puzzle", true); + this.put("pyramid", true); + this.put("quality", true); + this.put("quantum", true); + this.put("quarter", true); + this.put("question", true); + this.put("quick", true); + this.put("quit", true); + this.put("quiz", true); + this.put("quote", true); + this.put("rabbit", true); + this.put("raccoon", true); + this.put("race", true); + this.put("rack", true); + this.put("radar", true); + this.put("radio", true); + this.put("rail", true); + this.put("rain", true); + this.put("raise", true); + this.put("rally", true); + this.put("ramp", true); + this.put("ranch", true); + this.put("random", true); + this.put("range", true); + this.put("rapid", true); + this.put("rare", true); + this.put("rate", true); + this.put("rather", true); + this.put("raven", true); + this.put("raw", true); + this.put("razor", true); + this.put("ready", true); + this.put("real", true); + this.put("reason", true); + this.put("rebel", true); + this.put("rebuild", true); + this.put("recall", true); + this.put("receive", true); + this.put("recipe", true); + this.put("record", true); + this.put("recycle", true); + this.put("reduce", true); + this.put("reflect", true); + this.put("reform", true); + this.put("refuse", true); + this.put("region", true); + this.put("regret", true); + this.put("regular", true); + this.put("reject", true); + this.put("relax", true); + this.put("release", true); + this.put("relief", true); + this.put("rely", true); + this.put("remain", true); + this.put("remember", true); + this.put("remind", true); + this.put("remove", true); + this.put("render", true); + this.put("renew", true); + this.put("rent", true); + this.put("reopen", true); + this.put("repair", true); + this.put("repeat", true); + this.put("replace", true); + this.put("report", true); + this.put("require", true); + this.put("rescue", true); + this.put("resemble", true); + this.put("resist", true); + this.put("resource", true); + this.put("response", true); + this.put("result", true); + this.put("retire", true); + this.put("retreat", true); + this.put("return", true); + this.put("reunion", true); + this.put("reveal", true); + this.put("review", true); + this.put("reward", true); + this.put("rhythm", true); + this.put("rib", true); + this.put("ribbon", true); + this.put("rice", true); + this.put("rich", true); + this.put("ride", true); + this.put("ridge", true); + this.put("rifle", true); + this.put("right", true); + this.put("rigid", true); + this.put("ring", true); + this.put("riot", true); + this.put("ripple", true); + this.put("risk", true); + this.put("ritual", true); + this.put("rival", true); + this.put("river", true); + this.put("road", true); + this.put("roast", true); + this.put("robot", true); + this.put("robust", true); + this.put("rocket", true); + this.put("romance", true); + this.put("roof", true); + this.put("rookie", true); + this.put("room", true); + this.put("rose", true); + this.put("rotate", true); + this.put("rough", true); + this.put("round", true); + this.put("route", true); + this.put("royal", true); + this.put("rubber", true); + this.put("rude", true); + this.put("rug", true); + this.put("rule", true); + this.put("run", true); + this.put("runway", true); + this.put("rural", true); + this.put("sad", true); + this.put("saddle", true); + this.put("sadness", true); + this.put("safe", true); + this.put("sail", true); + this.put("salad", true); + this.put("salmon", true); + this.put("salon", true); + this.put("salt", true); + this.put("salute", true); + this.put("same", true); + this.put("sample", true); + this.put("sand", true); + this.put("satisfy", true); + this.put("satoshi", true); + this.put("sauce", true); + this.put("sausage", true); + this.put("save", true); + this.put("say", true); + this.put("scale", true); + this.put("scan", true); + this.put("scare", true); + this.put("scatter", true); + this.put("scene", true); + this.put("scheme", true); + this.put("school", true); + this.put("science", true); + this.put("scissors", true); + this.put("scorpion", true); + this.put("scout", true); + this.put("scrap", true); + this.put("screen", true); + this.put("script", true); + this.put("scrub", true); + this.put("sea", true); + this.put("search", true); + this.put("season", true); + this.put("seat", true); + this.put("second", true); + this.put("secret", true); + this.put("section", true); + this.put("security", true); + this.put("seed", true); + this.put("seek", true); + this.put("segment", true); + this.put("select", true); + this.put("sell", true); + this.put("seminar", true); + this.put("senior", true); + this.put("sense", true); + this.put("sentence", true); + this.put("series", true); + this.put("service", true); + this.put("session", true); + this.put("settle", true); + this.put("setup", true); + this.put("seven", true); + this.put("shadow", true); + this.put("shaft", true); + this.put("shallow", true); + this.put("share", true); + this.put("shed", true); + this.put("shell", true); + this.put("sheriff", true); + this.put("shield", true); + this.put("shift", true); + this.put("shine", true); + this.put("ship", true); + this.put("shiver", true); + this.put("shock", true); + this.put("shoe", true); + this.put("shoot", true); + this.put("shop", true); + this.put("short", true); + this.put("shoulder", true); + this.put("shove", true); + this.put("shrimp", true); + this.put("shrug", true); + this.put("shuffle", true); + this.put("shy", true); + this.put("sibling", true); + this.put("sick", true); + this.put("side", true); + this.put("siege", true); + this.put("sight", true); + this.put("sign", true); + this.put("silent", true); + this.put("silk", true); + this.put("silly", true); + this.put("silver", true); + this.put("similar", true); + this.put("simple", true); + this.put("since", true); + this.put("sing", true); + this.put("siren", true); + this.put("sister", true); + this.put("situate", true); + this.put("six", true); + this.put("size", true); + this.put("skate", true); + this.put("sketch", true); + this.put("ski", true); + this.put("skill", true); + this.put("skin", true); + this.put("skirt", true); + this.put("skull", true); + this.put("slab", true); + this.put("slam", true); + this.put("sleep", true); + this.put("slender", true); + this.put("slice", true); + this.put("slide", true); + this.put("slight", true); + this.put("slim", true); + this.put("slogan", true); + this.put("slot", true); + this.put("slow", true); + this.put("slush", true); + this.put("small", true); + this.put("smart", true); + this.put("smile", true); + this.put("smoke", true); + this.put("smooth", true); + this.put("snack", true); + this.put("snake", true); + this.put("snap", true); + this.put("sniff", true); + this.put("snow", true); + this.put("soap", true); + this.put("soccer", true); + this.put("social", true); + this.put("sock", true); + this.put("soda", true); + this.put("soft", true); + this.put("solar", true); + this.put("soldier", true); + this.put("solid", true); + this.put("solution", true); + this.put("solve", true); + this.put("someone", true); + this.put("song", true); + this.put("soon", true); + this.put("sorry", true); + this.put("sort", true); + this.put("soul", true); + this.put("sound", true); + this.put("soup", true); + this.put("source", true); + this.put("south", true); + this.put("space", true); + this.put("spare", true); + this.put("spatial", true); + this.put("spawn", true); + this.put("speak", true); + this.put("special", true); + this.put("speed", true); + this.put("spell", true); + this.put("spend", true); + this.put("sphere", true); + this.put("spice", true); + this.put("spider", true); + this.put("spike", true); + this.put("spin", true); + this.put("spirit", true); + this.put("split", true); + this.put("spoil", true); + this.put("sponsor", true); + this.put("spoon", true); + this.put("sport", true); + this.put("spot", true); + this.put("spray", true); + this.put("spread", true); + this.put("spring", true); + this.put("spy", true); + this.put("square", true); + this.put("squeeze", true); + this.put("squirrel", true); + this.put("stable", true); + this.put("stadium", true); + this.put("staff", true); + this.put("stage", true); + this.put("stairs", true); + this.put("stamp", true); + this.put("stand", true); + this.put("start", true); + this.put("state", true); + this.put("stay", true); + this.put("steak", true); + this.put("steel", true); + this.put("stem", true); + this.put("step", true); + this.put("stereo", true); + this.put("stick", true); + this.put("still", true); + this.put("sting", true); + this.put("stock", true); + this.put("stomach", true); + this.put("stone", true); + this.put("stool", true); + this.put("story", true); + this.put("stove", true); + this.put("strategy", true); + this.put("street", true); + this.put("strike", true); + this.put("strong", true); + this.put("struggle", true); + this.put("student", true); + this.put("stuff", true); + this.put("stumble", true); + this.put("style", true); + this.put("subject", true); + this.put("submit", true); + this.put("subway", true); + this.put("success", true); + this.put("such", true); + this.put("sudden", true); + this.put("suffer", true); + this.put("sugar", true); + this.put("suggest", true); + this.put("suit", true); + this.put("summer", true); + this.put("sun", true); + this.put("sunny", true); + this.put("sunset", true); + this.put("super", true); + this.put("supply", true); + this.put("supreme", true); + this.put("sure", true); + this.put("surface", true); + this.put("surge", true); + this.put("surprise", true); + this.put("surround", true); + this.put("survey", true); + this.put("suspect", true); + this.put("sustain", true); + this.put("swallow", true); + this.put("swamp", true); + this.put("swap", true); + this.put("swarm", true); + this.put("swear", true); + this.put("sweet", true); + this.put("swift", true); + this.put("swim", true); + this.put("swing", true); + this.put("switch", true); + this.put("sword", true); + this.put("symbol", true); + this.put("symptom", true); + this.put("syrup", true); + this.put("system", true); + this.put("table", true); + this.put("tackle", true); + this.put("tag", true); + this.put("tail", true); + this.put("talent", true); + this.put("talk", true); + this.put("tank", true); + this.put("tape", true); + this.put("target", true); + this.put("task", true); + this.put("taste", true); + this.put("tattoo", true); + this.put("taxi", true); + this.put("teach", true); + this.put("team", true); + this.put("tell", true); + this.put("ten", true); + this.put("tenant", true); + this.put("tennis", true); + this.put("tent", true); + this.put("term", true); + this.put("test", true); + this.put("text", true); + this.put("thank", true); + this.put("that", true); + this.put("theme", true); + this.put("then", true); + this.put("theory", true); + this.put("there", true); + this.put("they", true); + this.put("thing", true); + this.put("this", true); + this.put("thought", true); + this.put("three", true); + this.put("thrive", true); + this.put("throw", true); + this.put("thumb", true); + this.put("thunder", true); + this.put("ticket", true); + this.put("tide", true); + this.put("tiger", true); + this.put("tilt", true); + this.put("timber", true); + this.put("time", true); + this.put("tiny", true); + this.put("tip", true); + this.put("tired", true); + this.put("tissue", true); + this.put("title", true); + this.put("toast", true); + this.put("tobacco", true); + this.put("today", true); + this.put("toddler", true); + this.put("toe", true); + this.put("together", true); + this.put("toilet", true); + this.put("token", true); + this.put("tomato", true); + this.put("tomorrow", true); + this.put("tone", true); + this.put("tongue", true); + this.put("tonight", true); + this.put("tool", true); + this.put("tooth", true); + this.put("top", true); + this.put("topic", true); + this.put("topple", true); + this.put("torch", true); + this.put("tornado", true); + this.put("tortoise", true); + this.put("toss", true); + this.put("total", true); + this.put("tourist", true); + this.put("toward", true); + this.put("tower", true); + this.put("town", true); + this.put("toy", true); + this.put("track", true); + this.put("trade", true); + this.put("traffic", true); + this.put("tragic", true); + this.put("train", true); + this.put("transfer", true); + this.put("trap", true); + this.put("trash", true); + this.put("travel", true); + this.put("tray", true); + this.put("treat", true); + this.put("tree", true); + this.put("trend", true); + this.put("trial", true); + this.put("tribe", true); + this.put("trick", true); + this.put("trigger", true); + this.put("trim", true); + this.put("trip", true); + this.put("trophy", true); + this.put("trouble", true); + this.put("truck", true); + this.put("true", true); + this.put("truly", true); + this.put("trumpet", true); + this.put("trust", true); + this.put("truth", true); + this.put("try", true); + this.put("tube", true); + this.put("tuition", true); + this.put("tumble", true); + this.put("tuna", true); + this.put("tunnel", true); + this.put("turkey", true); + this.put("turn", true); + this.put("turtle", true); + this.put("twelve", true); + this.put("twenty", true); + this.put("twice", true); + this.put("twin", true); + this.put("twist", true); + this.put("two", true); + this.put("type", true); + this.put("typical", true); + this.put("ugly", true); + this.put("umbrella", true); + this.put("unable", true); + this.put("unaware", true); + this.put("uncle", true); + this.put("uncover", true); + this.put("under", true); + this.put("undo", true); + this.put("unfair", true); + this.put("unfold", true); + this.put("unhappy", true); + this.put("uniform", true); + this.put("unique", true); + this.put("unit", true); + this.put("universe", true); + this.put("unknown", true); + this.put("unlock", true); + this.put("until", true); + this.put("unusual", true); + this.put("unveil", true); + this.put("update", true); + this.put("upgrade", true); + this.put("uphold", true); + this.put("upon", true); + this.put("upper", true); + this.put("upset", true); + this.put("urban", true); + this.put("urge", true); + this.put("usage", true); + this.put("use", true); + this.put("used", true); + this.put("useful", true); + this.put("useless", true); + this.put("usual", true); + this.put("utility", true); + this.put("vacant", true); + this.put("vacuum", true); + this.put("vague", true); + this.put("valid", true); + this.put("valley", true); + this.put("valve", true); + this.put("van", true); + this.put("vanish", true); + this.put("vapor", true); + this.put("various", true); + this.put("vast", true); + this.put("vault", true); + this.put("vehicle", true); + this.put("velvet", true); + this.put("vendor", true); + this.put("venture", true); + this.put("venue", true); + this.put("verb", true); + this.put("verify", true); + this.put("version", true); + this.put("very", true); + this.put("vessel", true); + this.put("veteran", true); + this.put("viable", true); + this.put("vibrant", true); + this.put("vicious", true); + this.put("victory", true); + this.put("video", true); + this.put("view", true); + this.put("village", true); + this.put("vintage", true); + this.put("violin", true); + this.put("virtual", true); + this.put("virus", true); + this.put("visa", true); + this.put("visit", true); + this.put("visual", true); + this.put("vital", true); + this.put("vivid", true); + this.put("vocal", true); + this.put("voice", true); + this.put("void", true); + this.put("volcano", true); + this.put("volume", true); + this.put("vote", true); + this.put("voyage", true); + this.put("wage", true); + this.put("wagon", true); + this.put("wait", true); + this.put("walk", true); + this.put("wall", true); + this.put("walnut", true); + this.put("want", true); + this.put("warfare", true); + this.put("warm", true); + this.put("warrior", true); + this.put("wash", true); + this.put("wasp", true); + this.put("waste", true); + this.put("water", true); + this.put("wave", true); + this.put("way", true); + this.put("wealth", true); + this.put("weapon", true); + this.put("wear", true); + this.put("weasel", true); + this.put("weather", true); + this.put("web", true); + this.put("wedding", true); + this.put("weekend", true); + this.put("weird", true); + this.put("welcome", true); + this.put("west", true); + this.put("wet", true); + this.put("whale", true); + this.put("what", true); + this.put("wheat", true); + this.put("wheel", true); + this.put("when", true); + this.put("where", true); + this.put("whip", true); + this.put("whisper", true); + this.put("wide", true); + this.put("width", true); + this.put("wife", true); + this.put("wild", true); + this.put("will", true); + this.put("win", true); + this.put("window", true); + this.put("wine", true); + this.put("wing", true); + this.put("wink", true); + this.put("winner", true); + this.put("winter", true); + this.put("wire", true); + this.put("wisdom", true); + this.put("wise", true); + this.put("wish", true); + this.put("witness", true); + this.put("wolf", true); + this.put("woman", true); + this.put("wonder", true); + this.put("wood", true); + this.put("wool", true); + this.put("word", true); + this.put("work", true); + this.put("world", true); + this.put("worry", true); + this.put("worth", true); + this.put("wrap", true); + this.put("wreck", true); + this.put("wrestle", true); + this.put("wrist", true); + this.put("write", true); + this.put("wrong", true); + this.put("yard", true); + this.put("year", true); + this.put("yellow", true); + this.put("you", true); + this.put("young", true); + this.put("youth", true); + this.put("zebra", true); + this.put("zero", true); + this.put("zone", true); + this.put("zoo", true); + }}; + + public static int HARDENED_BIT = 0x80000000; + public static String derivationPathBCD0 = "m/44'/999'/0'/0/0"; // Bitcoin Diamond + public static String derivationPathBCD1 = "m/44'/999'/1'/0/0"; + public static String derivationPathBCD2 = "m/44'/999'/2'/0/0"; + public static String derivationPathBCH0 = "m/44'/145'/0'/0/0"; // Bitcoin Cash + public static String derivationPathBCH1 = "m/44'/145'/1'/0/0"; + public static String derivationPathBCH2 = "m/44'/145'/2'/0/0"; + public static String derivationPathBSV0 = "m/44'/145'/0'/0/0"; // Bitcoin SV + public static String derivationPathBSV1 = "m/44'/145'/1'/0/0"; + public static String derivationPathBSV2 = "m/44'/145'/2'/0/0"; + public static final int[] derivationPathBTC0 = {44 | HARDENED_BIT, 0 | HARDENED_BIT, 0 | HARDENED_BIT, 0, 0}; + /** + * BIP-44 m/purpose/coin_type/account/change/address_index + */ + public static String derivationPathBTC0_str = "m/44'/0'/0'/0/0"; // Bitcoin + public static final int[] derivationPathBTC1 = {44 | HARDENED_BIT, 0 | HARDENED_BIT, 1 | HARDENED_BIT, 0, 0}; + public static String derivationPathBTC1_str = "m/44'/0'/1'/0/0"; + public static final int[] derivationPathBTC2 = {44 | HARDENED_BIT, 0 | HARDENED_BIT, 2 | HARDENED_BIT, 0, 0}; + public static String derivationPathBTC2_str = "m/44'/0'/2'/0/0"; + public static final int[] derivationPathBTC3 = {44 | HARDENED_BIT, 0 | HARDENED_BIT, 3 | HARDENED_BIT, 0, 0}; + public static String derivationPathBTC3_str = "m/44'/0'/3'/0/0"; + public static final int[] derivationPathBTC4 = {44 | HARDENED_BIT, 0 | HARDENED_BIT, 4 | HARDENED_BIT, 0, 0}; + public static String derivationPathBTC4_str = "m/44'/0'/4'/0/0"; + public static final int[] derivationPathBTC5 = {44 | HARDENED_BIT, 0 | HARDENED_BIT, 5 | HARDENED_BIT, 0, 0}; + public static String derivationPathBTC5_str = "m/44'/0'/5'/0/0"; + public static final int[] derivationPathBTC6 = {44 | HARDENED_BIT, 0 | HARDENED_BIT, 6 | HARDENED_BIT, 0, 0}; + public static String derivationPathBTC6_str = "m/44'/0'/6'/0/0"; + public static final int[] derivationPathBTC7 = {44 | HARDENED_BIT, 0 | HARDENED_BIT, 7 | HARDENED_BIT, 0, 0}; + public static String derivationPathBTC7_str = "m/44'/0'/7'/0/0"; + public static final int[] derivationPathBTC8 = {44 | HARDENED_BIT, 0 | HARDENED_BIT, 8 | HARDENED_BIT, 0, 0}; + public static String derivationPathBTC8_str = "m/44'/0'/8'/0/0"; + public static final int[] derivationPathBTC9 = {44 | HARDENED_BIT, 0 | HARDENED_BIT, 9 | HARDENED_BIT, 0, 0}; + public static String derivationPathBTC9_str = "m/44'/0'/9'/0/0"; + public static String derivationPathBTG0 = "m/44'/0'/0'/0/0"; // Bitcoin Gold + public static String derivationPathBTG1 = "m/44'/0'/1'/0/0"; + public static String derivationPathBTG2 = "m/44'/0'/2'/0/0"; + public static String derivationPathCARDANO0 = "m/44'/1815'/0'/0/0"; // Cardano + public static String derivationPathCARDANO1 = "m/44'/1815'/1'/0/0"; + public static String derivationPathCARDANO2 = "m/44'/1815'/2'/0/0"; + public static String derivationPathCOSMOS0 = "m/44'/1815'/0'/0/0"; // Cosmos + public static String derivationPathCOSMOS1 = "m/44'/1815'/1'/0/0"; + public static String derivationPathCOSMOS2 = "m/44'/1815'/2'/0/0"; + public static String derivationPathDASG0 = "m/44'/5'/0'"; // Dash + public static String derivationPathDASH1 = "m/44'/5'/1'"; + public static String derivationPathDASH2 = "m/44'/5'/2'"; + public static String derivationPathDCR0 = "m/44'/999'/0'/0/0"; // Decred + public static String derivationPathDCR1 = "m/44'/999'/1'/0/0"; + public static String derivationPathDCR2 = "m/44'/999'/2'/0/0"; + public static String derivationPathDGB0 = "m/44'/20'/0'/0/0"; // DigiByte + public static String derivationPathDGB1 = "m/44'/20'/1'/0/0"; + public static String derivationPathDGB2 = "m/44'/20'/2'/0/0"; + public static String derivationPathDOGE0 = "m/44'/3'/0'/0/0"; // DOGE + public static String derivationPathDOGE1 = "m/44'/3'/1'/0/0"; + public static String derivationPathDOGE2 = "m/44'/3'/2'/0/0"; + public static String derivationPathDOT0 = "m/44'/354'/0'/0/0"; // DOT + public static String derivationPathDOT1 = "m/44'/354'/1'/0/0"; + public static String derivationPathDOT2 = "m/44'/354'/2'/0/0"; + public static final int[] derivationPathETH0 = {44 | HARDENED_BIT, 60 | HARDENED_BIT, 0 | HARDENED_BIT, 0, 0}; + public static String derivationPathETH0_str = "m/44'/60'/0'/0/0"; // ETH + public static final int[] derivationPathETH1 = {44 | HARDENED_BIT, 60 | HARDENED_BIT, 1 | HARDENED_BIT, 0, 0}; + public static String derivationPathETH1_str = "m/44'/60'/1'/0/0"; + public static final int[] derivationPathETH2 = {44 | HARDENED_BIT, 60 | HARDENED_BIT, 2 | HARDENED_BIT, 0, 0}; + public static String derivationPathETH2_str = "m/44'/60'/2'/0/0"; + public static final int[] derivationPathETH3 = {44 | HARDENED_BIT, 60 | HARDENED_BIT, 3 | HARDENED_BIT, 0, 0}; + public static String derivationPathETH3_str = "m/44'/60'/3'/0/0"; + public static final int[] derivationPathETH4 = {44 | HARDENED_BIT, 60 | HARDENED_BIT, 4 | HARDENED_BIT, 0, 0}; + public static String derivationPathETH4_str = "m/44'/60'/4'/0/0"; + public static final int[] derivationPathETH5 = {44 | HARDENED_BIT, 60 | HARDENED_BIT, 5 | HARDENED_BIT, 0, 0}; + public static String derivationPathETH5_str = "m/44'/60'/5'/0/0"; + public static final int[] derivationPathETH6 = {44 | HARDENED_BIT, 60 | HARDENED_BIT, 6 | HARDENED_BIT, 0, 0}; + public static String derivationPathETH6_str = "m/44'/60'/6'/0/0"; + public static final int[] derivationPathETH7 = {44 | HARDENED_BIT, 60 | HARDENED_BIT, 7 | HARDENED_BIT, 0, 0}; + public static String derivationPathETH7_str = "m/44'/60'/7'/0/0"; + public static final int[] derivationPathETH8 = {44 | HARDENED_BIT, 60 | HARDENED_BIT, 8 | HARDENED_BIT, 0, 0}; + public static String derivationPathETH8_str = "m/44'/60'/8'/0/0"; + public static final int[] derivationPathETH9 = {44 | HARDENED_BIT, 60 | HARDENED_BIT, 9 | HARDENED_BIT, 0, 0}; + public static String derivationPathETH9_str = "m/44'/60'/9'/0/0"; + public static String derivationPathGAS0 = "m/44'/888'/0'/0"; // GAS + public static String derivationPathGAS1 = "m/44'/888'/1'/0"; + public static String derivationPathGAS2 = "m/44'/888'/2'/0"; + public static String derivationPathGRS0 = "m/44'/0'/0'/0/0"; // Groestlcoin + public static String derivationPathGRS1 = "m/44'/0'/1'/0/0"; + public static String derivationPathGRS2 = "m/44'/0'/2'/0/0"; + public static String derivationPathKIN0 = "m/44'/148'/0'"; // Kin + public static String derivationPathKIN1 = "m/44'/148'/1'"; + public static String derivationPathKIN2 = "m/44'/148'/2'"; + public static String derivationPathLSK0 = "m/44'/148'/0'"; // Lisk + public static String derivationPathLSK1 = "m/44'/148'/1'"; + public static String derivationPathLSK2 = "m/44'/148'/2'"; + public static String derivationPathLTC0 = "m/44'/60'/0'/0/0"; // Litecoin + public static String derivationPathLTC1 = "m/44'/60'/1'/0/0"; + public static String derivationPathLTC2 = "m/44'/60'/2'/0/0"; + public static String derivationPathNEO0 = "m/44'/888'/0'/0"; // NEO + public static String derivationPathNEO1 = "m/44'/888'/1'/0"; + public static String derivationPathNEO2 = "m/44'/888'/2'/0"; + public static String derivationPathONG0 = "m/44'/1024'/0'/0/0"; // ONG + public static String derivationPathONG1 = "m/44'/1024'/1'/0/0"; + public static String derivationPathONG2 = "m/44'/1024'/2'/0/0"; + public static String derivationPathQTUM0 = "m/44'/2301'/0'/0/0"; // QTUM + public static String derivationPathQTUM1 = "m/44'/2301'/1'/0/0"; + public static String derivationPathQTUM2 = "m/44'/2301'/2'/0/0"; + @SuppressWarnings("serial") + public static final ArrayList derivationPathsBTC = new ArrayList() {{ + this.add(derivationPathBTC0); + this.add(derivationPathBTC1); + this.add(derivationPathBTC2); + this.add(derivationPathBTC3); + this.add(derivationPathBTC4); + this.add(derivationPathBTC5); + this.add(derivationPathBTC6); + this.add(derivationPathBTC7); + this.add(derivationPathBTC8); + this.add(derivationPathBTC9); + }}; + @SuppressWarnings("serial") + public static final ArrayList derivationPathsETH = new ArrayList() {{ + this.add(derivationPathETH0); + this.add(derivationPathETH1); + this.add(derivationPathETH2); + this.add(derivationPathETH3); + this.add(derivationPathETH4); + this.add(derivationPathETH5); + this.add(derivationPathETH6); + this.add(derivationPathETH7); + this.add(derivationPathETH8); + this.add(derivationPathETH9); + }}; + public static String derivationPathSMART0 = "m/44'/224'/0'/0/0"; // SmartCash + public static String derivationPathSMART1 = "m/44'/224'/1'/0/0"; + public static String derivationPathSMART2 = "m/44'/224'/2'/0/0"; + public static String derivationPathSOL0 = "m/44'/501'/0'"; // Solana + public static String derivationPathSOL1 = "m/44'/501'/1'"; + public static String derivationPathSOL2 = "m/44'/501'/2'"; + public static String derivationPathTPAY0 = "m/44'/265'/0'"; // TokenPay + public static String derivationPathTPAY1 = "m/44'/265'/1'"; + public static String derivationPathTPAY2 = "m/44'/265'/2'"; + public static String derivationPathTRON0 = "m/44'/195'/0'"; // Tron + public static String derivationPathTRON1 = "m/44'/195'/1'"; + public static String derivationPathTRON2 = "m/44'/195'/2'"; + public static String derivationPathVET0 = "m/44'/818'/0'/0"; // Vechain + public static String derivationPathVET1 = "m/44'/818'/1'/0"; + public static String derivationPathVET2 = "m/44'/818'/2'/0"; + public static String derivationPathWAVES0 = "m/44'/5741564'/0'/0"; // Waves + public static String derivationPathWAVES1 = "m/44'/5741564'/1'/0"; + public static String derivationPathWAVES2 = "m/44'/5741564'/2'/0"; + public static String derivationPathXEM0 = "m/44'/43'/0'/0"; // Nem + public static String derivationPathXEM1 = "m/44'/43'/1'/0"; + public static String derivationPathXEM2 = "m/44'/43'/2'/0"; + public static String derivationPathXLM0 = "m/44'/148'/0'"; // Stellar + public static String derivationPathXLM1 = "m/44'/148'/1'"; + public static String derivationPathXLM2 = "m/44'/148'/2'"; + public static String derivationPathXRP0 = "m/44'/144'/0/0/0'"; // Ripple + public static String derivationPathXRP1 = "m/44'/144'/1/0/0'"; + public static String derivationPathXRP2 = "m/44'/144'/2/0/0'"; + public static String derivationPathXTZ0 = "m/44'/1729'/0/0/0'"; // Tezos + public static String derivationPathXTZ1 = "m/44'/1729'/1/0/0'"; + public static String derivationPathXTZ2 = "m/44'/1729'/2/0/0'"; + public static String derivationPathZEC0 = "m/44'/133'/0/0/0'"; // ZCash + public static String derivationPathZEC01 = "m/44'/133'/1/0/0'"; + public static String derivationPathZEC02 = "m/44'/133'/2/0/0'"; + +} diff --git a/src/main/java/crypto/forestfish/objects/embedded/avm/AccountDetailsAVM.java b/src/main/java/crypto/forestfish/objects/embedded/avm/AccountDetailsAVM.java new file mode 100644 index 0000000..1de0763 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/embedded/avm/AccountDetailsAVM.java @@ -0,0 +1,60 @@ +package crypto.forestfish.objects.embedded.avm; + +import java.util.ArrayList; +import java.util.HashMap; + +import crypto.forestfish.enums.AddressCategory; +import crypto.forestfish.enums.CustomContractCategory; +import crypto.forestfish.enums.avm.AVMChain; +import crypto.forestfish.objects.avm.AVMKnownAccountAddress; +import crypto.forestfish.objects.avm.AVMKnownCustomContractAddress; + +public class AccountDetailsAVM { + + @SuppressWarnings("serial") + public static HashMap getKnownAVMWalletAddresses() { + HashMap addresses = new HashMap<>(); + + // zero address + AVMKnownAccountAddress zero = new AVMKnownAccountAddress( + "Algorand encoded address of 32 zero bytes", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ ", + AddressCategory.CORE, + new ArrayList() {{ + this.add("https://developer.algorand.org/docs/get-details/accounts/"); + this.add("https://algoexplorer.io/address/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ"); + }}); + addresses.put(zero.getAddress(), zero); + + // testnetdispenser1 + AVMKnownAccountAddress testnetdispenser1 = new AVMKnownAccountAddress( + "Algorand Testnet Dispenser", + "HZ57J3K46JIJXILONBBZOHX6BKPXEM2VVXNRFSUED6DKFD5ZD24PMJ3MVA ", + AddressCategory.CORE, + new ArrayList() {{ + this.add("https://testnet.algoexplorer.io/address/HZ57J3K46JIJXILONBBZOHX6BKPXEM2VVXNRFSUED6DKFD5ZD24PMJ3MVA"); + this.add("https://dispenser.testnet.aws.algodev.network"); + }}); + addresses.put(testnetdispenser1.getAddress(), testnetdispenser1); + + return addresses; + } + + @SuppressWarnings("serial") + public static HashMap getKnownAVMCustomContractAddressesBSC() { + HashMap addresses = new HashMap<>(); + + // test + AVMKnownCustomContractAddress stargate_busd_staking = new AVMKnownCustomContractAddress( + "Stargate", + "0xe2fc31f816a9b94326492132018c3aecc4a93ae1", + AVMChain.MAINNET, + CustomContractCategory.STAKING, + new ArrayList() {{ + this.add("https://bscscan.com/address/0x3052a0f6ab15b4ae1df39962d5ddefaca86dab47"); + }}); + addresses.put(stargate_busd_staking.getAddress(), stargate_busd_staking); + + return addresses; + } +} diff --git a/src/main/java/crypto/forestfish/objects/embedded/avm/BlockchainDetailsAVM.java b/src/main/java/crypto/forestfish/objects/embedded/avm/BlockchainDetailsAVM.java new file mode 100644 index 0000000..514f938 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/embedded/avm/BlockchainDetailsAVM.java @@ -0,0 +1,323 @@ +package crypto.forestfish.objects.embedded.avm; + +import java.util.ArrayList; +import java.util.HashMap; + +import crypto.forestfish.enums.BlockchainType; +import crypto.forestfish.enums.TokenCategory; +import crypto.forestfish.enums.avm.AVMChain; +import crypto.forestfish.enums.avm.AVMNFTStandard; +import crypto.forestfish.enums.avm.AVMNFTState; +import crypto.forestfish.enums.avm.AVMNFTType; +import crypto.forestfish.enums.avm.MainnetARC69; +import crypto.forestfish.enums.avm.MainnetASA; +import crypto.forestfish.enums.avm.TestnetASA; +import crypto.forestfish.objects.avm.AlgoRelayNode; +import crypto.forestfish.objects.avm.AlgoIndexerNode; +import crypto.forestfish.objects.avm.model.asa.ASAIndex; +import crypto.forestfish.objects.avm.model.asa.AVMASAInfo; +import crypto.forestfish.objects.avm.model.chain.AVMChainIndex; +import crypto.forestfish.objects.avm.model.chain.AVMChainInfo; +import crypto.forestfish.objects.avm.model.chain.AVMCurrency; +import crypto.forestfish.objects.avm.model.nft.ARC3Info; +import crypto.forestfish.objects.avm.model.nft.ARC69Info; +import crypto.forestfish.objects.avm.model.nft.AVMNFTIndex; +import crypto.forestfish.utils.JSONUtils; + +public class BlockchainDetailsAVM { + + public static AVMNFTIndex generateDummyNFTIndex() { + HashMap arc3s = new HashMap<>(); + HashMap arc69s = new HashMap<>(); + return new AVMNFTIndex(arc3s, arc69s); + } + + public static ASAIndex generateDummyASAIndex() { + HashMap tokens = new HashMap<>(); + return new ASAIndex(tokens); + } + + @SuppressWarnings("serial") + public static AVMChainIndex generateAVMChainIndex() { + + HashMap networks = new HashMap<>(); + + // mainnet + AVMChainInfo mainnet = new AVMChainInfo( + AVMChain.MAINNET.toString(), + "Algorand Mainnet", + BlockchainType.PUBLIC.toString(), + "mainnet-v1.0", + "wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=", + new AVMCurrency("ALGO", "ALGO", 6), + new ArrayList() {{ + this.add(new AlgoRelayNode("https://mainnet-api.algonode.network", 443, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "X-API-Key")); + this.add(new AlgoRelayNode("https://mainnet-api.algonode.cloud", 443, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "X-API-Key")); + this.add(new AlgoRelayNode("https://xna-mainnet-api.algonode.cloud", 443, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "X-API-Key")); + this.add(new AlgoRelayNode("https://node.algoexplorerapi.io", 443, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "X-API-Key")); + + //this.add(new AlgoRelayNode("https://mainnet-algorand.api.purestake.io/ps2", 443, "", "X-API-Key")); // custom + //https://algo.getblock.io/05259d72-ef42-41e1-9c3c-5b.../mainnet/ // custom + //https://quicknode.com // custom + }}, + new ArrayList() {{ + this.add(new AlgoIndexerNode("https://mainnet-idx.algonode.network", 443, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "X-API-Key")); + this.add(new AlgoIndexerNode("https://mainnet-idx.algonode.cloud", 443, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "X-API-Key")); + + //this.add(new AlgoIndexerNode("https://indexer.algoexplorerapi.io", 443, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "X-API-Key")); // does not allow custom limit settings, {"message":"invalid value on parameter 'limit'"} + //this.add(new AlgoIndexerNode("https://mainnet-algorand.api.purestake.io/idx2", 443, "", "X-API-Key")); // custom + }}, + new ArrayList() {{ + this.add("https://algoexplorer.io"); + this.add("https://goalseeker.purestake.io/algorand/mainnet"); + }}, + new ArrayList() {{ + this.add("no faucet available"); + }}, + new ArrayList() {{ + this.add("https://www.algorand.com"); + }}, + generateMainnetASAIndex(), + generateMainnetNFTIndex()); + networks.put(AVMChain.MAINNET, mainnet); + + // testnet + AVMChainInfo testnet = new AVMChainInfo( + AVMChain.TESTNET.toString(), + "Algorand Testnet", + BlockchainType.PUBLIC.toString(), + "testnet-v1.0", + "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=", + new AVMCurrency("ALGO", "ALGO", 6), + new ArrayList() {{ + this.add(new AlgoRelayNode("https://testnet-api.algonode.cloud", 443, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "X-API-Key")); + this.add(new AlgoRelayNode("https://node.testnet.algoexplorerapi.io", 443, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "X-API-Key")); + // , https://replit.com/@Algorand/Getting-Started-with-JavaScript#index.js // custom + //this.add(new AlgoRelayNode("https://academy-algod.dev.aws.algodev.network", 443, "2f3203f21e738a1de6110eba6984f9d03e5a95d7a577b34616854064cf2c0e7b", "X-Algo-API-Token")); // custom + //this.add(new AlgoRelayNode("https://testnet-algorand.api.purestake.io/ps2", 443, "", "X-API-Key")); // custom + }}, + new ArrayList() {{ + this.add(new AlgoIndexerNode("https://testnet-idx.algonode.cloud", 443, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "X-API-Key")); + //this.add(new AlgoIndexerNode("https://indexer.testnet.algoexplorerapi.io", 443, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "X-API-Key")); // does not allow custom limit settings, {"message":"invalid value on parameter 'limit'"} + //this.add(new AlgoIndexerNode("https://testnet-algorand.api.purestake.io/idx2", 443, "", "X-API-Key")); // custom + }}, + new ArrayList() {{ + this.add("https://testnet.algoexplorer.io"); + this.add("https://goalseeker.purestake.io/algorand/testnet"); + }}, + new ArrayList() {{ + this.add("https://dispenser.testnet.aws.algodev.network"); + this.add("https://testnet.algoexplorer.io/dispenser"); + }}, + new ArrayList() {{ + this.add("https://www.algorand.com"); + }}, + generateTestnetASAIndex(), + generateDummyNFTIndex()); + networks.put(AVMChain.TESTNET, testnet); + + // betanet + AVMChainInfo betanet = new AVMChainInfo( + AVMChain.BETANET.toString(), + "Algorand Betanet", + BlockchainType.PUBLIC.toString(), + "betanet-v1.0", + "mFgazF+2uRS1tMiL9dsj01hJGySEmPN28B/TjjvpVW0=", + new AVMCurrency("ALGO", "ALGO", 6), + new ArrayList() {{ + this.add(new AlgoRelayNode("https://betanet-api.algonode.cloud", 443, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "X-API-Key")); + //this.add(new AlgoRelayNode("https://betanet-algorand.api.purestake.io/ps2", 443, "", "X-API-Key")); + }}, + new ArrayList() {{ + this.add(new AlgoIndexerNode("https://betanet-idx.algonode.cloud", 443, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "X-API-Key")); + //this.add(new AlgoIndexerNode("https://betanet-algorand.api.purestake.io/idx2", 443, "", "X-API-Key")); + }}, + new ArrayList() {{ + this.add("https://betanet.algoexplorer.io"); + this.add("https://goalseeker.purestake.io/algorand/betanet"); + }}, + new ArrayList() {{ + this.add("https://betanet.algoexplorer.io/dispenser"); + this.add("https://bank.betanet.algodev.network/"); + }}, + new ArrayList() {{ + this.add("https://www.algorand.com"); + }}, + generateDummyASAIndex(), + generateDummyNFTIndex()); + networks.put(AVMChain.BETANET, betanet); + + // localtestnet + AVMChainInfo localtestnet = new AVMChainInfo( + AVMChain.TESTNET_SANDBOX4001.toString(), + "Algorand Testnet", + BlockchainType.LOCAL.toString(), + "testnet-v1.0", + "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=", + new AVMCurrency("ALGO", "ALGO", 6), + new ArrayList() {{ + this.add(new AlgoRelayNode("http://localhost", 4001, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "X-Algo-API-Token")); + }}, + new ArrayList() {{ + //this.add(new AlgoIndexerNode("http://..", 4.., "", "X-Algo-API-Token")); + }}, + new ArrayList() {{ + this.add("https://testnet.algoexplorer.io"); + this.add("https://goalseeker.purestake.io/algorand/testnet"); + }}, + new ArrayList() {{ + this.add("https://dispenser.testnet.aws.algodev.network"); + this.add("https://testnet.algoexplorer.io/dispenser"); + this.add("https://bank.testnet.algorand.network"); + }}, + new ArrayList() {{ + this.add("https://www.algorand.com"); + }}, + generateTestnetASAIndex(), + generateDummyNFTIndex()); + networks.put(AVMChain.TESTNET_SANDBOX4001, localtestnet); + + // voi_testnet + AVMChainInfo voi_testnet = new AVMChainInfo( + AVMChain.VOI_TESTNET.toString(), + "Voi Testnet", + BlockchainType.PUBLIC.toString(), + "voitest-v1", + "IXnoWtviVVJW5LGivNFc0Dq14V3kqaXuK2u5OQrdVZo=", + new AVMCurrency("VOI", "VOI", 6), + new ArrayList() {{ + this.add(new AlgoRelayNode("https://testnet-api.voi.nodly.io", 443, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "X-Algo-API-Token")); + + //this.add(new AlgoRelayNode("https://voitest-api.k1-fi.a-wallet.net", 443, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "X-Algo-API-Token")); // random "Invalid API Token" responses + //this.add(new AlgoRelayNode("http://10.0.0.8", 8080, "f0ef3d2b9fa936ffe78adb75c460a308c11de212ad05a137c2955e47b673ccf6", "X-Algo-API-Token")); // custom + }}, + new ArrayList() {{ + this.add(new AlgoIndexerNode("https://testnet-idx.voi.nodly.io", 443, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "X-Algo-API-Token")); + }}, + new ArrayList() {{ + this.add("https://voitest-explorer.k1-fi.a-wallet.net/dashboard/home"); + this.add("https://app.dappflow.org/explorer/home"); + }}, + new ArrayList() {{ + this.add("Google form https://forms.gle/Trhib6toVZb6uf2HA"); + }}, + new ArrayList() {{ + this.add("https://voi.network"); + }}, + generateDummyASAIndex(), + generateDummyNFTIndex()); + networks.put(AVMChain.VOI_TESTNET, voi_testnet); + + return new AVMChainIndex(networks); + + } + + public static String generateAVMChainIndexJSON() { + AVMChainIndex idx = generateAVMChainIndex(); + return JSONUtils.createJSONFromPOJO(idx); + } + + @SuppressWarnings("serial") + public static ASAIndex generateMainnetASAIndex() { + HashMap tokens = new HashMap<>(); + + // usdc + AVMASAInfo usdc = new AVMASAInfo( + MainnetASA.USDC.toString(), + 31566704L, + "USDC stablecoin token", + 6, + TokenCategory.STABLECOIN.toString(), + AVMChain.MAINNET.toString(), + new ArrayList() {{ + this.add("https://algoexplorer.io/asset/31566704"); + this.add("https://www.coingecko.com/en/coins/usd-coin"); + }}); + tokens.put("31566704", usdc); + + // coop + AVMASAInfo coop = new AVMASAInfo( + MainnetASA.COOP.toString(), + 796425061L, + "COOP coin", + 6, + TokenCategory.MEME.toString(), + AVMChain.MAINNET.toString(), + new ArrayList() {{ + this.add("https://algoexplorer.io/asset/796425061"); + }}); + tokens.put("796425061", coop); + + // opul + AVMASAInfo opul = new AVMASAInfo( + MainnetASA.OPUL.toString(), + 287867876L, + "Opulous token", + 10, + TokenCategory.MFT.toString(), + AVMChain.MAINNET.toString(), + new ArrayList() {{ + this.add("https://algoexplorer.io/asset/287867876"); + this.add("https://opulous.org/"); + }}); + tokens.put("287867876", opul); + + return new ASAIndex(tokens); + } + + public static String generateNFTIndexJSON(AVMNFTIndex idx) { + return JSONUtils.createJSONFromPOJO(idx); + } + + @SuppressWarnings("serial") + public static ASAIndex generateTestnetASAIndex() { + HashMap tokens = new HashMap<>(); + + // usdc + AVMASAInfo usdc = new AVMASAInfo( + TestnetASA.USDC.toString(), + 10458941L, + "USDC stablecoin token", + 6, + TokenCategory.STABLECOIN.toString(), + AVMChain.TESTNET_SANDBOX4001.toString(), + new ArrayList() {{ + this.add("https://testnet.algoexplorer.io/asset/10458941"); + this.add("https://www.coingecko.com/en/coins/usd-coin"); + this.add("https://dispenser.testnet.aws.algodev.network"); + }}); + tokens.put("10458941", usdc); + + return new ASAIndex(tokens); + } + + @SuppressWarnings("serial") + public static AVMNFTIndex generateMainnetNFTIndex() { + HashMap arc3s = new HashMap<>(); + HashMap arc69s = new HashMap<>(); + + // IMMUTABLE = nofreeze, noclawback + + // Alchemon ZIP + ARC69Info alchemon_zip = new ARC69Info( + MainnetARC69.ALCH0046.toString(), + "OJGTHEJ2O5NXN7FVXDZZEEJTUEQHHCIYIE5MWY6BEFVVLZ2KANJODBOKGA", + AVMNFTStandard.ARC69, + AVMNFTType.FRACTIONAL, + AVMNFTState.MUTABLE, + "Alchemon NFT Zip (ALCH0046)", + TokenCategory.GAMING.toString(), + AVMChain.MAINNET.toString(), + new ArrayList() {{ + this.add("https://algoexplorer.io/address/OJGTHEJ2O5NXN7FVXDZZEEJTUEQHHCIYIE5MWY6BEFVVLZ2KANJODBOKGA"); + }}); + arc69s.put(MainnetARC69.ALCH0046.toString(), alchemon_zip); + + return new AVMNFTIndex(arc3s, arc69s); + } + + public static String generateASAIndexJSON(ASAIndex idx) { + return JSONUtils.createJSONFromPOJO(idx); + } + +} diff --git a/src/main/java/crypto/forestfish/objects/embedded/evm/ABI.java b/src/main/java/crypto/forestfish/objects/embedded/evm/ABI.java new file mode 100644 index 0000000..dbf86a3 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/embedded/evm/ABI.java @@ -0,0 +1,25 @@ +package crypto.forestfish.objects.embedded.evm; + +public class ABI { + + /** + * Selected embedded ABI files (dont expand this list) + */ + + // https://docs.aavegotchi.com/abi/diamondabi + public static String abiAavegotchiDiamond = new StringBuilder("[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"aavegotchiClaimTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"claimTime_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"allAavegotchisOfOwner\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"randomNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"status\",\"type\":\"uint256\"},{\"internalType\":\"int16[6]\",\"name\":\"numericTraits\",\"type\":\"int16[6]\"},{\"internalType\":\"int16[6]\",\"name\":\"modifiedNumericTraits\",\"type\":\"int16[6]\"},{\"internalType\":\"uint16[16]\",\"name\":\"equippedWearables\",\"type\":\"uint16[16]\"},{\"internalType\":\"address\",\"name\":\"collateral\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"escrow\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"stakedAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minimumStake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"kinship\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lastInteracted\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"experience\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toNextLevel\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"usedSkillPoints\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"level\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"hauntId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"baseRarityScore\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"modifiedRarityScore\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"locked\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"itemId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"description\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"author\",\"type\":\"string\"},{\"internalType\":\"int8[6]\",\"name\":\"traitModifiers\",\"type\":\"int8[6]\"},{\"internalType\":\"bool[16]\",\"name\":\"slotPositions\",\"type\":\"bool[16]\"},{\"internalType\":\"uint8[]\",\"name\":\"allowedCollaterals\",\"type\":\"uint8[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"x\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"y\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"width\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"height\",\"type\":\"uint8\"}],\"internalType\":\"struct Dimensions\",\"name\":\"dimensions\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"ghstPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"svgId\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"rarityScoreModifier\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"canPurchaseWithGhst\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"minLevel\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"canBeTransferred\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"category\",\"type\":\"uint8\"},{\"internalType\":\"int16\",\"name\":\"kinshipBonus\",\"type\":\"int16\"},{\"internalType\":\"uint32\",\"name\":\"experienceBonus\",\"type\":\"uint32\"}],\"internalType\":\"struct ItemType\",\"name\":\"itemType\",\"type\":\"tuple\"}],\"internalType\":\"struct ItemTypeIO[]\",\"name\":\"items\",\"type\":\"tuple[]\"}],\"internalType\":\"struct AavegotchiInfo[]\",\"name\":\"aavegotchiInfos_\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_approved\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"getAavegotchi\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"randomNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"status\",\"type\":\"uint256\"},{\"internalType\":\"int16[6]\",\"name\":\"numericTraits\",\"type\":\"int16[6]\"},{\"internalType\":\"int16[6]\",\"name\":\"modifiedNumericTraits\",\"type\":\"int16[6]\"},{\"internalType\":\"uint16[16]\",\"name\":\"equippedWearables\",\"type\":\"uint16[16]\"},{\"internalType\":\"address\",\"name\":\"collateral\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"escrow\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"stakedAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minimumStake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"kinship\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lastInteracted\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"experience\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toNextLevel\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"usedSkillPoints\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"level\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"hauntId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"baseRarityScore\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"modifiedRarityScore\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"locked\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"itemId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"description\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"author\",\"type\":\"string\"},{\"internalType\":\"int8[6]\",\"name\":\"traitModifiers\",\"type\":\"int8[6]\"},{\"internalType\":\"bool[16]\",\"name\":\"slotPositions\",\"type\":\"bool[16]\"},{\"internalType\":\"uint8[]\",\"name\":\"allowedCollaterals\",\"type\":\"uint8[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"x\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"y\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"width\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"height\",\"type\":\"uint8\"}],\"internalType\":\"struct Dimensions\",\"name\":\"dimensions\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"ghstPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"svgId\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"rarityScoreModifier\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"canPurchaseWithGhst\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"minLevel\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"canBeTransferred\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"category\",\"type\":\"uint8\"},{\"internalType\":\"int16\",\"name\":\"kinshipBonus\",\"type\":\"int16\"},{\"internalType\":\"uint32\",\"name\":\"experienceBonus\",\"type\":\"uint32\"}],\"internalType\":\"struct ItemType\",\"name\":\"itemType\",\"type\":\"tuple\"}],\"internalType\":\"struct ItemTypeIO[]\",\"name\":\"items\",\"type\":\"tuple[]\"}],\"internalType\":\"struct AavegotchiInfo\",\"name\":\"aavegotchiInfo_\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"approved_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"approved_\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"owner_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"tokenByIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"tokenIdsOfOwner\",\"outputs\":[{\"internalType\":\"uint32[]\",\"name\":\"tokenIds_\",\"type\":\"uint32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"tokenOfOwnerByIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"tokenURI\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"totalSupply_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"ClaimAavegotchi\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_time\",\"type\":\"uint256\"}],\"name\":\"LockAavegotchi\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"_oldName\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"_newName\",\"type\":\"string\"}],\"name\":\"SetAavegotchiName\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_batchId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"SetBatchId\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"int16[4]\",\"name\":\"_values\",\"type\":\"int16[4]\"}],\"name\":\"SpendSkillpoints\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_time\",\"type\":\"uint256\"}],\"name\":\"UnLockAavegotchi\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_experience\",\"type\":\"uint256\"}],\"name\":\"aavegotchiLevel\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"level_\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_name\",\"type\":\"string\"}],\"name\":\"aavegotchiNameAvailable\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"available_\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"availableSkillPoints\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int16[6]\",\"name\":\"_numericTraits\",\"type\":\"int16[6]\"}],\"name\":\"baseRarityScore\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"rarityScore_\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_option\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_stakeAmount\",\"type\":\"uint256\"}],\"name\":\"claimAavegotchi\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentHaunt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"hauntId_\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"hauntMaxSize\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"portalPrice\",\"type\":\"uint256\"},{\"internalType\":\"bytes3\",\"name\":\"bodyColor\",\"type\":\"bytes3\"},{\"internalType\":\"uint24\",\"name\":\"totalCount\",\"type\":\"uint24\"}],\"internalType\":\"struct Haunt\",\"name\":\"haunt_\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"getNumericTraits\",\"outputs\":[{\"internalType\":\"int16[6]\",\"name\":\"numericTraits_\",\"type\":\"int16[6]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ghstAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"contract_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"interact\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"kinship\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"score_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"modifiedTraitsAndRarityScore\",\"outputs\":[{\"internalType\":\"int16[6]\",\"name\":\"numericTraits_\",\"type\":\"int16[6]\"},{\"internalType\":\"uint256\",\"name\":\"rarityScore_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"portalAavegotchiTraits\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"randomNumber\",\"type\":\"uint256\"},{\"internalType\":\"int16[6]\",\"name\":\"numericTraits\",\"type\":\"int16[6]\"},{\"internalType\":\"address\",\"name\":\"collateralType\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minimumStake\",\"type\":\"uint256\"}],\"internalType\":\"struct PortalAavegotchiTraitsIO[10]\",\"name\":\"portalAavegotchiTraits_\",\"type\":\"tuple[10]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int16[6]\",\"name\":\"_numericTraits\",\"type\":\"int16[6]\"}],\"name\":\"rarityMultiplier\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"multiplier_\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"revenueShares\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"burnAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"daoAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rarityFarming\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pixelCraft\",\"type\":\"address\"}],\"internalType\":\"struct AavegotchiGameFacet.RevenueSharesIO\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_name\",\"type\":\"string\"}],\"name\":\"setAavegotchiName\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"int16[4]\",\"name\":\"_values\",\"type\":\"int16[4]\"}],\"name\":\"spendSkillPoints\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_experience\",\"type\":\"uint256\"}],\"name\":\"xpUntilNextLevel\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requiredXp_\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"AddedAavegotchiBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"}],\"name\":\"AddedItemsBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"WithdrawnBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"}],\"name\":\"WithdrawnItems\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"childChainManager\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_user\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_depositData\",\"type\":\"bytes\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newChildChainManager\",\"type\":\"address\"}],\"name\":\"setChildChainManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"withdrawAavegotchiBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_values\",\"type\":\"uint256[]\"}],\"name\":\"withdrawItemsBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_reduceAmount\",\"type\":\"uint256\"}],\"name\":\"DecreaseStake\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_fromTokenId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_toTokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"experience\",\"type\":\"uint256\"}],\"name\":\"ExperienceTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_stakeAmount\",\"type\":\"uint256\"}],\"name\":\"IncreaseStake\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"collateralBalance\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"collateralType_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"escrow_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"balance_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_collateralId\",\"type\":\"uint256\"}],\"name\":\"collateralInfo\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"collateralType\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"int16[6]\",\"name\":\"modifiers\",\"type\":\"int16[6]\"},{\"internalType\":\"bytes3\",\"name\":\"primaryColor\",\"type\":\"bytes3\"},{\"internalType\":\"bytes3\",\"name\":\"secondaryColor\",\"type\":\"bytes3\"},{\"internalType\":\"bytes3\",\"name\":\"cheekColor\",\"type\":\"bytes3\"},{\"internalType\":\"uint8\",\"name\":\"svgId\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"eyeShapeSvgId\",\"type\":\"uint8\"},{\"internalType\":\"uint16\",\"name\":\"conversionRate\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"delisted\",\"type\":\"bool\"}],\"internalType\":\"struct AavegotchiCollateralTypeInfo\",\"name\":\"collateralTypeInfo\",\"type\":\"tuple\"}],\"internalType\":\"struct AavegotchiCollateralTypeIO\",\"name\":\"collateralInfo_\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collaterals\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"collateralTypes_\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_toId\",\"type\":\"uint256\"}],\"name\":\"decreaseAndDestroy\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_reduceAmount\",\"type\":\"uint256\"}],\"name\":\"decreaseStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCollateralInfo\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"collateralType\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"int16[6]\",\"name\":\"modifiers\",\"type\":\"int16[6]\"},{\"internalType\":\"bytes3\",\"name\":\"primaryColor\",\"type\":\"bytes3\"},{\"internalType\":\"bytes3\",\"name\":\"secondaryColor\",\"type\":\"bytes3\"},{\"internalType\":\"bytes3\",\"name\":\"cheekColor\",\"type\":\"bytes3\"},{\"internalType\":\"uint8\",\"name\":\"svgId\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"eyeShapeSvgId\",\"type\":\"uint8\"},{\"internalType\":\"uint16\",\"name\":\"conversionRate\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"delisted\",\"type\":\"bool\"}],\"internalType\":\"struct AavegotchiCollateralTypeInfo\",\"name\":\"collateralTypeInfo\",\"type\":\"tuple\"}],\"internalType\":\"struct AavegotchiCollateralTypeIO[]\",\"name\":\"collateralInfo_\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_stakeAmount\",\"type\":\"uint256\"}],\"name\":\"increaseStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_collateralToken\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"_svgId\",\"type\":\"uint8\"}],\"name\":\"setCollateralEyeShapeSvgId\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"collateralType\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"int16[6]\",\"name\":\"modifiers\",\"type\":\"int16[6]\"},") + .append("{\"internalType\":\"bytes3\",\"name\":\"primaryColor\",\"type\":\"bytes3\"},{\"internalType\":\"bytes3\",\"name\":\"secondaryColor\",\"type\":\"bytes3\"},{\"internalType\":\"bytes3\",\"name\":\"cheekColor\",\"type\":\"bytes3\"},{\"internalType\":\"uint8\",\"name\":\"svgId\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"eyeShapeSvgId\",\"type\":\"uint8\"},{\"internalType\":\"uint16\",\"name\":\"conversionRate\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"delisted\",\"type\":\"bool\"}],\"internalType\":\"struct AavegotchiCollateralTypeInfo\",\"name\":\"collateralTypeInfo\",\"type\":\"tuple\"}],\"indexed\":false,\"internalType\":\"struct AavegotchiCollateralTypeIO\",\"name\":\"_collateralType\",\"type\":\"tuple\"}],\"name\":\"AddCollateralType\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"description\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"author\",\"type\":\"string\"},{\"internalType\":\"int8[6]\",\"name\":\"traitModifiers\",\"type\":\"int8[6]\"},{\"internalType\":\"bool[16]\",\"name\":\"slotPositions\",\"type\":\"bool[16]\"},{\"internalType\":\"uint8[]\",\"name\":\"allowedCollaterals\",\"type\":\"uint8[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"x\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"y\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"width\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"height\",\"type\":\"uint8\"}],\"internalType\":\"struct Dimensions\",\"name\":\"dimensions\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"ghstPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"svgId\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"rarityScoreModifier\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"canPurchaseWithGhst\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"minLevel\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"canBeTransferred\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"category\",\"type\":\"uint8\"},{\"internalType\":\"int16\",\"name\":\"kinshipBonus\",\"type\":\"int16\"},{\"internalType\":\"uint32\",\"name\":\"experienceBonus\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"struct ItemType\",\"name\":\"_itemType\",\"type\":\"tuple\"}],\"name\":\"AddItemType\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"uint8[]\",\"name\":\"allowedCollaterals\",\"type\":\"uint8[]\"},{\"internalType\":\"uint16[]\",\"name\":\"wearableIds\",\"type\":\"uint16[]\"},{\"internalType\":\"int8[5]\",\"name\":\"traitsBonuses\",\"type\":\"int8[5]\"}],\"indexed\":false,\"internalType\":\"struct WearableSet\",\"name\":\"_wearableSet\",\"type\":\"tuple\"}],\"name\":\"AddWearableSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_hauntId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_hauntMaxSize\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_portalPrice\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"_bodyColor\",\"type\":\"bytes32\"}],\"name\":\"CreateHaunt\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousDao\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newDao\",\"type\":\"address\"}],\"name\":\"DaoTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousDaoTreasury\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newDaoTreasury\",\"type\":\"address\"}],\"name\":\"DaoTreasuryTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousGameManager\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newGameManager\",\"type\":\"address\"}],\"name\":\"GameManagerTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_xpValues\",\"type\":\"uint256[]\"}],\"name\":\"GrantExperience\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_itemIds\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_maxQuanities\",\"type\":\"uint256[]\"}],\"name\":\"ItemTypeMaxQuantity\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int16[6]\",\"name\":\"_oldModifiers\",\"type\":\"int16[6]\"},{\"indexed\":false,\"internalType\":\"int16[6]\",\"name\":\"_newModifiers\",\"type\":\"int16[6]\"}],\"name\":\"UpdateCollateralModifiers\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_setId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"uint8[]\",\"name\":\"allowedCollaterals\",\"type\":\"uint8[]\"},{\"internalType\":\"uint16[]\",\"name\":\"wearableIds\",\"type\":\"uint16[]\"},{\"internalType\":\"int8[5]\",\"name\":\"traitsBonuses\",\"type\":\"int8[5]\"}],\"indexed\":false,\"internalType\":\"struct WearableSet\",\"name\":\"_wearableSet\",\"type\":\"tuple\"}],\"name\":\"UpdateWearableSet\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"collateralType\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"int16[6]\",\"name\":\"modifiers\",\"type\":\"int16[6]\"},{\"internalType\":\"bytes3\",\"name\":\"primaryColor\",\"type\":\"bytes3\"},{\"internalType\":\"bytes3\",\"name\":\"secondaryColor\",\"type\":\"bytes3\"},{\"internalType\":\"bytes3\",\"name\":\"cheekColor\",\"type\":\"bytes3\"},{\"internalType\":\"uint8\",\"name\":\"svgId\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"eyeShapeSvgId\",\"type\":\"uint8\"},{\"internalType\":\"uint16\",\"name\":\"conversionRate\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"delisted\",\"type\":\"bool\"}],\"internalType\":\"struct AavegotchiCollateralTypeInfo\",\"name\":\"collateralTypeInfo\",\"type\":\"tuple\"}],\"internalType\":\"struct AavegotchiCollateralTypeIO[]\",\"name\":\"_collateralTypes\",\"type\":\"tuple[]\"}],\"name\":\"addCollateralTypes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"description\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"author\",\"type\":\"string\"},{\"internalType\":\"int8[6]\",\"name\":\"traitModifiers\",\"type\":\"int8[6]\"},{\"internalType\":\"bool[16]\",\"name\":\"slotPositions\",\"type\":\"bool[16]\"},{\"internalType\":\"uint8[]\",\"name\":\"allowedCollaterals\",\"type\":\"uint8[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"x\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"y\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"width\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"height\",\"type\":\"uint8\"}],\"internalType\":\"struct Dimensions\",\"name\":\"dimensions\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"ghstPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"svgId\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"rarityScoreModifier\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"canPurchaseWithGhst\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"minLevel\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"canBeTransferred\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"category\",\"type\":\"uint8\"},{\"internalType\":\"int16\",\"name\":\"kinshipBonus\",\"type\":\"int16\"},{\"internalType\":\"uint32\",\"name\":\"experienceBonus\",\"type\":\"uint32\"}],\"internalType\":\"struct ItemType[]\",\"name\":\"_itemTypes\",\"type\":\"tuple[]\"}],\"name\":\"addItemTypes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"description\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"author\",\"type\":\"string\"},{\"internalType\":\"int8[6]\",\"name\":\"traitModifiers\",\"type\":\"int8[6]\"},{\"internalType\":\"bool[16]\",\"name\":\"slotPositions\",\"type\":\"bool[16]\"},{\"internalType\":\"uint8[]\",\"name\":\"allowedCollaterals\",\"type\":\"uint8[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"x\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"y\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"width\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"height\",\"type\":\"uint8\"}],\"internalType\":\"struct Dimensions\",\"name\":\"dimensions\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"ghstPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"svgId\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"rarityScoreModifier\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"canPurchaseWithGhst\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"minLevel\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"canBeTransferred\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"category\",\"type\":\"uint8\"},{\"internalType\":\"int16\",\"name\":\"kinshipBonus\",\"type\":\"int16\"},{\"internalType\":\"uint32\",\"name\":\"experienceBonus\",\"type\":\"uint32\"}],\"internalType\":\"struct ItemType[]\",\"name\":\"_itemTypes\",\"type\":\"tuple[]\"},{\"internalType\":\"string\",\"name\":\"_svg\",\"type\":\"string\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"svgType\",\"type\":\"bytes32\"},{\"internalType\":\"uint256[]\",\"name\":\"sizes\",\"type\":\"uint256[]\"}],\"internalType\":\"struct LibSvg.SvgTypeAndSizes[]\",\"name\":\"_typesAndSizes\",\"type\":\"tuple[]\"}],\"name\":\"addItemTypesAndSvgs\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"uint8[]\",\"name\":\"allowedCollaterals\",\"type\":\"uint8[]\"},{\"internalType\":\"uint16[]\",\"name\":\"wearableIds\",\"type\":\"uint16[]\"},{\"internalType\":\"int8[5]\",\"name\":\"traitsBonuses\",\"type\":\"int8[5]\"}],\"internalType\":\"struct WearableSet[]\",\"name\":\"_wearableSets\",\"type\":\"tuple[]\"}],\"name\":\"addWearableSets\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint24\",\"name\":\"_hauntMaxSize\",\"type\":\"uint24\"},{\"internalType\":\"uint96\",\"name\":\"_portalPrice\",\"type\":\"uint96\"},{\"internalType\":\"bytes3\",\"name\":\"_bodyColor\",\"type\":\"bytes3\"}],\"name\":\"createHaunt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"hauntId_\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gameManager\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_xpValues\",\"type\":\"uint256[]\"}],\"name\":\"grantExperience\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_itemIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_quantities\",\"type\":\"uint256[]\"}],\"name\":\"mintItems\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newDao\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_newDaoTreasury\",\"type\":\"address\"}],\"name\":\"setDao\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_gameManager\",\"type\":\"address\"}],\"name\":\"setGameManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_collateralType\",\"type\":\"address\"},{\"internalType\":\"int16[6]\",\"name\":\"_modifiers\",\"type\":\"int16[6]\"}],\"name\":\"updateCollateralModifiers\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_itemIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_maxQuantities\",\"type\":\"uint256[]\"}],\"name\":\"updateItemTypeMaxQuantity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_setIds\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"uint8[]\",\"name\":\"allowedCollaterals\",\"type\":\"uint8[]\"},{\"internalType\":\"uint16[]\",\"name\":\"wearableIds\",\"type\":\"uint16[]\"},{\"internalType\":\"int8[5]\",\"name\":\"traitsBonuses\",\"type\":\"int8[5]\"}],\"internalType\":\"struct WearableSet[]\",\"name\":\"_wearableSets\",\"type\":\"tuple[]\"}],\"name\":\"updateWearableSets\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"listingFeeInWei\",\"type\":\"uint256\"}],\"name\":\"ChangedListingFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"seller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"buyer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"erc1155TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"erc1155TypeId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_quantity\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"priceInWei\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"ERC1155ExecutedListing\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"seller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"erc1155TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"erc1155TypeId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"quantity\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"priceInWei\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"ERC1155ListingAdd\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"}],\"name\":\"ERC1155ListingCancelled\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_listingId\",\"type\":\"uint256\"}],\"name\":\"cancelERC1155Listing\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_listingIds\",\"type\":\"uint256[]\"}],\"name\":\"cancelERC1155Listings\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_listingId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_quantity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_priceInWei\",\"type\":\"uint256\"}],\"name\":\"executeERC1155Listing\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_erc1155TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_erc1155TypeId\",\"type\":\"uint256\"}],\"name\":\"getERC1155Category\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"category_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_listingId\",\"type\":\"uint256\"}],\"name\":\"getERC1155Listing\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"seller\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"erc1155TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"erc1155TypeId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"quantity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"priceInWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timeCreated\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timeLastPurchased\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"sourceListingId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sold\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"cancelled\",\"type\":\"bool\"}],\"internalType\":\"struct ERC1155Listing\",\"name\":\"listing_\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_erc1155TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_erc1155TypeId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"getERC1155ListingFromToken\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"seller\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"erc1155TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"erc1155TypeId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"quantity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"priceInWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timeCreated\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timeLastPurchased\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"sourceListingId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sold\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"cancelled\",\"type\":\"bool\"}],\"internalType\":\"struct ERC1155Listing\",\"name\":\"listing_\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_category\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_sort\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"_length\",\"type\":\"uint256\"}],\"name\":\"getERC1155Listings\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"seller\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"erc1155TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"erc1155TypeId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"quantity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"priceInWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timeCreated\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timeLastPurchased\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"sourceListingId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sold\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"cancelled\",\"type\":\"bool\"}],\"internalType\":\"struct ERC1155Listing[]\",\"name\":\"listings_\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getListingFeeInWei\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_category\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_sort\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"_length\",\"type\":\"uint256\"}],\"name\":\"getOwnerERC1155Listings\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"seller\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"erc1155TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"erc1155TypeId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"quantity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"priceInWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timeCreated\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timeLastPurchased\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"sourceListingId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sold\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"cancelled\",\"type\":\"bool\"}],\"internalType\":\"struct ERC1155Listing[]\",\"name\":\"listings_\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"erc1155TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"erc1155TypeId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"}],\"internalType\":\"struct ERC1155MarketplaceFacet.Category[]\",\"name\":\"_categories\",\"type\":\"tuple[]\"}],\"name\":\"setERC1155Categories\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_erc1155TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_erc1155TypeId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_quantity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_priceInWei\",\"type\":\"uint256\"}],\"name\":\"setERC1155Listing\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_listingFeeInWei\",\"type\":\"uint256\"}],\"name\":\"setListingFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_erc1155TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_erc1155TypeIds\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"updateBatchERC1155Listing\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_erc1155TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_erc1155TypeId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"updateERC1155Listing\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"seller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"buyer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"erc721TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"erc721TokenId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"priceInWei\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"ERC721ExecutedListing\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"seller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"erc721TokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"erc721TokenId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"ERC721ListingAdd\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_erc721TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_erc721TokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_priceInWei\",\"type\":\"uint256\"}],\"name\":\"addERC721Listing\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_listingId\",\"type\":\"uint256\"}],\"name\":\"cancelERC721Listing\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_erc721TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_erc721TokenId\",\"type\":\"uint256\"}],\"name\":\"cancelERC721ListingByToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_listingIds\",\"type\":\"uint256[]\"}],\"name\":\"cancelERC721Listings\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_listingId\",\"type\":\"uint256\"}],\"name\":\"executeERC721Listing\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_listingId\",\"type\":\"uint256\"}],\"name\":\"getAavegotchiListing\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"seller\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"erc721TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"erc721TokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"priceInWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timeCreated\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timePurchased\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"cancelled\",\"type\":\"bool\"}],\"internalType\":\"struct ERC721Listing\",\"name\":\"listing_\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"randomNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"status\",\"type\":\"uint256\"},{\"internalType\":\"int16[6]\",\"name\":\"numericTraits\",\"type\":\"int16[6]\"},{\"internalType\":\"int16[6]\",\"name\":\"modifiedNumericTraits\",\"type\":\"int16[6]\"},{\"internalType\":\"uint16[16]\",\"name\":\"equippedWearables\",\"type\":\"uint16[16]\"},{\"internalType\":\"address\",\"name\":\"collateral\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"escrow\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"stakedAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minimumStake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"kinship\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lastInteracted\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"experience\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toNextLevel\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"usedSkillPoints\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"level\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"hauntId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"baseRarityScore\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"modifiedRarityScore\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"locked\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"itemId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"description\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"author\",\"type\":\"string\"},{\"internalType\":\"int8[6]\",\"name\":\"traitModifiers\",\"type\":\"int8[6]\"},{\"internalType\":\"bool[16]\",\"name\":\"slotPositions\",\"type\":\"bool[16]\"},{\"internalType\":\"uint8[]\",\"name\":\"allowedCollaterals\",\"type\":\"uint8[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"x\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"y\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"width\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"height\",\"type\":\"uint8\"}],\"internalType\":\"struct Dimensions\",\"name\":\"dimensions\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"ghstPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"svgId\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"rarityScoreModifier\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"canPurchaseWithGhst\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"minLevel\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"canBeTransferred\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"category\",\"type\":\"uint8\"},{\"internalType\":\"int16\",\"name\":\"kinshipBonus\",\"type\":\"int16\"},{\"internalType\":\"uint32\",\"name\":\"experienceBonus\",\"type\":\"uint32\"}],\"internalType\":\"struct ItemType\",\"name\":\"itemType\",\"type\":\"tuple\"}],\"internalType\":\"struct ItemTypeIO[]\",\"name\":\"items\",\"type\":\"tuple[]\"}],\"internalType\":\"struct AavegotchiInfo\",\"name\":\"aavegotchiInfo_\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_category\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_sort\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"_length\",\"type\":\"uint256\"}],\"name\":\"getAavegotchiListings\",\"outputs\":[{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"seller\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"erc721TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"erc721TokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"priceInWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timeCreated\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timePurchased\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"cancelled\",\"type\":\"bool\"}],\"internalType\":\"struct ERC721Listing\",\"name\":\"listing_\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"randomNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"status\",\"type\":\"uint256\"},{\"internalType\":\"int16[6]\",\"name\":\"numericTraits\",\"type\":\"int16[6]\"},{\"internalType\":\"int16[6]\",\"name\":\"modifiedNumericTraits\",\"type\":\"int16[6]\"},{\"internalType\":\"uint16[16]\",\"name\":\"equippedWearables\",\"type\":\"uint16[16]\"},{\"internalType\":\"address\",\"name\":\"collateral\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"escrow\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"stakedAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minimumStake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"kinship\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lastInteracted\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"experience\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toNextLevel\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"usedSkillPoints\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"level\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"hauntId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"baseRarityScore\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"modifiedRarityScore\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"locked\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"itemId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"description\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"author\",\"type\":\"string\"},{\"internalType\":\"int8[6]\",\"name\":\"traitModifiers\",\"type\":\"int8[6]\"},{\"internalType\":\"bool[16]\",\"name\":\"slotPositions\",\"type\":\"bool[16]\"},{\"internalType\":\"uint8[]\",\"name\":\"allowedCollaterals\",\"type\":\"uint8[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"x\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"y\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"width\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"height\",\"type\":\"uint8\"}],\"internalType\":\"struct Dimensions\",\"name\":\"dimensions\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"ghstPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"svgId\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"rarityScoreModifier\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"canPurchaseWithGhst\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"minLevel\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"canBeTransferred\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"category\",\"type\":\"uint8\"},{\"internalType\":\"int16\",\"name\":\"kinshipBonus\",\"type\":\"int16\"},{\"internalType\":\"uint32\",\"name\":\"experienceBonus\",\"type\":\"uint32\"}],\"internalType\":\"struct ItemType\",\"name\":\"itemType\",\"type\":\"tuple\"}],\"internalType\":\"struct ItemTypeIO[]\",\"name\":\"items\",\"type\":\"tuple[]\"}],\"internalType\":\"struct AavegotchiInfo\",\"name\":\"aavegotchiInfo_\",\"type\":\"tuple\"}],\"internalType\":\"struct ERC721MarketplaceFacet.AavegotchiListing[]\",\"name\":\"listings_\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_erc721TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_erc721TokenId\",\"type\":\"uint256\"}],\"name\":\"getERC721Category\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"category_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_listingId\",\"type\":\"uint256\"}],\"name\":\"getERC721Listing\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"seller\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"erc721TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"erc721TokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"priceInWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timeCreated\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timePurchased\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"cancelled\",\"type\":\"bool\"}],\"internalType\":\"struct ERC721Listing\",\"name\":\"listing_\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_erc721TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_erc721TokenId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"getERC721ListingFromToken\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"seller\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"erc721TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"erc721TokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"priceInWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timeCreated\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timePurchased\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"cancelled\",\"type\":\"bool\"}],\"internalType\":\"struct ERC721Listing\",\"name\":\"listing_\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_category\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_sort\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"_length\",\"type\":\"uint256\"}],\"name\":\"getERC721Listings\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"seller\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"erc721TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"erc721TokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"priceInWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timeCreated\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timePurchased\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"cancelled\",\"type\":\"bool\"}],\"internalType\":\"struct ERC721Listing[]\",\"name\":\"listings_\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_category\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_sort\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"_length\",\"type\":\"uint256\"}],\"name\":\"getOwnerAavegotchiListings\",\"outputs\":[{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"seller\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"erc721TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"erc721TokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"priceInWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timeCreated\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timePurchased\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"cancelled\",\"type\":\"bool\"}],\"internalType\":\"struct ERC721Listing\",\"name\":\"listing_\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"randomNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"status\",\"type\":\"uint256\"},{\"internalType\":\"int16[6]\",\"name\":\"numericTraits\",\"type\":\"int16[6]\"},{\"internalType\":\"int16[6]\",\"name\":\"modifiedNumericTraits\",\"type\":\"int16[6]\"},{\"internalType\":\"uint16[16]\",\"name\":\"equippedWearables\",\"type\":\"uint16[16]\"},{\"internalType\":\"address\",\"name\":\"collateral\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"escrow\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"stakedAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minimumStake\",\"type\":\"uint256\"},") + .append("{\"internalType\":\"uint256\",\"name\":\"kinship\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lastInteracted\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"experience\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"toNextLevel\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"usedSkillPoints\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"level\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"hauntId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"baseRarityScore\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"modifiedRarityScore\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"locked\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"itemId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"description\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"author\",\"type\":\"string\"},{\"internalType\":\"int8[6]\",\"name\":\"traitModifiers\",\"type\":\"int8[6]\"},{\"internalType\":\"bool[16]\",\"name\":\"slotPositions\",\"type\":\"bool[16]\"},{\"internalType\":\"uint8[]\",\"name\":\"allowedCollaterals\",\"type\":\"uint8[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"x\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"y\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"width\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"height\",\"type\":\"uint8\"}],\"internalType\":\"struct Dimensions\",\"name\":\"dimensions\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"ghstPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"svgId\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"rarityScoreModifier\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"canPurchaseWithGhst\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"minLevel\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"canBeTransferred\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"category\",\"type\":\"uint8\"},{\"internalType\":\"int16\",\"name\":\"kinshipBonus\",\"type\":\"int16\"},{\"internalType\":\"uint32\",\"name\":\"experienceBonus\",\"type\":\"uint32\"}],\"internalType\":\"struct ItemType\",\"name\":\"itemType\",\"type\":\"tuple\"}],\"internalType\":\"struct ItemTypeIO[]\",\"name\":\"items\",\"type\":\"tuple[]\"}],\"internalType\":\"struct AavegotchiInfo\",\"name\":\"aavegotchiInfo_\",\"type\":\"tuple\"}],\"internalType\":\"struct ERC721MarketplaceFacet.AavegotchiListing[]\",\"name\":\"listings_\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_category\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_sort\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"_length\",\"type\":\"uint256\"}],\"name\":\"getOwnerERC721Listings\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"seller\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"erc721TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"erc721TokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"priceInWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timeCreated\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timePurchased\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"cancelled\",\"type\":\"bool\"}],\"internalType\":\"struct ERC721Listing[]\",\"name\":\"listings_\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_erc721TokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_erc721TokenId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"updateERC721Listing\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16[16]\",\"name\":\"_oldWearables\",\"type\":\"uint16[16]\"},{\"indexed\":false,\"internalType\":\"uint16[16]\",\"name\":\"_newWearables\",\"type\":\"uint16[16]\"}],\"name\":\"EquipWearables\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_toContract\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_toTokenId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_tokenTypeId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"TransferToParent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_itemIds\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_quantities\",\"type\":\"uint256[]\"}],\"name\":\"UseConsumables\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_id\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"bal_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_owners\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_ids\",\"type\":\"uint256[]\"}],\"name\":\"balanceOfBatch\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"bals\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_tokenContract\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_id\",\"type\":\"uint256\"}],\"name\":\"balanceOfToken\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint16[16]\",\"name\":\"_equippedWearables\",\"type\":\"uint16[16]\"}],\"name\":\"equipWearables\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"equippedWearables\",\"outputs\":[{\"internalType\":\"uint16[16]\",\"name\":\"wearableIds_\",\"type\":\"uint16[16]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_wearableIds\",\"type\":\"uint256[]\"}],\"name\":\"findWearableSets\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"wearableSetIds_\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_itemId\",\"type\":\"uint256\"}],\"name\":\"getItemType\",\"outputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"description\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"author\",\"type\":\"string\"},{\"internalType\":\"int8[6]\",\"name\":\"traitModifiers\",\"type\":\"int8[6]\"},{\"internalType\":\"bool[16]\",\"name\":\"slotPositions\",\"type\":\"bool[16]\"},{\"internalType\":\"uint8[]\",\"name\":\"allowedCollaterals\",\"type\":\"uint8[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"x\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"y\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"width\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"height\",\"type\":\"uint8\"}],\"internalType\":\"struct Dimensions\",\"name\":\"dimensions\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"ghstPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"svgId\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"rarityScoreModifier\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"canPurchaseWithGhst\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"minLevel\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"canBeTransferred\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"category\",\"type\":\"uint8\"},{\"internalType\":\"int16\",\"name\":\"kinshipBonus\",\"type\":\"int16\"},{\"internalType\":\"uint32\",\"name\":\"experienceBonus\",\"type\":\"uint32\"}],\"internalType\":\"struct ItemType\",\"name\":\"itemType_\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_itemIds\",\"type\":\"uint256[]\"}],\"name\":\"getItemTypes\",\"outputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"description\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"author\",\"type\":\"string\"},{\"internalType\":\"int8[6]\",\"name\":\"traitModifiers\",\"type\":\"int8[6]\"},{\"internalType\":\"bool[16]\",\"name\":\"slotPositions\",\"type\":\"bool[16]\"},{\"internalType\":\"uint8[]\",\"name\":\"allowedCollaterals\",\"type\":\"uint8[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"x\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"y\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"width\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"height\",\"type\":\"uint8\"}],\"internalType\":\"struct Dimensions\",\"name\":\"dimensions\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"ghstPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"svgId\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"rarityScoreModifier\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"canPurchaseWithGhst\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"minLevel\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"canBeTransferred\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"category\",\"type\":\"uint8\"},{\"internalType\":\"int16\",\"name\":\"kinshipBonus\",\"type\":\"int16\"},{\"internalType\":\"uint32\",\"name\":\"experienceBonus\",\"type\":\"uint32\"}],\"internalType\":\"struct ItemType[]\",\"name\":\"itemTypes_\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"getWearableSet\",\"outputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"uint8[]\",\"name\":\"allowedCollaterals\",\"type\":\"uint8[]\"},{\"internalType\":\"uint16[]\",\"name\":\"wearableIds\",\"type\":\"uint16[]\"},{\"internalType\":\"int8[5]\",\"name\":\"traitsBonuses\",\"type\":\"int8[5]\"}],\"internalType\":\"struct WearableSet\",\"name\":\"wearableSet_\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWearableSets\",\"outputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"uint8[]\",\"name\":\"allowedCollaterals\",\"type\":\"uint8[]\"},{\"internalType\":\"uint16[]\",\"name\":\"wearableIds\",\"type\":\"uint16[]\"},{\"internalType\":\"int8[5]\",\"name\":\"traitsBonuses\",\"type\":\"int8[5]\"}],\"internalType\":\"struct WearableSet[]\",\"name\":\"wearableSets_\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"}],\"name\":\"itemBalances\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"itemId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct ItemsFacet.ItemIdIO[]\",\"name\":\"bals_\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_tokenContract\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"itemBalancesOfToken\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"itemId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"internalType\":\"struct ItemsFacet.ItemIdIO[]\",\"name\":\"bals_\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_tokenContract\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"itemBalancesOfTokenWithTypes\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"itemId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"description\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"author\",\"type\":\"string\"},{\"internalType\":\"int8[6]\",\"name\":\"traitModifiers\",\"type\":\"int8[6]\"},{\"internalType\":\"bool[16]\",\"name\":\"slotPositions\",\"type\":\"bool[16]\"},{\"internalType\":\"uint8[]\",\"name\":\"allowedCollaterals\",\"type\":\"uint8[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"x\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"y\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"width\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"height\",\"type\":\"uint8\"}],\"internalType\":\"struct Dimensions\",\"name\":\"dimensions\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"ghstPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"svgId\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"rarityScoreModifier\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"canPurchaseWithGhst\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"minLevel\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"canBeTransferred\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"category\",\"type\":\"uint8\"},{\"internalType\":\"int16\",\"name\":\"kinshipBonus\",\"type\":\"int16\"},{\"internalType\":\"uint32\",\"name\":\"experienceBonus\",\"type\":\"uint32\"}],\"internalType\":\"struct ItemType\",\"name\":\"itemType\",\"type\":\"tuple\"}],\"internalType\":\"struct ItemTypeIO[]\",\"name\":\"itemBalancesOfTokenWithTypes_\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"itemBalancesWithTypes\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"itemId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"description\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"author\",\"type\":\"string\"},{\"internalType\":\"int8[6]\",\"name\":\"traitModifiers\",\"type\":\"int8[6]\"},{\"internalType\":\"bool[16]\",\"name\":\"slotPositions\",\"type\":\"bool[16]\"},{\"internalType\":\"uint8[]\",\"name\":\"allowedCollaterals\",\"type\":\"uint8[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"x\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"y\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"width\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"height\",\"type\":\"uint8\"}],\"internalType\":\"struct Dimensions\",\"name\":\"dimensions\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"ghstPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalQuantity\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"svgId\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"rarityScoreModifier\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"canPurchaseWithGhst\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"minLevel\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"canBeTransferred\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"category\",\"type\":\"uint8\"},{\"internalType\":\"int16\",\"name\":\"kinshipBonus\",\"type\":\"int16\"},{\"internalType\":\"uint32\",\"name\":\"experienceBonus\",\"type\":\"uint32\"}],\"internalType\":\"struct ItemType\",\"name\":\"itemType\",\"type\":\"tuple\"}],\"internalType\":\"struct ItemTypeIO[]\",\"name\":\"output_\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_value\",\"type\":\"string\"}],\"name\":\"setBaseURI\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_wearableId\",\"type\":\"uint256\"},{\"internalType\":\"bool[16]\",\"name\":\"_slotPositions\",\"type\":\"bool[16]\"}],\"name\":\"setWearableSlotPositions\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalWearableSets\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_id\",\"type\":\"uint256\"}],\"name\":\"uri\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"_itemIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_quantities\",\"type\":\"uint256[]\"}],\"name\":\"useConsumables\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_fromContract\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_fromTokenId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_toContract\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_toTokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"_ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_values\",\"type\":\"uint256[]\"}],\"name\":\"batchTransferAsChild\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_fromContract\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_fromTokenId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_values\",\"type\":\"uint256[]\"}],\"name\":\"batchTransferFromParent\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_toContract\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_toTokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"_ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_values\",\"type\":\"uint256[]\"}],\"name\":\"batchTransferToParent\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"onERC1155BatchReceived\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"onERC1155Received\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_values\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"safeBatchTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_fromContract\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_fromTokenId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_toContract\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_toTokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transferAsChild\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_fromContract\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_fromTokenId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transferFromParent\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_toContract\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_toTokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transferToParent\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"userAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address payable\",\"name\":\"relayerAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"functionSignature\",\"type\":\"bytes\"}],\"name\":\"MetaTransactionExecuted\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"userAddress\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"functionSignature\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"sigR\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"sigS\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"sigV\",\"type\":\"uint8\"}],\"name\":\"executeMetaTransaction\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"getNonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_numAavegotchisToPurchase\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_totalPrice\",\"type\":\"uint256\"}],\"name\":\"BuyPortals\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_buyer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_itemIds\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_quantities\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_totalPrice\",\"type\":\"uint256\"}],\"name\":\"PurchaseItemsWithGhst\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_buyer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_itemIds\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_quantities\",\"type\":\"uint256[]\"}],\"name\":\"PurchaseItemsWithVouchers\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_buyer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_itemIds\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_quantities\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_totalPrice\",\"type\":\"uint256\"}],\"name\":\"PurchaseTransferItemsWithGhst\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_ghst\",\"type\":\"uint256\"}],\"name\":\"buyPortals\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_itemIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_quantities\",\"type\":\"uint256[]\"}],\"name\":\"purchaseItemsWithGhst\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_itemIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_quantities\",\"type\":\"uint256[]\"}],\"name\":\"purchaseTransferItemsWithGhst\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_svgType\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"_numLayers\",\"type\":\"uint256\"}],\"name\":\"deleteLastSvgLayers\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"getAavegotchiSvg\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"ag_\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_itemId\",\"type\":\"uint256\"}],\"name\":\"getItemSvg\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"ag_\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_svgType\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"_itemId\",\"type\":\"uint256\"}],\"name\":\"getSvg\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"svg_\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_svgType\",\"type\":\"bytes32\"},{\"internalType\":\"uint256[]\",\"name\":\"_itemIds\",\"type\":\"uint256[]\"}],\"name\":\"getSvgs\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"svgs_\",\"type\":\"string[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"portalAavegotchisSvg\",\"outputs\":[{\"internalType\":\"string[10]\",\"name\":\"svg_\",\"type\":\"string[10]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_itemIds\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"x\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"y\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"width\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"height\",\"type\":\"uint8\"}],\"internalType\":\"struct Dimensions[]\",\"name\":\"_dimensions\",\"type\":\"tuple[]\"}],\"name\":\"setItemsDimensions\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"sleeveId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"wearableId\",\"type\":\"uint256\"}],\"internalType\":\"struct SvgFacet.Sleeve[]\",\"name\":\"_sleeves\",\"type\":\"tuple[]\"}],\"name\":\"setSleeves\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_svg\",\"type\":\"string\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"svgType\",\"type\":\"bytes32\"},{\"internalType\":\"uint256[]\",\"name\":\"sizes\",\"type\":\"uint256[]\"}],\"internalType\":\"struct LibSvg.SvgTypeAndSizes[]\",\"name\":\"_typesAndSizes\",\"type\":\"tuple[]\"}],\"name\":\"storeSvg\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_svg\",\"type\":\"string\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"svgType\",\"type\":\"bytes32\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"sizes\",\"type\":\"uint256[]\"}],\"internalType\":\"struct LibSvg.SvgTypeAndIdsAndSizes[]\",\"name\":\"_typesAndIdsAndSizes\",\"type\":\"tuple[]\"}],\"name\":\"updateSvg\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"OpenPortals\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"PortalOpened\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"randomNumber\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_vrfTimeSet\",\"type\":\"uint256\"}],\"name\":\"VrfRandomNumber\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newFee\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"_keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"}],\"name\":\"changeVrf\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"keyHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"link\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"linkBalance_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"openPortals\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_requestId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"_randomNumber\",\"type\":\"uint256\"}],\"name\":\"rawFulfillRandomness\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"removeLinkTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vrfCoordinator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_ids\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_values\",\"type\":\"uint256[]\"}],\"name\":\"MigrateVouchers\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"}],\"internalType\":\"struct VoucherMigrationFacet.VouchersOwner[]\",\"name\":\"_vouchersOwners\",\"type\":\"tuple[]\"}],\"name\":\"migrateVouchers\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_buyer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_itemIds\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_quantities\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_totalPrice\",\"type\":\"uint256\"}],\"name\":\"PurchaseItemsWithGhst\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_buyer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_itemIds\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_quantities\",\"type\":\"uint256[]\"}],\"name\":\"PurchaseItemsWithVouchers\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_buyer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_itemIds\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_quantities\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_totalPrice\",\"type\":\"uint256\"}],\"name\":\"PurchaseTransferItemsWithGhst\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_numAavegotchisToPurchase\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_totalPrice\",\"type\":\"uint256\"}],\"name\":\"Xingyun\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_itemIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_quantities\",\"type\":\"uint256[]\"}],\"name\":\"purchaseItemsWithGhst\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_itemIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_quantities\",\"type\":\"uint256[]\"}],\"name\":\"purchaseTransferItemsWithGhst\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_ghst\",\"type\":\"uint256\"}],\"name\":\"xingyun\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"kinship\",\"type\":\"uint256\"}],\"name\":\"AavegotchiInteract\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"ERC1155ListingCancelled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"ERC1155ListingRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"quantity\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"priceInWei\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"UpdateERC1155Listing\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"ERC721ListingCancelled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"listingId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"category\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"}],\"name\":\"ERC721ListingRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"svgType\",\"type\":\"bytes32\"},{\"internalType\":\"uint256[]\",\"name\":\"sizes\",\"type\":\"uint256[]\"}],\"indexed\":false,\"internalType\":\"struct LibSvg.SvgTypeAndSizes[]\",\"name\":\"_typesAndSizes\",\"type\":\"tuple[]\"}],\"name\":\"StoreSvg\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"svgType\",\"type\":\"bytes32\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"sizes\",\"type\":\"uint256[]\"}],\"indexed\":false,\"internalType\":\"struct LibSvg.SvgTypeAndIdsAndSizes[]\",\"name\":\"_typesAndIdsAndSizes\",\"type\":\"tuple[]\"}],\"name\":\"UpdateSvg\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"facetAddress\",\"type\":\"address\"},{\"internalType\":\"enum IDiamondCut.FacetCutAction\",\"name\":\"action\",\"type\":\"uint8\"},{\"internalType\":\"bytes4[]\",\"name\":\"functionSelectors\",\"type\":\"bytes4[]\"}],\"indexed\":false,\"internalType\":\"struct IDiamondCut.FacetCut[]\",\"name\":\"_diamondCut\",\"type\":\"tuple[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_init\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"_calldata\",\"type\":\"bytes\"}],\"name\":\"DiamondCut\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"_approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_ids\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_values\",\"type\":\"uint256[]\"}],\"name\":\"TransferBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_fromContract\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_fromTokenId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_tokenTypeId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"TransferFromParent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"TransferSingle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_toContract\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_toTokenId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_tokenTypeId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"TransferToParent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"_value\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_id\",\"type\":\"uint256\"}],\"name\":\"URI\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_approved\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"_approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"}]") + .toString(); + + // https://github.com/thetiptoken/TheTipToken-WebPlatform/tree/master/build/contracts + public static String abiERC20 = "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"tokenOwner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenOwner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"balance\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenOwner\",\"type\":\"address\"},{\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"name\":\"remaining\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"spender\",\"type\":\"address\"},{\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"; + public static String abiERC721Basic = "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_approved\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_operator\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"_balance\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"exists\",\"outputs\":[{\"name\":\"_exists\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"name\":\"_operator\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_operator\",\"type\":\"address\"},{\"name\":\"_approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"; + public static String abiERC721Enumerable = "[{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"name\":\"_operator\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"exists\",\"outputs\":[{\"name\":\"_exists\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"_balance\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_operator\",\"type\":\"address\"},{\"name\":\"_approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_approved\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_operator\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"tokenOfOwnerByIndex\",\"outputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"tokenByIndex\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]"; + public static String abiERC721Metadata = "[{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"name\":\"_operator\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"exists\",\"outputs\":[{\"name\":\"_exists\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"_balance\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_operator\",\"type\":\"address\"},{\"name\":\"_approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_approved\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_operator\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"_name\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"_symbol\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"tokenURI\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]"; + public static String abiERC721Receiver = "[{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"onERC721Received\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes4\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"; + public static String abiERC721Token = "[{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"exists\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_name\",\"type\":\"string\"},{\"name\":\"_symbol\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_approved\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_operator\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"tokenURI\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"tokenOfOwnerByIndex\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"tokenByIndex\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]"; + + // https://github.com/miracle1109/threejsgameapp-webaverse/blob/master/erc1155-abi.json + public static String abiERC1155 = "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"}],\"name\":\"TransferBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"TransferSingle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"URI\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"name\":\"balanceOfBatch\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeBatchTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"uri\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]"; +} diff --git a/src/main/java/crypto/forestfish/objects/embedded/evm/AccountDetailsEVM.java b/src/main/java/crypto/forestfish/objects/embedded/evm/AccountDetailsEVM.java new file mode 100644 index 0000000..4706d19 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/embedded/evm/AccountDetailsEVM.java @@ -0,0 +1,62 @@ +package crypto.forestfish.objects.embedded.evm; + +import java.util.ArrayList; +import java.util.HashMap; + +import crypto.forestfish.enums.AddressCategory; +import crypto.forestfish.enums.CustomContractCategory; +import crypto.forestfish.enums.evm.EVMChain; +import crypto.forestfish.objects.evm.EVMKnownAccountAddress; +import crypto.forestfish.objects.evm.EVMKnownCustomContractAddress; + +public class AccountDetailsEVM { + + @SuppressWarnings("serial") + public static HashMap getKnownEVMWalletAddresses() { + HashMap addresses = new HashMap<>(); + + // binance exchange hot wallet + EVMKnownAccountAddress binancehotwallet007 = new EVMKnownAccountAddress( + "Binance Hot Wallet", + "0xe2fc31f816a9b94326492132018c3aecc4a93ae1", + AddressCategory.EXCHANGE, + new ArrayList() {{ + this.add("https://bscscan.com/address/0xe2fc31f816a9b94326492132018c3aecc4a93ae1"); + this.add("https://www.coingecko.com/en/coins/aavegotchi-fomo"); + }}); + addresses.put(binancehotwallet007.getAddress(), binancehotwallet007); + + return addresses; + } + + @SuppressWarnings("serial") + public static HashMap getKnownEVMCustomContractAddressesBSC() { + HashMap addresses = new HashMap<>(); + + // binance hot wallet + EVMKnownCustomContractAddress stargate_busd_staking = new EVMKnownCustomContractAddress( + "Stargate", + "0xe2fc31f816a9b94326492132018c3aecc4a93ae1", + EVMChain.BSC, + CustomContractCategory.STAKING, + new ArrayList() {{ + this.add("https://bscscan.com/address/0x3052a0f6ab15b4ae1df39962d5ddefaca86dab47"); + }}); + addresses.put(stargate_busd_staking.getAddress(), stargate_busd_staking); + + // railgun deposit + EVMKnownCustomContractAddress railgun = new EVMKnownCustomContractAddress( + "Railgun deposit address", + "0x57F5925FeB79B1fd7Cc491F858D7fBc65502D3FE", + EVMChain.GOERLITEST, + CustomContractCategory.PRIVACY, + new ArrayList() {{ + this.add("https://goerli.etherscan.io/address/0x57f5925feb79b1fd7cc491f858d7fbc65502d3fe"); + }}); + addresses.put(railgun.getAddress(), railgun); + + return addresses; + } + + +} diff --git a/src/main/java/crypto/forestfish/objects/embedded/evm/BlockchainDetailsEVM.java b/src/main/java/crypto/forestfish/objects/embedded/evm/BlockchainDetailsEVM.java new file mode 100644 index 0000000..8b840f2 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/embedded/evm/BlockchainDetailsEVM.java @@ -0,0 +1,7748 @@ +package crypto.forestfish.objects.embedded.evm; + +import java.util.ArrayList; +import java.util.HashMap; + +import crypto.forestfish.enums.BlockchainType; +import crypto.forestfish.enums.TokenCategory; +import crypto.forestfish.enums.evm.ArbitrumONEERC20Token; +import crypto.forestfish.enums.evm.ArbitrumONEERC721Token; +import crypto.forestfish.enums.evm.AvaxERC20Token; +import crypto.forestfish.enums.evm.BSCBEP20Token; +import crypto.forestfish.enums.evm.BSCERC721Token; +import crypto.forestfish.enums.evm.BaseERC20Token; +import crypto.forestfish.enums.evm.BitkubERC721Token; +import crypto.forestfish.enums.evm.BitkubKAP20Token; +import crypto.forestfish.enums.evm.BoraChainKIP7Token; +import crypto.forestfish.enums.evm.CeloERC20Token; +import crypto.forestfish.enums.evm.ConfluxERC20Token; +import crypto.forestfish.enums.evm.ConfluxTestnetERC20Token; +import crypto.forestfish.enums.evm.CoreERC20Token; +import crypto.forestfish.enums.evm.EVMChain; +import crypto.forestfish.enums.evm.EVMPriceMechanism; +import crypto.forestfish.enums.evm.EthereumERC20Token; +import crypto.forestfish.enums.evm.EthereumERC721Token; +import crypto.forestfish.enums.evm.FantomERC20Token; +import crypto.forestfish.enums.evm.GoerliERC20Token; +import crypto.forestfish.enums.evm.GoerliERC721Token; +import crypto.forestfish.enums.evm.KavaTestERC20Token; +import crypto.forestfish.enums.evm.KlaytnKIP7Token; +import crypto.forestfish.enums.evm.LineaERC20Token; +import crypto.forestfish.enums.evm.LineaERC721Token; +import crypto.forestfish.enums.evm.MantleERC20Token; +import crypto.forestfish.enums.evm.MantleERC721Token; +import crypto.forestfish.enums.evm.MantleTestnetERC20Token; +import crypto.forestfish.enums.evm.MetisERC20Token; +import crypto.forestfish.enums.evm.MilkomedaA1ERC20Token; +import crypto.forestfish.enums.evm.MilkomedaC1ERC20Token; +import crypto.forestfish.enums.evm.MilkomedaC1ERC721Token; +import crypto.forestfish.enums.evm.MoonbeamERC20Token; +import crypto.forestfish.enums.evm.MoonbeamERC721Token; +import crypto.forestfish.enums.evm.MumbaiERC20Token; +import crypto.forestfish.enums.evm.OptimismERC20Token; +import crypto.forestfish.enums.evm.PolygonERC1155Token; +import crypto.forestfish.enums.evm.PolygonERC20Token; +import crypto.forestfish.enums.evm.PolygonERC721Token; +import crypto.forestfish.enums.evm.PulsechainERC20Token; +import crypto.forestfish.enums.evm.ScrollERC20Token; +import crypto.forestfish.enums.evm.WemixERC20Token; +import crypto.forestfish.enums.evm.ZKEVMERC20Token; +import crypto.forestfish.enums.evm.ZKSyncEraERC721Token; +import crypto.forestfish.enums.evm.ZkSyncERC20Token; +import crypto.forestfish.objects.evm.model.chain.EVMChainIndex; +import crypto.forestfish.objects.evm.model.chain.EVMChainInfo; +import crypto.forestfish.objects.evm.model.chain.EVMCurrency; +import crypto.forestfish.objects.evm.model.erc20.ERC20TokenIndex; +import crypto.forestfish.objects.evm.model.erc20.EVMERC20TokenInfo; +import crypto.forestfish.objects.evm.model.nft.EVMERC1155TokenInfo; +import crypto.forestfish.objects.evm.model.nft.EVMERC721TokenInfo; +import crypto.forestfish.objects.evm.model.nft.EVMNFTIndex; +import crypto.forestfish.utils.JSONUtils; + +public class BlockchainDetailsEVM { + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateAvaxTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // stg + EVMERC20TokenInfo stg = new EVMERC20TokenInfo( + AvaxERC20Token.STG.toString(), + "0x2f6f07cdcf3588944bf4c42ac74ff24bf56e7590", + "StarGate token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.AVAX.toString(), + new ArrayList() {{ + this.add("https://snowtrace.io/address/0x2f6f07cdcf3588944bf4c42ac74ff24bf56e7590"); + this.add("https://www.coingecko.com/en/coins/stargate-finance"); + }}); + tokens.put(AvaxERC20Token.STG.toString(), stg); + + // png + EVMERC20TokenInfo png = new EVMERC20TokenInfo( + AvaxERC20Token.PNG.toString(), + "0x60781c2586d68229fde47564546784ab3faca982", + "PNG token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.AVAX.toString(), + new ArrayList() {{ + this.add("https://snowtrace.io/address/0x60781c2586d68229fde47564546784ab3faca982"); + this.add("https://www.coingecko.com/en/coins/pangolin"); + }}); + tokens.put(AvaxERC20Token.PNG.toString(), png); + + // usdc + EVMERC20TokenInfo usdc = new EVMERC20TokenInfo( + AvaxERC20Token.USDC.toString(), + "0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e", + "USDC stablecoin token", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.AVAX.toString(), + new ArrayList() {{ + this.add("https://snowtrace.io/address/0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e"); + this.add("https://www.coingecko.com/en/coins/usd-coin"); + }}); + tokens.put(AvaxERC20Token.USDC.toString(), usdc); + + // dai + EVMERC20TokenInfo dai = new EVMERC20TokenInfo( + AvaxERC20Token.DAI.toString(), + "0xd586e7f844cea2f87f50152665bcbc2c279d8d70", + "DAI stablecoin token", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.AVAX.toString(), + new ArrayList() {{ + this.add("https://snowtrace.io/address/0xd586e7f844cea2f87f50152665bcbc2c279d8d70"); + this.add("https://www.coingecko.com/en/coins/dai"); + }}); + tokens.put(AvaxERC20Token.DAI.toString(), dai); + + // usdt + EVMERC20TokenInfo usdt = new EVMERC20TokenInfo( + AvaxERC20Token.USDT.toString(), + "0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7", + "Tether stablecoin token", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.AVAX.toString(), + new ArrayList() {{ + this.add("https://snowtrace.io/address/0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7"); + this.add("https://www.coingecko.com/en/coins/tether"); + }}); + tokens.put(AvaxERC20Token.USDT.toString(), usdt); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static EVMNFTIndex generateBitkubNFTIndex() { + HashMap erc721tokens = new HashMap<>(); + HashMap erc1155tokens = new HashMap<>(); + + // mmv item + EVMERC721TokenInfo mmv_item = new EVMERC721TokenInfo( + BitkubERC721Token.MMV_ITEM.toString(), + "0xd08ac40b3a0a7fb20b026a3b6cd5d7cfadc3d6f5", + 0L, + "Morning Moon Village game item", + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/address/0xd08ac40b3a0a7fb20b026a3b6cd5d7cfadc3d6f5"); + this.add("https://morningmoonvillage.com/"); + this.add("https://mmv.megaland.io/"); + }}); + erc721tokens.put(BitkubERC721Token.MMV_ITEM.toString(), mmv_item); + + // sandx + EVMERC721TokenInfo sandx = new EVMERC721TokenInfo( + BitkubERC721Token.SANDX.toString(), + "0x998c4a4f5231b10ad867bd5d99fa181495f34cd8", + 0L, + "SandX NFT", + TokenCategory.NFT.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/address/0x998c4a4f5231b10ad867bd5d99fa181495f34cd8"); + this.add("https://www.megaland.io/"); + + }}); + erc721tokens.put(BitkubERC721Token.SANDX.toString(), sandx); + + return new EVMNFTIndex(erc721tokens, erc1155tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateBitkubTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // wrapped bitkub (KKUB) + EVMERC20TokenInfo kkub = new EVMERC20TokenInfo( + BitkubKAP20Token.KKUB.toString(), + "0x67eBD850304c70d983B2d1b93ea79c7CD6c3F6b5", + "Wrapped KUB (KKUB) token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0x67eBD850304c70d983B2d1b93ea79c7CD6c3F6b5/token-transfers"); + }}); + tokens.put(BitkubKAP20Token.KKUB.toString(), kkub); + + // mmv diamon LP + EVMERC20TokenInfo diamonLP = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_DIAMON_LP.toString(), + "0x7Bf51541208A70b784006eF7Bd6F774F4012Cd38", + "Morning Moon Village diamon LP", + 18, + TokenCategory.DEFI.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0x7Bf51541208A70b784006eF7Bd6F774F4012Cd38/token-transfers"); + }}); + tokens.put(BitkubKAP20Token.MMV_DIAMON_LP.toString(), diamonLP); + + // mmv rag + EVMERC20TokenInfo mmv_rag = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_RAG.toString(), + "0x1F14690e6c7D02fCeB67c6b818aa2C093e16fe27", + "Morning Moon Village game item", + 0, + TokenCategory.DEFI.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0x1F14690e6c7D02fCeB67c6b818aa2C093e16fe27/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_RAG.toString(), mmv_rag); + + // mmv leather piece + EVMERC20TokenInfo mmv_leather_piece = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_LEATHER_PIECE.toString(), + "0x15aa87eb74069d3800f8e75A93FC04fda79AA24d", + "Morning Moon Village game item", + 0, + TokenCategory.DEFI.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0x15aa87eb74069d3800f8e75A93FC04fda79AA24d/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_LEATHER_PIECE.toString(), mmv_leather_piece); + + // mmv white button mushroom + EVMERC20TokenInfo mmv_white_button_mushroom = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_WBUTTON_MUSHROOM.toString(), + "0xcb74a1A9dB4285E97D4dE8aa4B61cd10277Ab479", + "Morning Moon Village game item", + 0, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0xcb74a1A9dB4285E97D4dE8aa4B61cd10277Ab479/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_WBUTTON_MUSHROOM.toString(), mmv_white_button_mushroom); + + // mmv tomato soup + EVMERC20TokenInfo mmv_tomato_soup = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_TOMATOSOUP.toString(), + "0xbE46a81D181069aC0Ff18F4F7239Df10422E6DC3", + "Morning Moon Village game item", + 0, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0xbE46a81D181069aC0Ff18F4F7239Df10422E6DC3/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_TOMATOSOUP.toString(), mmv_tomato_soup); + + // mmv tomato seed + EVMERC20TokenInfo mmv_tomato_seed = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_TOMATOSEED.toString(), + "0xe991151Bf43bD712beAC33e5cFF2580841c9b440", + "Morning Moon Village game item", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0xe991151Bf43bD712beAC33e5cFF2580841c9b440/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_TOMATOSEED.toString(), mmv_tomato_seed); + + // mmv stir fried cabbage + EVMERC20TokenInfo mmv_sf_cabbage = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_SF_CABBAGE.toString(), + "0xc2990515610028139f68016b321a0c36a5101104", + "Morning Moon Village game item", + 0, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0xc2990515610028139f68016b321a0c36a5101104/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_SF_CABBAGE.toString(), mmv_sf_cabbage); + + // mmv silver key + EVMERC20TokenInfo mmv_silver_key = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_SILVERKEY.toString(), + "0x73d05f935534918bbc87cb353928cb957ed03697", + "Morning Moon Village game item", + 0, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0x73d05f935534918bbc87cb353928cb957ed03697/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_SILVERKEY.toString(), mmv_silver_key); + + // mmv shitake mushroom + EVMERC20TokenInfo mmv_shitake_mushroom = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_SHITAKE_MUSHROOM.toString(), + "0xd3b314b101b26fa2bd19df0d845a632d72c4fc44", + "Morning Moon Village game item", + 0, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0xd3b314b101b26fa2bd19df0d845a632d72c4fc44/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_SHITAKE_MUSHROOM.toString(), mmv_shitake_mushroom); + + // mmv salad + EVMERC20TokenInfo mmv_salad = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_SALAD.toString(), + "0x2944d051dc66669e04629b827ae9e3ebcb1e48d9", + "Morning Moon Village game item", + 0, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0x2944d051dc66669e04629b827ae9e3ebcb1e48d9/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_SALAD.toString(), mmv_salad); + + // mmv lumi + EVMERC20TokenInfo mmv_lumi = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_LUMI.toString(), + "0x95013dcb6a561e6c003aed9c43fb8b64008aa361", + "Morning Moon Village game item", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0x95013dcb6a561e6c003aed9c43fb8b64008aa361/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_LUMI.toString(), mmv_lumi); + + // mmv king trumpet mushroom + EVMERC20TokenInfo mmv_king_trumpet_mushroom = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_KTRUMPET_MUSHROOM.toString(), + "0xc14f24835efe355106ab8725488f16f93c8c5f96", + "Morning Moon Village game item", + 0, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0xc14f24835efe355106ab8725488f16f93c8c5f96/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_KTRUMPET_MUSHROOM.toString(), mmv_king_trumpet_mushroom); + + // mmv honey + EVMERC20TokenInfo mmv_honey = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_HONEY.toString(), + "0x575d7bfdbdf255d5741571334f159d903de1544f", + "Morning Moon Village game item", + 0, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0x575d7bfdbdf255d5741571334f159d903de1544f/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_HONEY.toString(), mmv_honey); + + // mmv greenapple + EVMERC20TokenInfo mmv_greenapple = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_GREENAPPLE.toString(), + "0x417e28bd41cd45d9f996b69450f81b02821a6d64", + "Morning Moon Village game item", + 0, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0x417e28bd41cd45d9f996b69450f81b02821a6d64/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_GREENAPPLE.toString(), mmv_greenapple); + + // mmv driedapple + EVMERC20TokenInfo mmv_driedapple = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_DRIEDAPPLE.toString(), + "0xb035c229903a0cff939be36b532d8c11204e6837", + "Morning Moon Village game item", + 0, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0xb035c229903a0cff939be36b532d8c11204e6837/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_DRIEDAPPLE.toString(), mmv_driedapple); + + // mmv corn soup + EVMERC20TokenInfo mmv_cornsoup = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_CORNSOUP.toString(), + "0x2b09ae76dfc601210407560502b340e104787b34", + "Morning Moon Village game item", + 0, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0x2b09ae76dfc601210407560502b340e104787b34/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_CORNSOUP.toString(), mmv_cornsoup); + + // mmv corn seed + EVMERC20TokenInfo mmv_cornseed = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_CORNSEED.toString(), + "0xe27aebed61be207e83fc05fbc408420c737881da", + "Morning Moon Village game item", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0xe27aebed61be207e83fc05fbc408420c737881da/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_CORNSEED.toString(), mmv_cornseed); + + // mmv carrot seed + EVMERC20TokenInfo mmv_carrotseed = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_CARROTSEED.toString(), + "0x7b263d648fff39142abecb07a1bb85297e09982d", + "Morning Moon Village game item", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0x7b263d648fff39142abecb07a1bb85297e09982d/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_CARROTSEED.toString(), mmv_carrotseed); + + // mmv cabbage seed + EVMERC20TokenInfo mmv_cabbageseed = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_CABBAGESEED.toString(), + "0x1f8b5af0ec97c44b24366b36c40f2d4aca2c73e2", + "Morning Moon Village game item", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0x1f8b5af0ec97c44b24366b36c40f2d4aca2c73e2/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_CABBAGESEED.toString(), mmv_cabbageseed); + + // green herb + EVMERC20TokenInfo mmv_greenherb = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_GREENHERB.toString(), + "0xde496524c30c460922e7810ddc6c806c0e2c5354", + "Morning Moon Village game item", + 0, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0xde496524c30c460922e7810ddc6c806c0e2c5354/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_GREENHERB.toString(), mmv_greenherb); + + // lesser health potion + EVMERC20TokenInfo mmv_lhealth_potion = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_LHEALTHPOTION.toString(), + "0xe66f21d817af8f99129af6023332dd7b37503b9d", + "Morning Moon Village game item", + 0, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0xe66f21d817af8f99129af6023332dd7b37503b9d/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_LHEALTHPOTION.toString(), mmv_lhealth_potion); + + // health potion + EVMERC20TokenInfo mmv_health_potion = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_HEALTHPOTION.toString(), + "0xbd60c8caf6e22907576d9e363ab1f91b43aaf769", + "Morning Moon Village game item", + 0, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0xbd60c8caf6e22907576d9e363ab1f91b43aaf769/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_HEALTHPOTION.toString(), mmv_health_potion); + + // silver key + EVMERC20TokenInfo mmv_silverkey = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_LHEALTHPOTION.toString(), + "0xe66f21d817af8f99129af6023332dd7b37503b9d", + "Morning Moon Village game item", + 0, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0xe66f21d817af8f99129af6023332dd7b37503b9d/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_LHEALTHPOTION.toString(), mmv_silverkey); + + // red herb + EVMERC20TokenInfo mmv_redherb = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_REDHERB.toString(), + "0x3F69C740456150268C5e23bD05a2A10Bf9e5c3CB", + "Morning Moon Village game item", + 0, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0x3F69C740456150268C5e23bD05a2A10Bf9e5c3CB/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_REDHERB.toString(), mmv_redherb); + + // mmv banana + EVMERC20TokenInfo mmv_banana = new EVMERC20TokenInfo( + BitkubKAP20Token.MMV_BANANA.toString(), + "0x0944882cf373adc8c3de740821fb14c8669e89eb", + "Morning Moon Village game item", + 0, + TokenCategory.GAMING.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0x0944882cf373adc8c3de740821fb14c8669e89eb/token-transfers"); + this.add("https://morningmoonvillage.com/"); + }}); + tokens.put(BitkubKAP20Token.MMV_BANANA.toString(), mmv_banana); + + // bitkub peg USDT + EVMERC20TokenInfo usdt = new EVMERC20TokenInfo( + BitkubKAP20Token.USDT.toString(), + "0x7d984c24d2499d840eb3b7016077164e15e5faa6", + "Morning Moon Village game item", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0x7d984c24d2499d840eb3b7016077164e15e5faa6/token-transfers"); + }}); + tokens.put(BitkubKAP20Token.USDT.toString(), usdt); + + // test + /* + EVMERC20TokenInfo test = new EVMERC20TokenInfo( + BitkubKAP20Token.TEST.toString(), + "0x2b591e99afe9f32eaa6214f7b7629768c40eeb39", + //"0x2b591e99afe9f32eaa6214f7b7629768c40eeb39", // HEX :) + "TEST token", + 18, + TokenCategory.TEST.toString(), + EVMChain.BITKUB.toString(), + new ArrayList() {{ + this.add("https://www.bkcscan.com/tokens/0xMOJO"); + }}); + tokens.put(BitkubKAP20Token.TEST.toString(), test); + */ + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateBorachainTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // tBORA + EVMERC20TokenInfo tbora = new EVMERC20TokenInfo( + BoraChainKIP7Token.tBORA.toString(), + "0x797115bcdbD85DC865222724eD67d473CE168962", + "tBORA token", + 18, + TokenCategory.GASCURRENCY.toString(), + EVMChain.BORACHAIN.toString(), + new ArrayList() {{ + this.add("https://scope.boraportal.com/token/0x797115bcdbd85dc865222724ed67d473ce168962"); + }}); + tokens.put(BoraChainKIP7Token.tBORA.toString(), tbora); + + // bluesalt + EVMERC20TokenInfo bluesalt = new EVMERC20TokenInfo( + BoraChainKIP7Token.BSLT.toString(), + "0xcfdbf6a1f765c295d8d557e841c1304019318525", + "ArcheWorld Blue Salt game token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BORACHAIN.toString(), + new ArrayList() {{ + this.add("https://scope.boraportal.com/address/0xcFdbf6a1f765C295d8D557E841C1304019318525"); + }}); + tokens.put(BoraChainKIP7Token.BSLT.toString(), bluesalt); + + // test + EVMERC20TokenInfo test = new EVMERC20TokenInfo( + BoraChainKIP7Token.TEST.toString(), + "0x7769cf946c011BB3A22d20ba6bF7f0bC419c722f", + //"0x7769cf946c011BB3A22d20ba6bF7f0bC419c722f", // BIRDIE token :) + "TEST token", + 18, + TokenCategory.TEST.toString(), + EVMChain.KLAYTN.toString(), + new ArrayList() {{ + this.add("https://scope.boraportal.com/token/0x7769cf946c011BB3A22d20ba6bF7f0bC419c722f"); + }}); + tokens.put(BoraChainKIP7Token.TEST.toString(), test); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static EVMNFTIndex generateZKSyncEraNFTIndex() { + HashMap erc721tokens = new HashMap<>(); + HashMap erc1155tokens = new HashMap<>(); + + // zkape + EVMERC721TokenInfo zkape = new EVMERC721TokenInfo( + ZKSyncEraERC721Token.ZKAPE.toString(), + "0x5e6f0f1d604d7300c10933aa8834afa034d448ea", + 0L, + "ZKSyncEra Ape", + TokenCategory.SOCIAL.toString(), + EVMChain.ZKSYNCERA.toString(), + new ArrayList() {{ + this.add("https://explorer.zksync.io/address/0x5e6f0f1d604d7300c10933aa8834afa034d448ea"); + this.add("https://zkape.io"); + this.add("https://mintsquare.io/collection/zksync/0x5e6f0f1d604d7300c10933aa8834afa034d448ea"); + }}); + erc721tokens.put(ZKSyncEraERC721Token.ZKAPE.toString(), zkape); + + // eranameservice + EVMERC721TokenInfo eranameservice = new EVMERC721TokenInfo( + ZKSyncEraERC721Token.ERANAMESERVICE.toString(), + "0x935442AF47F3dc1c11F006D551E13769F12eab13", + 0L, + "ERA Name service", + TokenCategory.NAMESERVICE.toString(), + EVMChain.ZKSYNCERA.toString(), + new ArrayList() {{ + this.add("https://explorer.zksync.io/address/0x935442AF47F3dc1c11F006D551E13769F12eab13"); + this.add("https://era.name"); + }}); + erc721tokens.put(ZKSyncEraERC721Token.ERANAMESERVICE.toString(), eranameservice); + + + return new EVMNFTIndex(erc721tokens, erc1155tokens); + } + + @SuppressWarnings("serial") + public static EVMNFTIndex generateBSCNFTIndex() { + HashMap erc721tokens = new HashMap<>(); + HashMap erc1155tokens = new HashMap<>(); + + // outerringmmoweapon + EVMERC721TokenInfo outerringmmo_weapon = new EVMERC721TokenInfo( + BSCERC721Token.OUTERRINGMMO_WEAPON.toString(), + "0xeb1aca4e9aa3448b7fecb2b555301325b5931ad9", + 0L, + "Outer Ring MMO Weapon", + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/token/0xeb1aca4e9aa3448b7fecb2b555301325b5931ad9"); + this.add("https://babylons.io/outerringofficial"); + }}); + erc721tokens.put(BSCERC721Token.OUTERRINGMMO_WEAPON.toString(), outerringmmo_weapon); + + // outerringmmolandvehicle + EVMERC721TokenInfo outerringmmolandvehicle = new EVMERC721TokenInfo( + BSCERC721Token.OUTERRINGMMO_LANDVEH.toString(), + "0x21d7d56350fcf7470e4ac38bb2f32c1461a73d8c", + 0L, + "Outer Ring MMO Land Vehicle", + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/token/0x21d7d56350fcf7470e4ac38bb2f32c1461a73d8c"); + this.add("https://babylons.io/outerringofficial"); + }}); + erc721tokens.put(BSCERC721Token.OUTERRINGMMO_LANDVEH.toString(), outerringmmolandvehicle); + + // outerringmmospacevehicle + EVMERC721TokenInfo outerringmmospacevehicle = new EVMERC721TokenInfo( + BSCERC721Token.OUTERRINGMMO_SPACEVEH.toString(), + "0xceaac6759038d4d3b8791683b27b1021efa57003", + 0L, + "Outer Ring MMO Space Vehicle", + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/token/0xceaac6759038d4d3b8791683b27b1021efa57003"); + this.add("https://babylons.io/outerringofficial"); + }}); + erc721tokens.put(BSCERC721Token.OUTERRINGMMO_SPACEVEH.toString(), outerringmmospacevehicle); + + // outerringmmoarmor + EVMERC721TokenInfo outerringmmoarmor = new EVMERC721TokenInfo( + BSCERC721Token.OUTERRINGMMO_ARMOR.toString(), + "0x0b36f379d7b3b4588f8b8e7e65091b2c44fa6dde", + 0L, + "Outer Ring MMO Armor", + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/token/0x0b36f379d7b3b4588f8b8e7e65091b2c44fa6dde"); + this.add("https://babylons.io/outerringofficial"); + }}); + erc721tokens.put(BSCERC721Token.OUTERRINGMMO_ARMOR.toString(), outerringmmoarmor); + + // outerringmmoexocredits + EVMERC721TokenInfo outerringmmoexocredits = new EVMERC721TokenInfo( + BSCERC721Token.OUTERRINGMMO_EXOCRED.toString(), + "0x3fb6e0dd0eefff9615f186a6bb3a66a396ed0a58", + 0L, + "Outer Ring MMO Exocredits", + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/address/0x3fb6e0dd0eefff9615f186a6bb3a66a396ed0a58"); + this.add("https://babylons.io/outerringofficial"); + }}); + erc721tokens.put(BSCERC721Token.OUTERRINGMMO_EXOCRED.toString(), outerringmmoexocredits); + + // dreamcard + EVMERC721TokenInfo dreamcard = new EVMERC721TokenInfo( + BSCERC721Token.DREAMCARD.toString(), + "0xe6965b4f189dbdb2bd65e60abaeb531b6fe9580b", + 0L, + "X World Games Dreamcard", + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/address/0xe6965b4f189dbdb2bd65e60abaeb531b6fe9580b"); + this.add("https://babylons.io/outerringofficial"); + }}, + new ArrayList() {{ + this.add(EVMChain.BSC.toString() + ":" + BSCBEP20Token.XWG.toString()); + }}); + erc721tokens.put(BSCERC721Token.DREAMCARD.toString(), dreamcard); + + // stellafantasy + EVMERC721TokenInfo stellafantasy = new EVMERC721TokenInfo( + BSCERC721Token.STELLAFANTASY_ASSET.toString(), + "0x80461f88de22b2363113226f0749a7a59cc2225a", + 0L, + "Stella Fantasy Asset", + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/token/0x80461f88de22b2363113226f0749a7a59cc2225a"); + this.add("https://www.stellafantasy.io/"); + }}, + new ArrayList() {{ + this.add(EVMChain.BSC.toString() + ":" + BSCBEP20Token.SFTY.toString()); + }}); + erc721tokens.put(BSCERC721Token.STELLAFANTASY_ASSET.toString(), stellafantasy); + + return new EVMNFTIndex(erc721tokens, erc1155tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateBSCTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // metis + EVMERC20TokenInfo metis = new EVMERC20TokenInfo( + BSCBEP20Token.METIS.toString(), + "0xe552fb52a4f19e44ef5a967632dbc320b0820639", + "METIS token on BSC", + 18, + TokenCategory.GASCURRENCY.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/address/0xe552fb52a4f19e44ef5a967632dbc320b0820639"); + this.add("https://www.coingecko.com/en/coins/metis-token"); + }}); + tokens.put(BSCBEP20Token.METIS.toString(), metis); + + // sups + EVMERC20TokenInfo sups = new EVMERC20TokenInfo( + BSCBEP20Token.SUPS.toString(), + "0xc99cfaa8f5d9bd9050182f29b83cc9888c5846c4", + "Supremacy game token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/address/0xc99cfaa8f5d9bd9050182f29b83cc9888c5846c4"); + this.add("https://www.coingecko.com/en/coins/supremacy"); + }}); + tokens.put(BSCBEP20Token.SUPS.toString(), sups); + + // mobox + EVMERC20TokenInfo mobox = new EVMERC20TokenInfo( + BSCBEP20Token.MOBOX.toString(), + "0x3203c9e46ca618c8c1ce5dc67e7e9d75f5da2377", + "MOBOX game token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/address/0x3203c9e46ca618c8c1ce5dc67e7e9d75f5da2377"); + this.add("https://www.coingecko.com/en/coins/mobox"); + }}); + tokens.put(BSCBEP20Token.MOBOX.toString(), mobox); + + // sck + EVMERC20TokenInfo sck = new EVMERC20TokenInfo( + BSCBEP20Token.SCK.toString(), + "0x227a3ef4d41d0215123f3197faa087bf71d2236a", + "Space Corsair Key", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/address/0x227a3ef4d41d0215123f3197faa087bf71d2236a"); + this.add("https://www.coingecko.com/en/coins/space-corsair-key"); + }}); + tokens.put(BSCBEP20Token.SCK.toString(), sck); + + // tron + EVMERC20TokenInfo tron = new EVMERC20TokenInfo( + BSCBEP20Token.TRON.toString(), + "0x85eac5ac2f758618dfa09bdbe0cf174e7d574d5b", + "TRON TRX token", + 18, + TokenCategory.SCAM.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://coinmarketcap.com/currencies/tron/"); + }}); + tokens.put(BSCBEP20Token.TRON.toString(), tron); + + // catgirl + EVMERC20TokenInfo catgirl = new EVMERC20TokenInfo( + BSCBEP20Token.CATGIRL.toString(), + "0x79ebc9a2ce02277a4b5b3a768b1c0a4ed75bd936", + "Catgirl NFT Token", + 18, + TokenCategory.NFT.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/address/0x79ebc9a2ce02277a4b5b3a768b1c0a4ed75bd936"); + this.add("https://www.coingecko.com/en/coins/catgirl"); + }}); + tokens.put(BSCBEP20Token.CATGIRL.toString(), catgirl); + + // gq + EVMERC20TokenInfo gq = new EVMERC20TokenInfo( + BSCBEP20Token.GQ.toString(), + "0xf700d4c708c2be1463e355f337603183d20e0808", + "Outer Ring MMO Game Token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/address/0xf700d4c708c2be1463e355f337603183d20e0808"); + this.add("https://www.coingecko.com/en/coins/outer-ring"); + }}); + tokens.put(BSCBEP20Token.GQ.toString(), gq); + + // plu + EVMERC20TokenInfo plu = new EVMERC20TokenInfo( + BSCBEP20Token.PLU.toString(), + "0x07958be5d12365db62a6535d0a88105944a2e81e", + "Outer Ring MMO Plutonium Token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/token/0x07958be5d12365db62a6535d0a88105944a2e81e"); + }}); + tokens.put(BSCBEP20Token.PLU.toString(), plu); + + // vanadium + EVMERC20TokenInfo vanadium = new EVMERC20TokenInfo( + BSCBEP20Token.VAN.toString(), + "0xd3dbf84f7aed90d5f56e8d7cab2f43004e9ef6a6", + "Outer Ring MMO Vanadium Token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/token/0xd3dbf84f7aed90d5f56e8d7cab2f43004e9ef6a6"); + }}); + tokens.put(BSCBEP20Token.VAN.toString(), vanadium); + + // carbon + EVMERC20TokenInfo carbon = new EVMERC20TokenInfo( + BSCBEP20Token.CAR.toString(), + "0x253b7a24003684f7b4fe87e531a017c7382a3894", + "Outer Ring MMO Carbon Token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/token/0x253b7a24003684f7b4fe87e531a017c7382a3894"); + }}); + tokens.put(BSCBEP20Token.CAR.toString(), carbon); + + // nickel + EVMERC20TokenInfo nickel = new EVMERC20TokenInfo( + BSCBEP20Token.NIC.toString(), + "0xf9a71cba51e260e184a72d9edf888d3f99f3bac1", + "Outer Ring MMO Nickel Token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/token/0xf9a71cba51e260e184a72d9edf888d3f99f3bac1"); + }}); + tokens.put(BSCBEP20Token.NIC.toString(), nickel); + + // methane + EVMERC20TokenInfo methane = new EVMERC20TokenInfo( + BSCBEP20Token.MET.toString(), + "0x03697caf2e5458c7c2a8d9f8818079c2ae72f353", + "Outer Ring MMO Methane Token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/token/0x03697caf2e5458c7c2a8d9f8818079c2ae72f353"); + }}); + tokens.put(BSCBEP20Token.MET.toString(), methane); + + // acetylene + EVMERC20TokenInfo acetylene = new EVMERC20TokenInfo( + BSCBEP20Token.ACE.toString(), + "0x6bf6c2b429421a55d90a02c56b2d8bffbc636039", + "Outer Ring MMO Acetylene Token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/token/0x6bf6c2b429421a55d90a02c56b2d8bffbc636039"); + }}); + tokens.put(BSCBEP20Token.ACE.toString(), acetylene); + + // argon + EVMERC20TokenInfo argon = new EVMERC20TokenInfo( + BSCBEP20Token.ARG.toString(), + "0x0efcf1737b81ce89325b17eafae2686a8afe8bd4", + "Outer Ring MMO Acetylene Token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/token/0x0efcf1737b81ce89325b17eafae2686a8afe8bd4"); + }}); + tokens.put(BSCBEP20Token.ARG.toString(), argon); + + // copper + EVMERC20TokenInfo copper = new EVMERC20TokenInfo( + BSCBEP20Token.COP.toString(), + "0x892f23e32b82ef0d5394cf33dcd4dff7f4b274b0", + "Outer Ring MMO Copper Token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/token/0x892f23e32b82ef0d5394cf33dcd4dff7f4b274b0"); + }}); + tokens.put(BSCBEP20Token.COP.toString(), copper); + + // iron + EVMERC20TokenInfo iron = new EVMERC20TokenInfo( + BSCBEP20Token.IRON.toString(), + "0xbd1945cd85a2be93a6475381c9f5edf19407a921", + "Outer Ring MMO Iron Token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/token/0xbd1945cd85a2be93a6475381c9f5edf19407a921"); + }}); + tokens.put(BSCBEP20Token.IRON.toString(), iron); + + // venus + EVMERC20TokenInfo venus = new EVMERC20TokenInfo( + BSCBEP20Token.XVS.toString(), + "0xcf6bb5389c92bdda8a3747ddb454cb7a64626c63", + "Venus Token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/address/0xcf6bb5389c92bdda8a3747ddb454cb7a64626c63"); + this.add("https://www.coingecko.com/en/coins/venus"); + }}); + tokens.put(BSCBEP20Token.XVS.toString(), venus); + + // chmb + EVMERC20TokenInfo chmb = new EVMERC20TokenInfo( + BSCBEP20Token.CHMB.toString(), + "0x5492ef6aeeba1a3896357359ef039a8b11621b45", + "Chumbi Valley Game Token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/token/0x5492ef6aeeba1a3896357359ef039a8b11621b45"); + this.add("https://www.coingecko.com/en/coins/chumbai-valley"); + }}); + tokens.put(BSCBEP20Token.CHMB.toString(), chmb); + + // xwg + EVMERC20TokenInfo xwg = new EVMERC20TokenInfo( + BSCBEP20Token.XWG.toString(), + "0x6b23c89196deb721e6fd9726e6c76e4810a464bc", + "X World Games Token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/address/0x6b23c89196deb721e6fd9726e6c76e4810a464bc"); + this.add("https://www.coingecko.com/en/coins/x-world-games"); + }}); + tokens.put(BSCBEP20Token.XWG.toString(), xwg); + + // nftart + EVMERC20TokenInfo nftart = new EVMERC20TokenInfo( + BSCBEP20Token.NFTART.toString(), + "0xf7844cb890f4c339c497aeab599abdc3c874b67a", + "NFT Art Token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/address/0xf7844cb890f4c339c497aeab599abdc3c874b67a"); + this.add("https://www.coingecko.com/en/coins/nft-art-finance"); + }}); + tokens.put(BSCBEP20Token.NFTART.toString(), nftart); + + // vikingswap + EVMERC20TokenInfo vikingswap = new EVMERC20TokenInfo( + BSCBEP20Token.VIKINGSWAP.toString(), + "0x896ede222d3f7f3414e136a2791bdb08aaa25ce0", + "Vikingswap Token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/address/0x896ede222d3f7f3414e136a2791bdb08aaa25ce0"); + this.add("https://www.coingecko.com/en/coins/viking-swap"); + }}); + tokens.put(BSCBEP20Token.VIKINGSWAP.toString(), vikingswap); + + // babycake + EVMERC20TokenInfo babycake = new EVMERC20TokenInfo( + BSCBEP20Token.BABYCAKE.toString(), + "0xdb8d30b74bf098af214e862c90e647bbb1fcc58c", + "BABYCAKE DEFI reflection Token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/token/0xdb8d30b74bf098af214e862c90e647bbb1fcc58c"); + this.add("https://www.coingecko.com/en/coins/baby-cake"); + }}); + tokens.put(BSCBEP20Token.BABYCAKE.toString(), babycake); + + // cake + EVMERC20TokenInfo cake = new EVMERC20TokenInfo( + BSCBEP20Token.CAKE.toString(), + "0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82", + "Pancakeswap DEFI Token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/token/0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82"); + this.add("https://www.coingecko.com/en/coins/pancakeswap"); + }}); + tokens.put(BSCBEP20Token.CAKE.toString(), cake); + + // stg + EVMERC20TokenInfo stg = new EVMERC20TokenInfo( + BSCBEP20Token.STG.toString(), + "0xb0d502e938ed5f4df2e681fe6e419ff29631d62b", + "StarGate token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/address/0xb0d502e938ed5f4df2e681fe6e419ff29631d62b"); + this.add("https://www.coingecko.com/en/coins/stargate-finance"); + }}); + tokens.put(BSCBEP20Token.STG.toString(), stg); + + // usdc + EVMERC20TokenInfo usdc = new EVMERC20TokenInfo( + BSCBEP20Token.USDC.toString(), + "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "USDC stablecoin token", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/address/0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d"); + this.add("https://www.coingecko.com/en/coins/usd-coin"); + }}); + tokens.put(BSCBEP20Token.USDC.toString(), usdc); + + // dai + EVMERC20TokenInfo dai = new EVMERC20TokenInfo( + BSCBEP20Token.DAI.toString(), + "0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3", + "DAI stablecoin token", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/address/0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3"); + this.add("https://www.coingecko.com/en/coins/dai"); + }}); + tokens.put(BSCBEP20Token.DAI.toString(), dai); + + // usdt + EVMERC20TokenInfo usdt = new EVMERC20TokenInfo( + BSCBEP20Token.USDT.toString(), + "0x55d398326f99059ff775485246999027b3197955", + "Tether stablecoin token", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/address/0x55d398326f99059ff775485246999027b3197955"); + this.add("https://www.coingecko.com/en/coins/tether"); + }}); + tokens.put(BSCBEP20Token.USDT.toString(), usdt); + + // busd stargate LP, staking contract: https://bscscan.com/address/0x3052a0f6ab15b4ae1df39962d5ddefaca86dab47#code + EVMERC20TokenInfo busdsglp = new EVMERC20TokenInfo( + BSCBEP20Token.STARGATE_BUSD_LP.toString(), + "0x98a5737749490856b401db5dc27f522fc314a4e1", + "StarGate sBUSD Pool token", + 18, + TokenCategory.LIQUIDITY_PROVIDER.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/token/0x98a5737749490856b401db5dc27f522fc314a4e1"); + }}); + tokens.put(BSCBEP20Token.STARGATE_BUSD_LP.toString(), busdsglp); + + // busd + EVMERC20TokenInfo busd = new EVMERC20TokenInfo( + BSCBEP20Token.BUSD.toString(), + "0xe9e7cea3dedca5984780bafc599bd69add087d56", + "Binance stablecoin token", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/address/0xe9e7cea3dedca5984780bafc599bd69add087d56"); + this.add("https://www.coingecko.com/en/coins/binance-usd"); + }}); + tokens.put(BSCBEP20Token.BUSD.toString(), busd); + + // sfty + EVMERC20TokenInfo sfty = new EVMERC20TokenInfo( + BSCBEP20Token.SFTY.toString(), + "0xe9d6d6d7cde5c7d45927f8c37460d932e612c902", + "Stella Fantasy gaming token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/address/0xe9d6d6d7cde5c7d45927f8c37460d932e612c902"); + this.add("https://www.coingecko.com/en/coins/stella-fantasy-token"); + }}); + tokens.put(BSCBEP20Token.SFTY.toString(), sfty); + + // test + EVMERC20TokenInfo test = new EVMERC20TokenInfo( + BSCBEP20Token.TEST.toString(), + "0x1c3c3941acb8a9be35e50f086fae6a481f7d9df7", + //"0x1c3c3941acb8a9be35e50f086fae6a481f7d9df7", // SQUID token :) + "TEST token", + 18, + TokenCategory.TEST.toString(), + EVMChain.BSC.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/token/0xMOJO"); + }}); + tokens.put(BSCBEP20Token.TEST.toString(), test); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateCeloTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // cUSD + EVMERC20TokenInfo cusd = new EVMERC20TokenInfo( + CeloERC20Token.cUSD.toString(), + "0x765DE816845861e75A25fCA122bb6898B8B1282a", + "CELO USD stable token", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.CELO.toString(), + new ArrayList() {{ + this.add("https://explorer.celo.org/token/0x765DE816845861e75A25fCA122bb6898B8B1282a"); + this.add("https://www.coingecko.com/en/coins/celo-dollar"); + }}); + tokens.put(CeloERC20Token.cUSD.toString(), cusd); + + EVMERC20TokenInfo zerocasino = new EVMERC20TokenInfo( + CeloERC20Token.ZEROCASINO.toString(), + "0xbccEc3bfd4639440b1714a502bb3940F407b890A", + "0CASINO token", + 18, + TokenCategory.TEST.toString(), + EVMChain.CELO.toString(), + new ArrayList() {{ + this.add("https://explorer.celo.org/token/0xbccEc3bfd4639440b1714a502bb3940F407b890A"); + }}); + tokens.put(CeloERC20Token.ZEROCASINO.toString(), zerocasino); + + // test + /* + EVMERC20TokenInfo test = new EVMERC20TokenInfo( + CeloERC20Token.TEST.toString(), + "0xbccEc3bfd4639440b1714a502bb3940F407b890A", + "TEST token", + 18, + TokenCategory.TEST.toString(), + EVMChain.CELO.toString(), + new ArrayList() {{ + this.add("https://explorer.celo.org/token/0xMOJO"); + }}); + tokens.put(CeloERC20Token.TEST.toString(), test); + */ + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static EVMNFTIndex generateMoonbeamNFTIndex() { + HashMap erc721tokens = new HashMap<>(); + HashMap erc1155tokens = new HashMap<>(); + + // snakesoldier + EVMERC721TokenInfo snakesoldier = new EVMERC721TokenInfo( + MoonbeamERC721Token.SNAKESOLDIERS.toString(), + "0x3ab955216bdd76f51fbe02a3fe237d6612bbd09f", + 0L, + "ZKSyncEra Ape", + TokenCategory.SOCIAL.toString(), + EVMChain.MOONBEAM.toString(), + new ArrayList() {{ + this.add("https://moonscan.io/token/0x3ab955216bdd76f51fbe02a3fe237d6612bbd09f"); + this.add("https://snakesoldiers.com"); + }}); + erc721tokens.put(MoonbeamERC721Token.SNAKESOLDIERS.toString(), snakesoldier); + + + return new EVMNFTIndex(erc721tokens, erc1155tokens); + } + + @SuppressWarnings("serial") + public static EVMNFTIndex generateArbitrumNFTIndex() { + HashMap erc721tokens = new HashMap<>(); + HashMap erc1155tokens = new HashMap<>(); + + // treasuretag + EVMERC721TokenInfo treasuretag = new EVMERC721TokenInfo( + ArbitrumONEERC721Token.TREASURETAG.toString(), + "0xe50abe4756809b51b0041bb5ab12ec4c5c67af47", + 0L, + "MAGIC Treasuretag NFT", + TokenCategory.GAMING.toString(), + EVMChain.ARBITRUMONE.toString(), + new ArrayList() {{ + this.add("https://arbiscan.io/token/0xe50abe4756809b51b0041bb5ab12ec4c5c67af47"); + this.add("https://app.treasure.lol/treasuretag"); + }}); + erc721tokens.put(ArbitrumONEERC721Token.TREASURETAG.toString(), treasuretag); + + + return new EVMNFTIndex(erc721tokens, erc1155tokens); + } + + public static EVMNFTIndex generateDummyNFTIndex() { + HashMap erc721tokens = new HashMap<>(); + HashMap erc1155tokens = new HashMap<>(); + return new EVMNFTIndex(erc721tokens, erc1155tokens); + } + + public static ERC20TokenIndex generateDummyTokenIndex() { + HashMap tokens = new HashMap<>(); + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static EVMNFTIndex generateEthereumNFTIndex() { + HashMap erc721tokens = new HashMap<>(); + HashMap erc1155tokens = new HashMap<>(); + + // lucha + EVMERC721TokenInfo lucha = new EVMERC721TokenInfo( + EthereumERC721Token.LUCHADORES.toString(), + "0x8b4616926705fb61e9c4eeac07cd946a5d4b0760", + 0L, + "Luchadores game NFT", + TokenCategory.GAMING.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0x8b4616926705fb61e9c4eeac07cd946a5d4b0760"); + this.add("https://opensea.io/collection/luchadores-io"); + }}, + new ArrayList() {{ + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.LUCHA.toString()); + }}); + erc721tokens.put(EthereumERC721Token.LUCHADORES.toString(), lucha); + + // www_land + EVMERC721TokenInfo www_land = new EVMERC721TokenInfo( + EthereumERC721Token.WWW_LAND.toString(), + "0xa1d4657e0e6507d5a94d06da93e94dc7c8c44b51", + 0L, + "World Wide Webb game NFT", + TokenCategory.GAMING.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0xa1d4657e0e6507d5a94d06da93e94dc7c8c44b51"); + this.add("https://opensea.io/collection/worldwidewebbland"); + }}); + erc721tokens.put(EthereumERC721Token.WWW_LAND.toString(), www_land); + + // bored ape + EVMERC721TokenInfo bored_ape = new EVMERC721TokenInfo( + EthereumERC721Token.BORED_APE.toString(), + "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", + 0L, + "Bored Ape NFT", + TokenCategory.GAMING.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d"); + this.add("https://opensea.io/collection/boredapeyachtclub"); + }}, + new ArrayList() {{ + this.add(EVMChain.ETHEREUM.toString() + ":" + EthereumERC20Token.APECOIN.toString()); + }}); + erc721tokens.put(EthereumERC721Token.BORED_APE.toString(), bored_ape); + + // unstoppable_domain + EVMERC721TokenInfo unstoppable_domain = new EVMERC721TokenInfo( + EthereumERC721Token.UNSTOPPABLE_DOMAIN.toString(), + "0x049aba7510f45ba5b64ea9e658e342f904db358d", + 0L, + "Unstoppable Domains NFT", + TokenCategory.NAMESERVICE.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/token/0x049aba7510f45ba5b64ea9e658e342f904db358d"); + this.add("https://opensea.io/collection/unstoppable-domains"); + }}); + erc721tokens.put(EthereumERC721Token.UNSTOPPABLE_DOMAIN.toString(), unstoppable_domain); + + // ensdomain + EVMERC721TokenInfo ensdomain = new EVMERC721TokenInfo( + EthereumERC721Token.ENS_DOMAIN.toString(), + "0x57f1887a8bf19b14fc0df6fd9b2acc9af147ea85", + 0L, + "Ethereum Name Service Domain NFT", + TokenCategory.NAMESERVICE.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/token/0x57f1887a8bf19b14fc0df6fd9b2acc9af147ea85"); + this.add("https://opensea.io/collection/ens"); + }}); + erc721tokens.put(EthereumERC721Token.ENS_DOMAIN.toString(), ensdomain); + + return new EVMNFTIndex(erc721tokens, erc1155tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateEthereumTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // cult + EVMERC20TokenInfo cult = new EVMERC20TokenInfo( + EthereumERC20Token.CULT.toString(), + "0xf0f9d895aca5c8678f706fb8216fa22957685a13", + "The CULT DAO token", + 18, + TokenCategory.MEME.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0xf0f9d895aca5c8678f706fb8216fa22957685a13"); + this.add("https://www.coingecko.com/en/coins/cult-dao"); + }}); + tokens.put(EthereumERC20Token.CULT.toString(), cult); + + // dobe + EVMERC20TokenInfo dobe = new EVMERC20TokenInfo( + EthereumERC20Token.DOBE.toString(), + "0xe7ab45162f5979f09b0bda1cc7dfc97c270ea3d5", + "The Dobermann token", + 18, + TokenCategory.MEME.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0xe7ab45162f5979f09b0bda1cc7dfc97c270ea3d5"); + this.add("https://www.coingecko.com/en/coins/dobermann"); + }}); + tokens.put(EthereumERC20Token.DOBE.toString(), dobe); + + // jshiba + EVMERC20TokenInfo jshiba = new EVMERC20TokenInfo( + EthereumERC20Token.JSHIBA.toString(), + "0x1426cc6d52d1b14e2b3b1cb04d57ea42b39c4c7c", + "The Jomon Shiba token", + 18, + TokenCategory.MEME.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0x1426cc6d52d1b14e2b3b1cb04d57ea42b39c4c7c"); + this.add("https://www.coingecko.com/en/coins/jomon-shiba"); + }}); + tokens.put(EthereumERC20Token.JSHIBA.toString(), jshiba); + + // jindoge + EVMERC20TokenInfo jindoge = new EVMERC20TokenInfo( + EthereumERC20Token.JINDOGE.toString(), + "0x3f4cd830543db25254ec0f05eac058d4d6e86166", + "The Jindoge token", + 18, + TokenCategory.MEME.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0x3f4cd830543db25254ec0f05eac058d4d6e86166"); + this.add("https://www.coingecko.com/en/coins/jindoge"); + }}); + tokens.put(EthereumERC20Token.JINDOGE.toString(), jindoge); + + // nb + EVMERC20TokenInfo nb = new EVMERC20TokenInfo( + EthereumERC20Token.NB.toString(), + "0x20be82943e8d9c682580e11d424ec15db95b4a24", + "The No Bull token", + 18, + TokenCategory.MEME.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0x20be82943e8d9c682580e11d424ec15db95b4a24"); + this.add("https://www.coingecko.com/en/coins/no-bull"); + }}); + tokens.put(EthereumERC20Token.NB.toString(), nb); + + // dojo + EVMERC20TokenInfo dojo = new EVMERC20TokenInfo( + EthereumERC20Token.DOJO.toString(), + "0x180dae91d6d56235453a892d2e56a3e40ba81df8", + "The DOJO token", + 18, + TokenCategory.MEME.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0x180dae91d6d56235453a892d2e56a3e40ba81df8"); + this.add("https://www.coingecko.com/en/coins/dojo"); + }}); + tokens.put(EthereumERC20Token.DOJO.toString(), dojo); + + // shushky + EVMERC20TokenInfo shushky = new EVMERC20TokenInfo( + EthereumERC20Token.SHUSHKY.toString(), + "0x236d53148f83706c3d670064809577385f923a75", + "The Siberian Husky token", + 18, + TokenCategory.MEME.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0x236d53148f83706c3d670064809577385f923a75"); + this.add("https://www.coingecko.com/en/coins/siberian-husky"); + }}); + tokens.put(EthereumERC20Token.SHUSHKY.toString(), shushky); + + // dinu + EVMERC20TokenInfo dinu = new EVMERC20TokenInfo( + EthereumERC20Token.DINU.toString(), + "0xbb1ee07d6c7baeb702949904080eb61f5d5e7732", + "The Dogey-Inu token", + 18, + TokenCategory.MEME.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0xbb1ee07d6c7baeb702949904080eb61f5d5e7732"); + this.add("https://www.coingecko.com/en/coins/dogey-inu"); + }}); + tokens.put(EthereumERC20Token.DINU.toString(), dinu); + + // sos + EVMERC20TokenInfo sos = new EVMERC20TokenInfo( + EthereumERC20Token.SOS.toString(), + "0x3b484b82567a09e2588a13d54d032153f0c0aee0", + "The OpenDAO SOS token", + 18, + TokenCategory.NFT.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0x3b484b82567a09e2588a13d54d032153f0c0aee0"); + this.add("https://www.coingecko.com/en/coins/opendao"); + }}); + tokens.put(EthereumERC20Token.SOS.toString(), sos); + + // sora + EVMERC20TokenInfo sora = new EVMERC20TokenInfo( + EthereumERC20Token.XOR.toString(), + "0x40fd72257597aa14c7231a7b1aaa29fce868f677", + "The SORA token", + 18, + TokenCategory.UNKNOWN.toString().toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0x40fd72257597aa14c7231a7b1aaa29fce868f677"); + this.add("https://www.coingecko.com/en/coins/sora"); + }}); + tokens.put(EthereumERC20Token.XOR.toString(), sora); + + // usdc + EVMERC20TokenInfo usdc = new EVMERC20TokenInfo( + EthereumERC20Token.USDC.toString(), + "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "USDC stablecoin token", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"); + this.add("https://www.coingecko.com/en/coins/usd-coin"); + }}); + tokens.put(EthereumERC20Token.USDC.toString(), usdc); + + // fwb + EVMERC20TokenInfo fwb = new EVMERC20TokenInfo( + EthereumERC20Token.FWB.toString(), + "0x35bd01fc9d6d5d81ca9e055db88dc49aa2c699a8", + "Friends With Benefits token", + 18, + TokenCategory.SOCIAL.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0x35bd01fc9d6d5d81ca9e055db88dc49aa2c699a8"); + this.add("https://www.coingecko.com/en/coins/friends-with-benefits-pro"); + }}); + tokens.put(EthereumERC20Token.FWB.toString(), fwb); + + // vidya + EVMERC20TokenInfo vidya = new EVMERC20TokenInfo( + EthereumERC20Token.VIDYA.toString(), + "0x3d3d35bb9bec23b06ca00fe472b50e7a4c692c30", + "VIDYA token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0x3d3d35bb9bec23b06ca00fe472b50e7a4c692c30"); + this.add("https://www.coingecko.com/en/coins/vidya"); + }}); + tokens.put(EthereumERC20Token.VIDYA.toString(), vidya); + + // unidex + EVMERC20TokenInfo unidex = new EVMERC20TokenInfo( + EthereumERC20Token.UNIDX.toString(), + "0x95b3497bbcccc46a8f45f5cf54b0878b39f8d96c", + "UniDex token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0x95b3497bbcccc46a8f45f5cf54b0878b39f8d96c"); + this.add("https://www.coingecko.com/en/coins/unidex"); + }}); + tokens.put(EthereumERC20Token.UNIDX.toString(), unidex); + + // serum + EVMERC20TokenInfo serum = new EVMERC20TokenInfo( + EthereumERC20Token.SERUM.toString(), + "0x476c5e26a75bd202a9683ffd34359c0cc15be0ff", + "Serum token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0x476c5e26a75bd202a9683ffd34359c0cc15be0ff"); + this.add("https://www.coingecko.com/en/coins/serum"); + }}); + tokens.put(EthereumERC20Token.SERUM.toString(), serum); + + // trac + EVMERC20TokenInfo trac = new EVMERC20TokenInfo( + EthereumERC20Token.TRAC.toString(), + "0xaa7a9ca87d3694b5755f213b5d04094b8d0f0a6f", + "OriginTrail token", + 18, + TokenCategory.SUPPLYCHAIN.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0xaa7a9ca87d3694b5755f213b5d04094b8d0f0a6f"); + this.add("https://www.coingecko.com/en/coins/origintrail"); + }}); + tokens.put(EthereumERC20Token.TRAC.toString(), trac); + + // dai + EVMERC20TokenInfo dai = new EVMERC20TokenInfo( + EthereumERC20Token.DAI.toString(), + "0x6b175474e89094c44da98b954eedeac495271d0f", + "DAI stablecoin token", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0x6b175474e89094c44da98b954eedeac495271d0f"); + this.add("https://www.coingecko.com/en/coins/dai"); + }}); + tokens.put(EthereumERC20Token.DAI.toString(), dai); + + // usdt + EVMERC20TokenInfo usdt = new EVMERC20TokenInfo( + EthereumERC20Token.USDT.toString(), + "0xdac17f958d2ee523a2206206994597c13d831ec7", + "Tether stablecoin token", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7"); + this.add("https://www.coingecko.com/en/coins/tether"); + }}); + tokens.put(EthereumERC20Token.USDT.toString(), usdt); + + // apecoin + EVMERC20TokenInfo apecoin = new EVMERC20TokenInfo( + EthereumERC20Token.APECOIN.toString(), + "0x4d224452801aced8b2f0aebe155379bb5d594381", + "Bored Ape game token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://www.coingecko.com/en/coins/apecoin"); + this.add("https://etherscan.io/address/0x4d224452801aced8b2f0aebe155379bb5d594381"); + }}); + tokens.put(EthereumERC20Token.APECOIN.toString(), apecoin); + + // test + EVMERC20TokenInfo test = new EVMERC20TokenInfo( + EthereumERC20Token.TEST.toString(), + "0x2b591e99afe9f32eaa6214f7b7629768c40eeb39", + //"0x2b591e99afe9f32eaa6214f7b7629768c40eeb39", // HEX :) + "TEST token", + 18, + TokenCategory.TEST.toString(), + EVMChain.ETHEREUM.toString(), + new ArrayList() {{ + this.add("https://etherscan.io/token/0xMOJO"); + }}); + tokens.put(EthereumERC20Token.TEST.toString(), test); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static EVMChainIndex generateEVMChainIndex() { + + HashMap networks = new HashMap<>(); + + // lamina1_betanet + EVMChainInfo lamina1_betanet = new EVMChainInfo( + EVMChain.LAMINA1BETATEST.toString(), + "Lamina1 Betanet", + 7649L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Lamina1 Gas Token", "L1", 18), + EVMPriceMechanism.EIP1559.toString(), + "1000000000", //1 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://rpc-betanet.lamina1.com/ext/bc/C/rpc"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://explorer.lamina1.com"); + }}, + new ArrayList() {{ + this.add(""); + }}, + new ArrayList() {{ + this.add("https://www.mantle.xyz/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.LAMINA1BETATEST, lamina1_betanet); + + // mantle + EVMChainInfo mantle = new EVMChainInfo( + EVMChain.MANTLE.toString(), + "Mantle Mainnet", + 5000L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Mantle Gas Token", "MNT", 18), + EVMPriceMechanism.EIP1559.toString(), + "1000000000", //1 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://rpc.mantle.xyz"); + this.add("https://mantle.publicnode.com"); + this.add("https://mantle-mainnet.public.blastapi.io"); + this.add("https://mantle.drpc.org"); + this.add("https://rpc.ankr.com/mantle"); + this.add("https://1rpc.io/mantle"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://explorer.mantle.xyz"); + }}, + new ArrayList() {{ + this.add("https://bridge.mantle.xyz/"); + }}, + new ArrayList() {{ + this.add("https://www.mantle.xyz/"); + }}, + generateMantleTokenIndex(), + generateMantleNFTIndex()); + networks.put(EVMChain.MANTLE, mantle); + + // mantle_testnet + EVMChainInfo mantletest = new EVMChainInfo( + EVMChain.MANTLETEST.toString(), + "Mantle Testnet", + 5001L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Mantle Gas Token", "MNT", 18), + EVMPriceMechanism.EIP1559.toString(), + "1000000000", //1 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://rpc.testnet.mantle.xyz"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://explorer.testnet.mantle.xyz"); + }}, + new ArrayList() {{ + this.add("https://faucet.testnet.mantle.xyz"); + this.add("https://bridge.testnet.mantle.xyz"); + this.add("https://goerli.etherscan.io/address/0xc1dc2d65a2243c22344e725677a3e3bebd26e604#writeProxyContract mint()"); + }}, + new ArrayList() {{ + this.add("https://www.mantle.xyz/"); + }}, + generateMantleTestnetTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.MANTLETEST, mantletest); + + // opbnb + EVMChainInfo opbnb = new EVMChainInfo( + EVMChain.OPBNB.toString(), + "opBNB Mainnet", + 204L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("opBNB Gas Token", "BNB", 18), + EVMPriceMechanism.EIP1559.toString(), + "1000000000", //1 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://opbnb.publicnode.com"); + this.add("https://opbnb-mainnet.nodereal.io/v1/64a9df0874fb4a93b9d0a3849de012d3"); + this.add("https://opbnb-mainnet-rpc.bnbchain.org"); + this.add("https://opbnb-mainnet.nodereal.io/v1/e9a36765eb8a40b9bd12e680a1fd2bc5"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://mainnet.opbnbscan.com"); + }}, + new ArrayList() {{ + this.add("https://opbnb-bridge.bnbchain.org/deposit"); + }}, + new ArrayList() {{ + this.add("https://opbnb.bnbchain.org"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.OPBNB, opbnb); + + // opbnb_test + EVMChainInfo opbnb_test = new EVMChainInfo( + EVMChain.OPBNBTEST.toString(), + "opBNB Testnet", + 5611L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("opBNB Gas Token", "tBNB", 18), + EVMPriceMechanism.EIP1559.toString(), + "1000000000", //1 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://opbnb-testnet-rpc.bnbchain.org"); + this.add("https://opbnb-testnet.nodereal.io/v1/64a9df0874fb4a93b9d0a3849de012d3"); + this.add("https://opbnb-testnet.nodereal.io/v1/e9a36765eb8a40b9bd12e680a1fd2bc5"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://testnet.opbnbscan.com"); + }}, + new ArrayList() {{ + this.add("https://opbnb-testnet-bridge.bnbchain.org/deposit"); + }}, + new ArrayList() {{ + this.add("https://opbnb.bnbchain.org"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.OPBNBTEST, opbnb_test); + + // zora + EVMChainInfo zora = new EVMChainInfo( + EVMChain.ZORA.toString(), + "Zora Mainnet", + 7777777L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Zora Gas Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://rpc.zora.energy"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://explorer.zora.energy"); + }}, + new ArrayList() {{ + this.add("https://bridge.zora.energy/"); + }}, + new ArrayList() {{ + this.add("https://zora.energy"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.ZORA, zora); + + // zora goerli + EVMChainInfo zoratest = new EVMChainInfo( + EVMChain.ZORATEST.toString(), + "Zora Goerli Testnet", + 999L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Zora Testnet Gas Token", "GöETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://testnet.rpc.zora.co"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://testnet.explorer.zora.co"); + this.add("https://goerli.etherscan.io/address/0xDb9F51790365e7dc196e7D072728df39Be958ACe"); + }}, + new ArrayList() {{ + this.add("https://bridgetozora.world/"); + }}, + new ArrayList() {{ + this.add("https://zora.energy"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.ZORATEST, zoratest); + + // tomochain + EVMChainInfo tomochain = new EVMChainInfo( + EVMChain.TOMOCHAIN.toString(), + "Tomochain Mainnet", + 88L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Tomo Gas Token", "TOMO", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://rpc.tomochain.com"); + this.add("https://tomo.blockpi.network/v1/rpc/public"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://tomoscan.io"); + }}, + new ArrayList() {{ + this.add(""); + }}, + new ArrayList() {{ + this.add("https://tomochain.com"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.TOMOCHAIN, tomochain); + + // tomochain_test + EVMChainInfo tomochain_test = new EVMChainInfo( + EVMChain.TOMOCHAINTEST.toString(), + "Tomochain Mainnet", + 89L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Tomo Gas Token", "TOMO", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://rpc.testnet.tomochain.com"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://scan.testnet.tomochain.com"); + }}, + new ArrayList() {{ + this.add(""); + }}, + new ArrayList() {{ + this.add("https://tomochain.com"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.TOMOCHAINTEST, tomochain_test); + + // tenet + EVMChainInfo tenet = new EVMChainInfo( + EVMChain.TENET.toString(), + "Tenet Mainnet", + 1559L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("TENET Gas Token", "TENET", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://rpc.tenet.org"); + this.add("https://tenet-evm.publicnode.com"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://tenetscan.io"); + }}, + new ArrayList() {{ + this.add(""); + }}, + new ArrayList() {{ + this.add("https://ethereumpow.org/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.TENET, tenet); + + // tenettest + EVMChainInfo tenettest = new EVMChainInfo( + EVMChain.TENETTEST.toString(), + "Tenet Testnet", + 155L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("TENET Gas Token", "TENET", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://rpc.testnet.tenet.org"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://testnet.tenetscan.io"); + }}, + new ArrayList() {{ + this.add("https://faucet.testnet.tenet.org/"); + }}, + new ArrayList() {{ + this.add("https://tenet.org"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.TENETTEST, tenettest); + + // ethhw + EVMChainInfo ethw = new EVMChainInfo( + EVMChain.ETHW.toString(), + "ETH PoW Mainnet", + 10001L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("ETHW Gas Token", "ETHW", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://mainnet.ethereumpow.org"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://mainnet.ethwscan.com/"); + }}, + new ArrayList() {{ + this.add(""); + }}, + new ArrayList() {{ + this.add("https://ethereumpow.org/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.ETHW, ethw); + + // kardiachain + EVMChainInfo kardiachain = new EVMChainInfo( + EVMChain.KARDIACHAIN.toString(), + "KARURA Mainnet", + 24L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("KARDIACHAIN Gas Token", "KAI", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://rpc.kardiachain.io"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://explorer.kardiachain.io/"); + }}, + new ArrayList() {{ + this.add(""); + }}, + new ArrayList() {{ + this.add("https://kardiachain.io/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.KARDIACHAIN, kardiachain); + + // karura_test + EVMChainInfo karura_test = new EVMChainInfo( + EVMChain.KARURATEST.toString(), + "KARURA Testnet", + 596L, + BlockchainType.BORKED.toString(), // no rpcs + new EVMCurrency("KARURA Test Token", "KAR", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://eth-rpc-karura-testnet.aca-staging.network"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("todo block explorer"); + }}, + new ArrayList() {{ + this.add("todo faucet"); + }}, + new ArrayList() {{ + this.add("https://acala.network/karura"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.KARURATEST, karura_test); + + // karura + EVMChainInfo karura = new EVMChainInfo( + EVMChain.KARURA.toString(), + "KARURA Mainnet", + 686L, + BlockchainType.BORKED.toString(), // rpc incomp? issue calling ethGetBalance() + new EVMCurrency("KARURA Gas Token", "KAR", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://rpc.evm.karura.network"); + this.add("https://eth-rpc-karura.aca-api.network"); + this.add("https://eth-rpc-karura.aca-staging.network"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://karura.network"); + }}, + new ArrayList() {{ + this.add(""); + }}, + new ArrayList() {{ + this.add("https://acala.network/karura"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.KARURA, karura); + + // lukso_test + EVMChainInfo lukso_test = new EVMChainInfo( + EVMChain.LUKSOTEST.toString(), + "LUKSO Testnet", + 4201L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("LUKSO Test Token", "LYXt", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://rpc.testnet.lukso.network"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://explorer.execution.testnet.lukso.network"); + }}, + new ArrayList() {{ + this.add("https://faucet.testnet.lukso.network/"); + }}, + new ArrayList() {{ + this.add("https://lukso.network/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.LUKSOTEST, lukso_test); + + // lukso + EVMChainInfo lukso = new EVMChainInfo( + EVMChain.LUKSO.toString(), + "LUKSO Mainnet", + 42L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("LUKSO Gas Token", "LYX", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://rpc.mainnet.lukso.network"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://explorer.execution.mainnet.lukso.network"); + }}, + new ArrayList() {{ + this.add(""); + }}, + new ArrayList() {{ + this.add("https://lukso.network/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.LUKSO, lukso); + + // fuse_test + EVMChainInfo fuse_test = new EVMChainInfo( + EVMChain.FUSESPARKTEST.toString(), + "FUSE Spark Testnet", + 123L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("FUSE Test Token", "FUSE", 18), + EVMPriceMechanism.EIP1559.toString(), + "10000000000", //10 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://rpc.fusespark.io"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://explorer.fusespark.io"); + }}, + new ArrayList() {{ + this.add("https://get.fusespark.io/"); + }}, + new ArrayList() {{ + this.add("https://www.fuse.io/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.FUSESPARKTEST, fuse_test); + + // fuse + EVMChainInfo fuse = new EVMChainInfo( + EVMChain.FUSE.toString(), + "FUSE Mainnet", + 122L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("FUSE Gas Token", "FUSE", 18), + EVMPriceMechanism.EIP1559.toString(), + "10000000000", //10 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://fuse-mainnet.chainstacklabs.com"); + this.add("https://rpc.fuse.io"); + this.add("https://fuse-rpc.gateway.pokt.network"); + this.add("https://fuse.api.onfinality.io/public"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://explorer.fuse.io/"); + }}, + new ArrayList() {{ + this.add(""); + }}, + new ArrayList() {{ + this.add("https://www.fuse.io/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.FUSE, fuse); + + // coredao_test + EVMChainInfo coredao_test = new EVMChainInfo( + EVMChain.CORETEST.toString(), + "Core DAO Testnet", + 1115L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Core Test Token", "tCORE", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://rpc.test.btcs.network"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://scan.test.btcs.network"); + }}, + new ArrayList() {{ + this.add("https://bridge.coredao.org/"); + }}, + new ArrayList() {{ + this.add("https://coredao.org/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.CORETEST, coredao_test); + + // coredao + EVMChainInfo coredao = new EVMChainInfo( + EVMChain.CORE.toString(), + "Core DAO Mainnet", + 1116L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Core Gas Token", "CORE", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://rpc.coredao.org"); + this.add("https://rpc-core.icecreamswap.com"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://scan.coredao.org"); + }}, + new ArrayList() {{ + this.add("https://bridge.coredao.org/"); + }}, + new ArrayList() {{ + this.add("https://coredao.org/"); + }}, + generateCoreTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.CORE, coredao); + + // optimism + EVMChainInfo optimism = new EVMChainInfo( + EVMChain.OPTIMISM.toString(), + "Optimism Mainnet", + 10L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Optimism Gas Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://mainnet.optimism.io"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://optimistic.etherscan.io"); + }}, + new ArrayList() {{ + this.add(""); + }}, + new ArrayList() {{ + this.add("https://www.optimism.io/"); + this.add("https://chainid.link/?network=optimism"); + }}, + generateOptimismTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.OPTIMISM, optimism); + + // optimism_goerli_test + EVMChainInfo optimism_goerli_test = new EVMChainInfo( + EVMChain.OPTIMISMGOERLITEST.toString(), + "Optimism Goerli Testnet", + 420L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Optimism Gas Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://endpoints.omniatech.io/v1/op/goerli/public"); + this.add("https://opt-goerli.g.alchemy.com/v2/demo"); + this.add("https://goerli.optimism.io"); + this.add("https://optimism-goerli.public.blastapi.io"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://optimistic.etherscan.io/"); + }}, + new ArrayList() {{ + this.add("https://goerli.hop.exchange/"); + }}, + new ArrayList() {{ + this.add("https://www.optimism.io/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.OPTIMISMGOERLITEST, optimism_goerli_test); + + // mode_test + EVMChainInfo mode_test = new EVMChainInfo( + EVMChain.MODETEST.toString(), + "MODE Testnet", + 919L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Mode Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://sepolia.mode.network"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://sepolia.explorer.mode.network"); + }}, + new ArrayList() {{ + this.add("https://www.mode.network"); + }}, + new ArrayList() {{ + this.add("https://confluxnetwork.org/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.MODETEST, mode_test); + + // conflux_test + EVMChainInfo conflux_test = new EVMChainInfo( + EVMChain.CONFLUXTEST.toString(), + "Conflux Testnet", + 71L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Conflux Token", "CFX", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://evmtestnet.confluxrpc.com"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://evmtestnet.confluxscan.net"); + }}, + new ArrayList() {{ + this.add("https://efaucet.confluxnetwork.org/"); + }}, + new ArrayList() {{ + this.add("https://confluxnetwork.org/"); + }}, + generateConfluxTestnetTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.CONFLUXTEST, conflux_test); + + // conflux + EVMChainInfo conflux = new EVMChainInfo( + EVMChain.CONFLUX.toString(), + "Conflux eSpace", + 1030L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Conflux Token", "CFX", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://evm.confluxrpc.com"); + this.add("https://conflux-espace-public.unifra.io"); // quickly gives 429 rate limit .. + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://evm.confluxscan.net"); + this.add("https://conflux-espace-public.unifra.io"); + }}, + new ArrayList() {{ + this.add("faucet todo"); + }}, + new ArrayList() {{ + this.add("https://confluxnetwork.org/"); + }}, + generateConfluxTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.CONFLUX, conflux); + + // zetachain_athens_testnet + EVMChainInfo zetachain_athens_testnet = new EVMChainInfo( + EVMChain.ZETAATHENSTEST.toString(), + "ZetaChain Athens Testnet", + 7001L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Zetachain Testnet Token", "aZETA", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://zetachain-athens-evm.blockpi.network/v1/rpc/public"); + // https://www.zetachain.com/docs/reference/api/ + this.add("https://rpc.ankr.com/zetachain_evm_testnet"); + //this.add("https://api.athens2.zetachain.com/evm"); // gives incorrect nonce quite often + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://explorer.athens.zetachain.com"); + }}, + new ArrayList() {{ + this.add("https://labs.zetachain.com/get-zeta"); + }}, + new ArrayList() {{ + this.add("https://www.zetachain.com/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.ZETAATHENSTEST, zetachain_athens_testnet); + + // kava + EVMChainInfo kava = new EVMChainInfo( + EVMChain.KAVA.toString(), + "KAVA Evm Mainnet", + 2222L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("KAVA Token", "KAVA", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://evm2.kava.io"); + this.add("https://evm.kava.io"); + this.add("https://kava-rpc.gateway.pokt.network"); + this.add("https://evm.kava.chainstacklabs.com"); + this.add("https://kava-evm.publicnode.com"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://explorer.kava.io/"); + }}, + new ArrayList() {{ + this.add("faucet-todo"); + }}, + new ArrayList() {{ + this.add("https://kava.io"); + this.add("https://docs.kava.io/docs/ethereum/metamask/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.KAVA, kava); + + // kavatest + EVMChainInfo kavatest = new EVMChainInfo( + EVMChain.KAVATEST.toString(), + "KAVA Evm Testnet", + 2221L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("KAVA Testnet Token", "KAVA", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "30000", //only give enough to enable transfers .. gas limit too low: 21000 (gas limit) < 21596 (intrinsic gas): out of gas:gas limit too low: 21000 (gas limit) < 21596 (intrinsic gas): out of gas:gas limit too low: 21000 (gas limit) < 21596 (intrinsic gas): out of gas: + new ArrayList() {{ + this.add("https://evm.testnet.kava.io"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://explorer.testnet.kava.io"); + }}, + new ArrayList() {{ + this.add("https://faucet.kava.io/"); + }}, + new ArrayList() {{ + this.add("https://kava.io"); + this.add("https://docs.kava.io/docs/ethereum/metamask/"); + }}, + generateKavaTestTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.KAVATEST, kavatest); + + // scroll_alphatest + EVMChainInfo scroll_alphatest = new EVMChainInfo( + EVMChain.SCROLLALPHATEST.toString(), + "Scroll Alpha Testnet", + 534353L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Scroll Alpha Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://alpha-rpc.scroll.io/l2"); + this.add("https://scroll-alphanet.public.blastapi.io"); + this.add("https://scroll-testnet.blockpi.network/v1/rpc/public"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://blockscout.scroll.io"); + }}, + new ArrayList() {{ + this.add("https://scroll.io/alpha/bridge"); + }}, + new ArrayList() {{ + this.add("https://scroll.io"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.SCROLLALPHATEST, scroll_alphatest); + + // scroll + EVMChainInfo scroll = new EVMChainInfo( + EVMChain.SCROLL.toString(), + "Scroll Mainnet", + 534352L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Scroll Test Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://scroll.blockpi.network/v1/rpc/public"); + this.add("https://rpc-scroll.icecreamswap.com"); + this.add("https://rpc.scroll.io"); + this.add("https://1rpc.io/scroll"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://blockscout.scroll.io"); + }}, + new ArrayList() {{ + this.add("https://scroll.io/bridge"); + }}, + new ArrayList() {{ + this.add("https://scroll.io"); + }}, + generateScrollTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.SCROLL, scroll); + + // scroll_sepoliatest + EVMChainInfo scroll_sepoliatest = new EVMChainInfo( + EVMChain.SCROLLSEPOLIATEST.toString(), + "Scroll Sepolia Testnet", + 534351L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Scroll Testnet Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://scroll-sepolia.blockpi.network/v1/rpc/public"); + this.add("https://sepolia-rpc.scroll.io"); + this.add("https://scroll-public.scroll-testnet.quiknode.pro"); + this.add("https://rpc.ankr.com/scroll_sepolia_testnet"); + this.add("https://scroll-testnet-public.unifra.io"); + this.add("https://1rpc.io/scroll/sepolia"); + this.add("https://scroll-sepolia.chainstacklabs.com"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://sepolia.scrollscan.dev"); + }}, + new ArrayList() {{ + this.add("https://sepolia.scroll.io/bridge"); + }}, + new ArrayList() {{ + this.add("https://scroll.io"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.SCROLLSEPOLIATEST, scroll_sepoliatest); + + // linea + EVMChainInfo linea = new EVMChainInfo( + EVMChain.LINEA.toString(), + "Linea Mainnet", + 59144L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Linea Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "1600000000", //1.6 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://rpc.linea.build/"); + this.add("https://linea.drpc.org"); + this.add("https://linea.blockpi.network/v1/rpc/public"); + this.add("https://1rpc.io/linea"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://lineascan.build"); + }}, + new ArrayList() {{ + this.add("faucet-todo"); + }}, + new ArrayList() {{ + this.add("https://linea.build/"); + }}, + generateLineaTokenIndex(), + generateLineaNFTIndex()); + networks.put(EVMChain.LINEA, linea); + + // linea_test + EVMChainInfo linea_test = new EVMChainInfo( + EVMChain.LINEATEST.toString(), + "Linea Testnet", + 59140L, + BlockchainType.BORKED.toString(), + new EVMCurrency("Linea Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "1600000000", //1.6 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. + new ArrayList() {{ + this.add("https://rpc.goerli.linea.build"); // only one, unstable + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://explorer.goerli.linea.build"); + }}, + new ArrayList() {{ + this.add("faucet-todo"); + }}, + new ArrayList() {{ + this.add("https://linea.build/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.LINEATEST, linea_test); + + // pulsechain + EVMChainInfo pulsechain = new EVMChainInfo( + EVMChain.PULSECHAIN.toString(), + "PulseChain", + 369L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("PulseChain Token", "PLS", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. crazy usage atm + new ArrayList() {{ + this.add("https://rpc.pulsechain.com"); + this.add("https://rpc-pulsechain.g4mm4.io"); + this.add("https://pulsechain.publicnode.com"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://scan.pulsechain.com"); + }}, + new ArrayList() {{ + this.add("faucet-todo"); + }}, + new ArrayList() {{ + this.add("https://pulsechain.com/"); + }}, + generatePulsechainTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.PULSECHAIN, pulsechain); + + // satoshichain + EVMChainInfo satoshichain = new EVMChainInfo( + EVMChain.SATOSHICHAIN.toString(), + "SatoshiChain Mainnet", + 12009L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("SATS Token", "SATS", 18), + EVMPriceMechanism.EIP1559.toString(), + "550030000000000", //550030 gwei, recommended 550k+ gwei default? + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. crazy usage atm + new ArrayList() {{ + this.add("https://mainnet-rpc.satoshichain.io"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://satoshiscan.io"); + }}, + new ArrayList() {{ + this.add("https://faucet.satoshichain.io/"); + }}, + new ArrayList() {{ + this.add("https://satoshix.io/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.SATOSHICHAIN, satoshichain); + + // satoshichaintest + EVMChainInfo satoshichaintest = new EVMChainInfo( + EVMChain.SATOSHICHAINTEST.toString(), + "SatoshiChain Testnet", + 5758L, + BlockchainType.PUBLIC.toString(), // not ready + new EVMCurrency("SATS Token", "SATS", 18), + EVMPriceMechanism.EIP1559.toString(), + "550030000000000", //550030 gwei, recommended 550k+ gwei default? + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. crazy usage atm + new ArrayList() {{ + this.add("https://testnet-rpc.satoshichain.io/"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://satoshiscan.io"); + }}, + new ArrayList() {{ + this.add("https://faucet.satoshichain.io/"); + }}, + new ArrayList() {{ + this.add("https://satoshix.io/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.SATOSHICHAINTEST, satoshichaintest); + + // zkevm + EVMChainInfo zkevm = new EVMChainInfo( + EVMChain.ZKEVM.toString(), + "Polygon ZKEVM Network", + 1101L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("ETH Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://zkevm-rpc.com"); + this.add("https://rpc.polygon-zkevm.gateway.fm"); + this.add("https://rpc.ankr.com/polygon_zkevm"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://zkevm.polygonscan.com/"); + }}, + new ArrayList() {{ + this.add("https://bridge.zkevm-rpc.com/"); + }}, + new ArrayList() {{ + this.add("https://wiki.polygon.technology/docs/zkEVM/develop"); + }}, + generateZKEVMTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.ZKEVM, zkevm); + + // zkevmtest + EVMChainInfo zkevmtest = new EVMChainInfo( + EVMChain.ZKEVMTEST.toString(), + "Polygon ZKEVM Test Network", + 1442L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("ETH Test Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://rpc.public.zkevm-test.net"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://testnet-zkevm.polygonscan.com"); + }}, + new ArrayList() {{ + this.add("https://wallet.polygon.technology/zkEVM-Bridge/bridge"); + }}, + new ArrayList() {{ + this.add("https://wiki.polygon.technology/docs/zkEVM/develop"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.ZKEVMTEST, zkevmtest); + + // ethotest + EVMChainInfo ethotest = new EVMChainInfo( + EVMChain.ETHOTEST.toString(), + "ETHO HC Test Network", + 27292L, + BlockchainType.PUBLIC.toString(), // not ready + new EVMCurrency("ETHOTest Token", "ETHO", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://testnetrpc.ethoprotocol.com/"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://testnetexplorer.ethoprotocol.com/"); + }}, + new ArrayList() {{ + this.add(""); + }}, + new ArrayList() {{ + this.add("https://docs.ethoprotocol.com/install-metamask"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.ETHOTEST, ethotest); + + // basetest + EVMChainInfo basetest = new EVMChainInfo( + EVMChain.BASETEST.toString(), + "Base Goerli Test Network", + 84531L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Base Goerli Test Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://goerli.base.org"); + this.add("https://base-goerli.public.blastapi.io"); + this.add("https://base-goerli.diamondswap.org/rpc"); + this.add("https://1rpc.io/base-goerli"); + this.add("https://base-goerli.publicnode.com"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://goerli.basescan.org"); + }}, + new ArrayList() {{ + this.add("https://bridge.base.org/"); + }}, + new ArrayList() {{ + this.add("https://base.org/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.BASETEST, basetest); + + // oasissapphiretest + EVMChainInfo oasissapphiretest = new EVMChainInfo( + EVMChain.OASISSAPPHIRETEST.toString(), + "Oasis Sapphire Test Network", + 23295L, + BlockchainType.BORKED.toString(), // not ready + new EVMCurrency("Oasis Test Token", "TEST", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://testnet.sapphire.oasis.dev"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://explorer.sapphire.oasis.io/"); + }}, + new ArrayList() {{ + this.add("https://faucet.testnet.oasis.dev/"); + }}, + new ArrayList() {{ + this.add("https://oasisprotocol.org/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.OASISSAPPHIRETEST, oasissapphiretest); + + // oasisemerald + EVMChainInfo oasisemeraldtest = new EVMChainInfo( + EVMChain.OASISEMERALDTEST.toString(), + "Oasis Emerald Test Network", + 42261L, + BlockchainType.BORKED.toString(), // testnet.emerald.oasis.dev often unavailable + new EVMCurrency("Oasis Test Token", "TEST", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://testnet.emerald.oasis.dev"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://explorer.emerald.oasis.dev/"); + }}, + new ArrayList() {{ + this.add("https://faucet.testnet.oasis.dev/"); + }}, + new ArrayList() {{ + this.add("https://oasisprotocol.org/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.OASISEMERALDTEST, oasisemeraldtest); + + // oasissapphire + EVMChainInfo oasissapphire = new EVMChainInfo( + EVMChain.OASISSAPPHIRE.toString(), + "Oasis Sapphire Network", + 23294L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Oasis Token", "ROSE", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://sapphire.oasis.io"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://explorer.sapphire.oasis.io/"); + }}, + new ArrayList() {{ + this.add("faucet-todo"); + }}, + new ArrayList() {{ + this.add("https://oasisprotocol.org/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.OASISSAPPHIRE, oasissapphire); + + // oasisemerald + EVMChainInfo oasisemerald = new EVMChainInfo( + EVMChain.OASISEMERALD.toString(), + "Oasis Emerald Network", + 42262L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Oasis Token", "ROSE", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://emerald.oasis.dev"); + this.add("https://1rpc.io/oasis/emerald"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://explorer.emerald.oasis.dev/"); + }}, + new ArrayList() {{ + this.add("faucet-todo"); + }}, + new ArrayList() {{ + this.add("https://oasisprotocol.org/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.OASISEMERALD, oasisemerald); + + // oasischain + EVMChainInfo oasischain = new EVMChainInfo( + EVMChain.OASISCHAIN.toString(), + "Oasis Chain", + 26863L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Oasis Token", "OAC", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://rpc1.oasischain.io"); + this.add("https://rpc2.oasischain.io"); + this.add("https://rpc3.oasischain.io"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://scan.oasischain.io/"); + }}, + new ArrayList() {{ + this.add("faucet-todo"); + }}, + new ArrayList() {{ + this.add("https://oasischain.io/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.OASISCHAIN, oasischain); + + // canto + EVMChainInfo canto = new EVMChainInfo( + EVMChain.CANTO.toString(), + "Canto Network", + 7700L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Canto Token", "CANTO", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://canto.gravitychain.io"); + this.add("https://canto.slingshot.finance/"); + this.add("https://canto.evm.chandrastation.com/"); + this.add("https://jsonrpc.canto.nodestake.top"); + + //this.add("https://canto.neobase.one/"); // dead + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://tuber.build/"); + }}, + new ArrayList() {{ + this.add("faucet-todo"); + }}, + new ArrayList() {{ + this.add("https://docs.canto.io/user-guides/connecting-to-canto"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.CANTO, canto); + + // cantotest + EVMChainInfo cantotest = new EVMChainInfo( + EVMChain.CANTOTEST.toString(), + "Canto Test Network", + 740L, + BlockchainType.BORKED.toString(), // single rpc node is down + new EVMCurrency("Canto Test Token", "CANTO", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "21000", //only give enough to enable transfers .. crazy usage atm + new ArrayList() {{ + this.add("https://eth.plexnode.wtf"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://testnet-explorer.canto.neobase.one/"); + }}, + new ArrayList() {{ + this.add("https://discord.com/invite/canto, social-faucet channel"); + }}, + new ArrayList() {{ + this.add("https://docs.canto.io/user-guides/connecting-to-canto"); + this.add("https://chainlist.org/chain/740"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.CANTOTEST, cantotest); + + // taikotest_alpha2 + EVMChainInfo taikotest_alpha2 = new EVMChainInfo( + EVMChain.TAIKOALPHA2TEST.toString(), + "Taiko Ethereum A2 Test Network", + 167004L, + BlockchainType.BORKED.toString(), // now alpha3 + new EVMCurrency("Taiko A2 Test Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://rpc.a2.taiko.xyz"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://explorer.a2.taiko.xyz"); + }}, + new ArrayList() {{ + this.add("https://bridge.test.taiko.xyz/"); + }}, + new ArrayList() {{ + this.add("https://taiko.xyz"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.TAIKOALPHA2TEST, taikotest_alpha2); + + // taikotest_alpha3 + EVMChainInfo taikotest_alpha3 = new EVMChainInfo( + EVMChain.TAIKOALPHA3TEST.toString(), + "Taiko Ethereum A3 Test Network", + 167005L, + BlockchainType.BORKED.toString(), + new EVMCurrency("Taiko A3 Test Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://rpc.test.taiko.xyz"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://explorer.test.taiko.xyz"); + }}, + new ArrayList() {{ + this.add("https://bridge.test.taiko.xyz/"); + }}, + new ArrayList() {{ + this.add("https://taiko.xyz"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.TAIKOALPHA3TEST, taikotest_alpha3); + + // taikotest_alpha + EVMChainInfo taikotest_alpha = new EVMChainInfo( + EVMChain.TAIKOALPHATEST.toString(), + "Taiko Ethereum A1 Test Network", + 167003L, + BlockchainType.BORKED.toString(), // endpoints/explorers from docs no longer resolve + new EVMCurrency("Taiko A1 Test Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://l2rpc.a1.taiko.xyz"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://l2explorer.a1.taiko.xyz"); + }}, + new ArrayList() {{ + this.add("https://l2faucet.a1.taiko.xyz/"); + }}, + new ArrayList() {{ + this.add("https://taiko.xyz/docs/alpha-1-testnet/configure-wallet"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.TAIKOALPHATEST, taikotest_alpha); + + // syscoin + EVMChainInfo syscoin = new EVMChainInfo( + EVMChain.SYSCOIN.toString(), + "SYSCoin Mainnet", + 57L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("SYS", "SYS", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://rpc.syscoin.org"); + this.add("https://syscoin-evm.publicnode.com"); + this.add("https://rpc.ankr.com/syscoin"); + this.add("https://syscoin.public-rpc.com"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://explorer.syscoin.org"); + }}, + new ArrayList() {{ + this.add("https://faucet.syscoin.org/"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/57"); + this.add("https://syscoin.medium.com/setting-up-metamask-for-syscoin-nevm-ea0012d6d1c8"); + this.add("https://www.coingecko.com/en/coins/syscoin"); + this.add("https://bridge.syscoin.org"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.SYSCOIN, syscoin); + + // milkomediaC1 + EVMChainInfo milkomedaC1 = new EVMChainInfo( + EVMChain.MILKOMEDAC1.toString(), + "Milkomeda Cardano mainnet", + 2001L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("milkADA", "mADA", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://rpc-mainnet-cardano-evm.c1.milkomeda.com"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://explorer-mainnet-cardano-evm.c1.milkomeda.com/"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/2001"); + this.add("https://app.blueshift.fi/#/bridge"); + }}, + generateMilkomedaC1TokenIndex(), + generateMilkomedaC1NFTIndex()); + networks.put(EVMChain.MILKOMEDAC1, milkomedaC1); + + // milkomediaA1 + EVMChainInfo milkomediaA1 = new EVMChainInfo( + EVMChain.MILKOMEDAA1.toString(), + "Milkomeda Algorand mainnet", + 2002L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("milkALGO", "milkALGO", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://rpc-mainnet-algorand-rollup.a1.milkomeda.com"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://explorer-mainnet-algorand-rollup.a1.milkomeda.com"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/2002"); + this.add("https://dcspark.github.io/milkomeda-documentation/algorand/for-end-users/configuring-metamask/"); + this.add("https://algorand-bridge.milkomeda.com/mainnet"); + }}, + generateMilkomedaA1TokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.MILKOMEDAA1, milkomediaA1); + + // milkomediatestA1 + EVMChainInfo milkomediatestA1 = new EVMChainInfo( + EVMChain.MILKOMEDAA1TEST.toString(), + "Milkomeda Algorand testnet", + 200202L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("milkTALGO", "milkTALGO", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://rpc-devnet-algorand-rollup.a1.milkomeda.com"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://testnet-algorand-rollup.a1.milkomeda.com"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/200202"); + this.add("https://dcspark.github.io/milkomeda-documentation/algorand/for-end-users/configuring-metamask/"); + this.add("https://algorand-bridge.milkomeda.com/devnet/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.MILKOMEDAA1TEST, milkomediatestA1); + + // wemix + EVMChainInfo wemix = new EVMChainInfo( + EVMChain.WEMIX.toString(), + "WEMIX mainnet", + 1111L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("WEMIX", "WEMIX", 18), + EVMPriceMechanism.EIP1559.toString(), + "101000000000", //101 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://api.wemix.com/"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://explorer.wemix.com"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/1111"); + this.add("https://medium.com/wemix-communication/metamask-wemix3-0-mainnet-setting-guide-1a249fcaf866"); + }}, + generateWemixTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.WEMIX, wemix); + + // arbitrum one + EVMChainInfo arbitrum_one = new EVMChainInfo( + EVMChain.ARBITRUMONE.toString(), + "Arbitrum ONE mainnet", + 42161L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("ETH", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://arb1.arbitrum.io/rpc"); + this.add("https://arbitrum.llamarpc.com"); + this.add("https://arbitrum.drpc.org"); + this.add("https://arbitrum-one.publicnode.com"); + this.add("https://arbitrum-one.public.blastapi.io"); + this.add("https://rpc.arb1.arbitrum.gateway.fm"); + this.add("https://1rpc.io/arb"); + this.add("https://rpc.ankr.com/arbitrum"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://arb1.arbitrum.io/rpc"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/42161"); + }}, + generateArbitrumONETokenIndex(), + generateArbitrumNFTIndex()); + networks.put(EVMChain.ARBITRUMONE, arbitrum_one); + + // shibuya test network + EVMChainInfo shibuya = new EVMChainInfo( + EVMChain.SHIBUYATEST.toString(), + "ASTAR Testnet", + 81L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("SBY", "SBY", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://evm.shibuya.astar.network"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://shibuya.subscan.io"); + }}, + new ArrayList() {{ + this.add("https://portal.astar.network"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/81"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.SHIBUYATEST, shibuya); + + // astar + EVMChainInfo astar = new EVMChainInfo( + EVMChain.ASTAR.toString(), + "ASTAR Mainnet", + 592L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("ASTR", "ASTR", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://astar.public.blastapi.io"); + this.add("https://evm.astar.network"); + this.add("https://1rpc.io/astr"); + this.add("https://astar-rpc.dwellir.com"); + + //this.add("https://rpc.astar.network:8545"); // continously times out + //this.add("https://astar-mainnet.g.alchemy.com/v2/demo"); // gone + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://astar.subscan.io"); + this.add("https://blockscout.com/astar"); + }}, + new ArrayList() {{ + this.add("https://portal.astar.network"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/592"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.ASTAR, astar); + + // evmos + EVMChainInfo evmos = new EVMChainInfo( + EVMChain.EVMOS.toString(), + "EVMOS Mainnet", + 9001L, + BlockchainType.BORKED.toString(), // so many issues .. + new EVMCurrency("EVMOS", "EVMOS", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://evmos-json-rpc.agoranodes.com"); + this.add("https://json-rpc.evmos.blockhunters.org"); + this.add("https://evmos-mainnet.public.blastapi.io"); + this.add("https://evmos-evm.publicnode.com"); + this.add("https://evmos-json-rpc.stakely.io"); + this.add("https://evmos-mainnet.gateway.pokt.network/v1/lb/627586ddea1b320039c95205"); + //this.add("https://eth.bd.evmos.org:8545"); // timeout + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://www.mintscan.io/evmos"); + this.add("https://evm.evmos.org/"); + }}, + new ArrayList() {{ + this.add("https://stakely.io/en/faucet/evmos-evm"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/9001"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.EVMOS, evmos); + + // evmostest + EVMChainInfo evmostest = new EVMChainInfo( + EVMChain.EVMOSTEST.toString(), + "EVMOS Testnet", + 9000L, + BlockchainType.BORKED.toString(), // so many issues .. + new EVMCurrency("tEVMOS", "tEVMOS", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://eth.bd.evmos.dev:8545"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://evm.evmos.dev/"); + }}, + new ArrayList() {{ + this.add("https://faucet.evmos.dev/"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/9000"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.EVMOSTEST, evmostest); + + // polygon + EVMChainInfo polygon = new EVMChainInfo( + EVMChain.POLYGON.toString(), + "Polygon Mainnet", + 137L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("MATIC", "MATIC", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + "31000000000", // 30 gwei threshold for miner.gasprice/txpool.pricelimit, enforced since Oct 2021: https://medium.com/stakingbits/polygon-minimum-gas-fee-is-now-30-gwei-to-curb-spam-8bd4313c83a2 + "300000", //300k units + new ArrayList() {{ + this.add("https://polygon-rpc.com/"); + this.add("https://rpc-mainnet.matic.quiknode.pro"); + this.add("https://rpc-mainnet.maticvigil.com"); + this.add("https://poly-rpc.gateway.pokt.network"); + this.add("https://polygon-mainnet.public.blastapi.io"); + this.add("https://rpc.ankr.com/polygon"); + this.add("https://1rpc.io/matic"); + this.add("https://polygon-bor.publicnode.com"); + this.add("https://polygon.llamarpc.com"); + this.add("https://polygon.rpc.blxrbdn.com"); + this.add("https://polygon.blockpi.network/v1/rpc/public"); + this.add("https://endpoints.omniatech.io/v1/matic/mainnet/public"); + this.add("https://polygon.api.onfinality.io/public"); + //this.add("https://matic-mainnet.chainstacklabs.com"); + //this.add("https://polygon-mainnet-public.unifra.io"); + //this.add("https://matic-mainnet-full-rpc.bwarelabs.com"); + //this.add("https://matic-mainnet-archive-rpc.bwarelabs.com"); + //this.add("https://polygon-mainnet.g.alchemy.com/v2/demo"); // dead node + //this.add("https://polygon-mainnet.rpcfast.com"); // consistently timeout + //this.add("https://polygonapi.terminet.io/rpc"); // consistently slow + //this.add("https://rpc-mainnet.matic.network"); // just unstable at times + }}, + new ArrayList() {{ + this.add("https://polygon-mainnet.g.alchemy.com/v2/"); // archive node + }}, + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://polygonscan.com"); + //this.add("https://explorer.matic.network"); // discontinued + }}, + new ArrayList() {{ + this.add("https://matic.supply"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/137"); + }}, + generatePolygonTokenIndex(), + generatePolygonNFTIndex()); + networks.put(EVMChain.POLYGON, polygon); + + // mumbai + EVMChainInfo mumbai = new EVMChainInfo( + EVMChain.MUMBAITEST.toString(), + "Polygon Test Network", + 80001L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Polygon Test Token", "MATIC", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + "31000000000", // some mumbai nodes actually implement the 30 gwei min threshold as mainnet (see polygon object) + "300000", //300k units + new ArrayList() {{ + this.add("https://rpc-mumbai.maticvigil.com"); + this.add("https://rpc.ankr.com/polygon_mumbai"); + this.add("https://rpc-mumbai.maticvigil.com"); + this.add("https://polygon-testnet.public.blastapi.io"); + //this.add("https://matic-mumbai.chainstacklabs.com"); + //this.add("https://matic-testnet-archive-rpc.bwarelabs.com"); // dead + //this.add("https://polygontestapi.terminet.io/rpc"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://mumbai.polygonscan.com"); + }}, + new ArrayList() {{ + this.add("https://faucet.polygon.technology/"); + this.add("https://mumbaifaucet.com/"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/80001"); + }}, + generateMumbaiTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.MUMBAITEST, mumbai); + + // zksyncera + EVMChainInfo zksyncera = new EVMChainInfo( + EVMChain.ZKSYNCERA.toString(), + "zkSync Era Mainnet", + 324L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("zkSync Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "250000000", //0.25 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://mainnet.era.zksync.io"); + this.add("https://zksync.drpc.org"); + this.add("https://zksync-era.blockpi.network/v1/rpc/public"); + this.add("https://zksync.meowrpc.com"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://explorer.zksync.io"); + }}, + new ArrayList() {{ + this.add("brige test funds from goerli using https://portal.zksync.io/bridge"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/324"); + }}, + generateZkSyncTokenIndex(), + generateZKSyncEraNFTIndex()); + networks.put(EVMChain.ZKSYNCERA, zksyncera); + + // zksynceratest + EVMChainInfo zksynceratest = new EVMChainInfo( + EVMChain.ZKSYNCERATEST.toString(), + "zkSync Test Network", + 280L, + BlockchainType.BORKED.toString(), // WEB3 RPC API not fully compatible, need to use https://docs.zksync.io/api/sdk/ + new EVMCurrency("zkSync Era Test Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://testnet.era.zksync.dev"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://goerli.explorer.zksync.io"); + }}, + new ArrayList() {{ + this.add("brige test funds from goerli using https://portal.zksync.io/bridge"); + this.add("https://goerli.portal.zksync.io/faucet"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/280"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.ZKSYNCERATEST, zksynceratest); + + // ropsten + EVMChainInfo ropsten = new EVMChainInfo( + EVMChain.ROPSTENTEST.toString(), + "Ropsten Test Network", + 3L, + BlockchainType.BORKED.toString(), // Network decommissioned, please use Goerli or Sepolia instead + new EVMCurrency("Ropsten Test Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://ropsten.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161"); + this.add("https://rpc.ankr.com/eth_ropsten"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://ropsten.etherscan.io"); + }}, + new ArrayList() {{ + this.add("decomissioned"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/3"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.ROPSTENTEST, ropsten); + + // sepolia + EVMChainInfo sepolia = new EVMChainInfo( + EVMChain.SEPOLIATEST.toString(), + "Sepolia Test Network", + 11155111L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Sepolia Test Token", "SEP", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://rpc.sepolia.org"); + this.add("https://rpc2.sepolia.org"); + this.add("https://ethereum-sepolia.blockpi.network/v1/rpc/public"); + this.add("https://eth-sepolia.public.blastapi.io"); + this.add("https://gateway.tenderly.co/public/sepolia"); + this.add("https://eth-sepolia.public.blastapi.io"); + this.add("https://endpoints.omniatech.io/v1/eth/sepolia/public"); + this.add("https://eth-sepolia-public.unifra.io"); + this.add("https://rpc.notadegen.com/sepolia"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://sepolia.etherscan.io/"); + }}, + new ArrayList() {{ + this.add("https://faucet.sepolia.dev/"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/11155111"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.SEPOLIATEST, sepolia); + + // arbitrumgoerli + EVMChainInfo arbitrumgoerli = new EVMChainInfo( + EVMChain.ARBITRUMGOERLITEST.toString(), + "Arbitrum Goerli Test Network", + 421613L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Arbitrum Goerli ETH Test Token", "AGOR", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "20000000", //20M units .. Arbitrum is weird + new ArrayList() {{ + this.add("https://goerli-rollup.arbitrum.io/rpc"); + this.add("https://arbitrum-goerli.public.blastapi.io"); + this.add("https://endpoints.omniatech.io/v1/arbitrum/goerli/public"); + //this.add("https://arb-goerli.g.alchemy.com/v2/demo"); // dead + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), + new ArrayList(), + new ArrayList() {{ + this.add("https://goerli.arbiscan.io/"); + this.add("https://goerli-rollup-explorer.arbitrum.io"); + }}, + new ArrayList() {{ + this.add("https://faucetttt"); + this.add("https://bridge.arbitrum.io"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/421613"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.ARBITRUMGOERLITEST, arbitrumgoerli); + + // goerli + EVMChainInfo goerli = new EVMChainInfo( + EVMChain.GOERLITEST.toString(), + "Goerli Test Network", + 5L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Goerli ETH Test Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161"); + this.add("https://rpc.ankr.com/eth_goerli"); + //this.add("https://rpc.goerli.mudit.blog"); // lagging/dead node + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList() {{ + this.add("https://rpc-goerli.flashbots.net"); + }}, + new ArrayList() {{ + this.add("https://relay-goerli.flashbots.net"); + //this.add("https://goerli-relay.securerpc.com"); // untested + }}, + new ArrayList() {{ + this.add("https://goerli.etherscan.io"); + }}, + new ArrayList() {{ + this.add("https://goerli-faucet.mudit.blog/"); + this.add("https://faucets.chain.link/goerli"); + this.add("https://goerli-faucet.slock.it/"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/5"); + }}, + generateGoerliTokenIndex(), + generateGoerliNFTIndex()); + networks.put(EVMChain.GOERLITEST, goerli); + + // fuji + EVMChainInfo fuji = new EVMChainInfo( + EVMChain.FUJITEST.toString(), + "Avalanche Fuji Test Network", + 43113L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("AVAX FUJI Test Token", "AVAX", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://api.avax-test.network/ext/bc/C/rpc"); + this.add("https://avalanche-fuji-c-chain.publicnode.com"); + this.add("https://ava-testnet.public.blastapi.io/ext/bc/C/rpc"); + this.add("https://rpc.ankr.com/avalanche_fuji"); + this.add("https://endpoints.omniatech.io/v1/avax/fuji/public"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://testnet.snowtrace.io"); + }}, + new ArrayList() {{ + this.add("https://faucet.avax.network/"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/43113"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.FUJITEST, fuji); + + // rinkeby + EVMChainInfo rinkeby = new EVMChainInfo( + EVMChain.RINKEBYTEST.toString(), + "Rinkeby Test Network", + 4L, + BlockchainType.BORKED.toString(), // Discontinued/readonly since 2022-10-05 + new EVMCurrency("Rinkeby Test Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://rpc.ankr.com/eth_rinkeby"); + this.add("https://rinkeby.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161 "); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://rinkeby.etherscan.io"); + }}, + new ArrayList() {{ + this.add("discontinued"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/4"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.RINKEBYTEST, rinkeby); + + // kovan, https://chainlist.org/chain/42 + EVMChainInfo kovan = new EVMChainInfo( + EVMChain.KOVANTEST.toString(), + "Kovan Test Network", + 42L, + BlockchainType.BORKED.toString(), // discontinued test network since September 1, 2022 + new EVMCurrency("Kovan Test Token", "KOV", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://kovan.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161"); + this.add("https://kovan.poa.network"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://kovan.etherscan.io"); + }}, + new ArrayList() {{ + this.add("discontinued"); + }}, + new ArrayList() {{ + this.add("https://rpc.info/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.KOVANTEST, kovan); + + // cronostest + EVMChainInfo cronostest = new EVMChainInfo( + EVMChain.CRONOSTEST.toString(), + "Cronos Test Network", + 338L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("CRONOS Test Token", "TCRO", 18), + EVMPriceMechanism.EIP1559.toString(), + "2000000000000", // 2000 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://evm-t3.cronos.org"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://testnet.cronoscan.com/"); + }}, + new ArrayList() {{ + this.add("https://cronos.org/faucet"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/338"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.CRONOSTEST, cronostest); + + // cronos + EVMChainInfo cronos = new EVMChainInfo( + EVMChain.CRONOS.toString(), + "Cronos Main Network", + 25L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("CRONOS Main Token", "CRO", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://cronosrpc-1.xstaking.sg"); + this.add("https://evm.cronos.org"); + this.add("https://cronos.blockpi.network/v1/rpc/public"); + this.add("https://cronos-evm.publicnode.com"); + //this.add("https://cronos-rpc.elk.finance"); // dead + //this.add("https://cronos-rpc.heavenswail.one"); // dead + + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://cronoscan.com/"); + }}, + new ArrayList() {{ + this.add("https://cronos.org/faucet"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/25"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.CRONOS, cronos); + + // eth + EVMChainInfo eth = new EVMChainInfo( + EVMChain.ETHEREUM.toString(), + "Ethereum Main Network", + 1L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Ethereum Main Token", "ETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://mainnet.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161"); + this.add("https://eth-mainnet.public.blastapi.io"); + this.add("https://rpc.ankr.com/eth"); + this.add("https://eth-rpc.gateway.pokt.network"); + this.add("https://eth-mainnet.gateway.pokt.network/v1/5f3453978e354ab992c4da79"); + this.add("https://cloudflare-eth.com"); + this.add("https://nodes.mewapi.io/rpc/eth"); + this.add("https://rpc.mevblocker.io"); + + //this.add("https://main-rpc.linkpool.io"); // invalid cert + //this.add("https://main-light.eth.linkpool.io"); // invalid cert + //this.add("https://api.mycryptoapi.com/eth"); // consistent 403 + //this.add("https://ethereumnodelight.app.runonflux.io"); // consistent rpc errors + //this.add("https://eth-mainnet.nodereal.io/v1/1659dfb40aa24bbb8153a677b98064d7"); + //this.add("https://mainnet-nethermind.blockscout.com"); // gone, resolve issues + //this.add("https://mainnet.eth.cloud.ava.do"); // just unstable + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList() {{ + this.add("https://rpc.flashbots.net"); + }}, + new ArrayList() {{ + this.add("https://relay.flashbots.net"); + //this.add("https://mainnet-relay.securerpc.com"); // untested + }}, + new ArrayList() {{ + this.add("https://etherscan.io"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/1"); + }}, + generateEthereumTokenIndex(), + generateEthereumNFTIndex()); + networks.put(EVMChain.ETHEREUM, eth); + + // avax + EVMChainInfo avax = new EVMChainInfo( + EVMChain.AVAX.toString(), + "Avalanche C-Chain", + 43114L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Avalanche Native Token", "AVAX", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://api.avax.network/ext/bc/C/rpc"); + this.add("https://rpc.ankr.com/avalanche"); + this.add("https://ava-mainnet.public.blastapi.io/ext/bc/C/rpc"); + this.add("https://avax.meowrpc.com"); + //this.add("https://avalancheapi.terminet.io/ext/bc/C/rpc"); // keps pushing 500 internal server error + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://snowtrace.io/"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/43114"); + }}, + generateAvaxTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.AVAX, avax); + + // boba + EVMChainInfo boba = new EVMChainInfo( + EVMChain.BOBA.toString(), + "Boba Network", + 288L, + BlockchainType.PUBLIC.toString(), // missing good rpcs + new EVMCurrency("Boba Token", "ETH", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://lightning-replica.boba.network"); + //this.add("https://boba-mainnet.gateway.pokt.network/v1/lb/623ad21b20354900396fed7f"); // timeout + this.add("https://mainnet.boba.network"); // was temp stuck at block 951796 + //this.add("https://lighting-replica.boba.network"); // does not resolve + }}, + new ArrayList() {{ + this.add("https://blockexplorer.boba.network"); + this.add("https://mainnet.boba.network "); + this.add("https://boba-mainnet.gateway.pokt.network/v1/lb/623ad21b20354900396fed7f "); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://gateway.testnet.bnb.boba.network/wallet"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/288"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.BOBA, boba); + + // bobarinkeby + EVMChainInfo bobarinkeby = new EVMChainInfo( + EVMChain.BOBARINKEBYTEST.toString(), + "Boba Rinkeby Test Token", + 28L, + BlockchainType.BORKED.toString(), // node no longer resolves, no replacement found + new EVMCurrency("Boba Rinkeby Test Token", "ETH", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://rinkeby.boba.network"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://blockexplorer.rinkeby.boba.network"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/28"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.BOBARINKEBYTEST, bobarinkeby); + + // bobabnb + EVMChainInfo bobabnb = new EVMChainInfo( + EVMChain.BOBABNBTEST.toString(), + "Boba BNB Test Token", + 9728L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Boba BNB Test Token", "BOBA", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://testnet.bnb.boba.network"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://blockexplorer.testnet.bnb.boba.network"); + }}, + new ArrayList() {{ + this.add("https://gateway.testnet.bnb.boba.network/wallet"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/9728"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.BOBABNBTEST, bobabnb); + + // bitkub + EVMChainInfo bitkub = new EVMChainInfo( + EVMChain.BITKUB.toString(), + "Bitkub Network", + 96L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Bitkub Native Token", "KUB", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://rpc.bitkubchain.io"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://bkcscan.com"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://support.bitkub.com/hc/en-us/articles/360061315771-How-to-connect-an-online-wallet-to-Bitkub-Chain-Metamask"); // NEXT Smart Chain? https://chainlist.org/chain/96 + }}, + generateBitkubTokenIndex(), + generateBitkubNFTIndex()); + networks.put(EVMChain.BITKUB, bitkub); + + // bitkub_test + EVMChainInfo bitkub_test = new EVMChainInfo( + EVMChain.BITKUBTEST.toString(), + "Bitkub Test Network", + 25925L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Bitkub Native Token", "tKUB", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://rpc-testnet.bitkubchain.io"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://testnet.bkcscan.com"); + }}, + new ArrayList() {{ + this.add("https://faucet.bitkubchain.com"); + }}, + new ArrayList() {{ + this.add("https://bitkub.com"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.BITKUBTEST, bitkub_test); + + // moonbeam + EVMChainInfo moonbeam = new EVMChainInfo( + EVMChain.MOONBEAM.toString(), + "Moonbeam Network", + 1284L, + BlockchainType.PUBLIC.toString(), // All nodes just give Value must be in format 0x[1-9]+[0-9]* or 0x0 errors .. + new EVMCurrency("Moonbeam Native Token", "GLMR", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://rpc.api.moonbeam.network"); + this.add("https://rpc.ankr.com/moonbeam"); + this.add("https://moonbeam.public.blastapi.io"); + this.add("https://moonbeam.unitedbloc.com:3000"); + this.add("https://moonbeam.api.onfinality.io/public"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://moonscan.io"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/1284"); + }}, + generateMoonbeamTokenIndex(), + generateMoonbeamNFTIndex()); + networks.put(EVMChain.MOONBEAM, moonbeam); + + // moonriver + EVMChainInfo moonriver = new EVMChainInfo( + EVMChain.MOONRIVER.toString(), + "Moonbeam Network", + 1285L, + BlockchainType.PUBLIC.toString(), // All nodes just give Value must be in format 0x[1-9]+[0-9]* or 0x0 errors .. + new EVMCurrency("MoonRiver Native Token", "MOVR", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://moonriver.unitedbloc.com:2000"); + this.add("https://moonriver.public.blastapi.io"); + this.add("https://rpc.api.moonriver.moonbeam.network"); + this.add("https://moonriver.api.onfinality.io/public"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://moonriver.moonscan.io"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/1285"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.MOONRIVER, moonriver); + + // taraxa + EVMChainInfo taraxa = new EVMChainInfo( + EVMChain.TARAXA.toString(), + "Taraxa Mainnet", + 841L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Taraxa Native Token", "TARA", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://rpc.mainnet.taraxa.io"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://explorer.mainnet.taraxa.io"); + }}, + new ArrayList() {{ + this.add(""); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/841"); + this.add("https://www.coingecko.com/sv/coins/taraxa"); + this.add("https://www.taraxa.io/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.TARAXA, taraxa); + + // taraxatest + EVMChainInfo taraxatest = new EVMChainInfo( + EVMChain.TARAXATEST.toString(), + "Taraxa Testnet", + 842L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Taraxa Native Token", "TARA", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://rpc.testnet.taraxa.io"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://explorer.testnet.taraxa.io"); + }}, + new ArrayList() {{ + this.add("https://testnet.explorer.taraxa.io/faucet"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/842"); + this.add("https://www.coingecko.com/sv/coins/taraxa"); + this.add("https://www.taraxa.io/"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.TARAXATEST, taraxatest); + + // fantom + EVMChainInfo fantom = new EVMChainInfo( + EVMChain.FANTOM.toString(), + "Fantom Network", + 250L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Fantom Native Token", "FTM", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://rpc.ftm.tools"); + this.add("https://fantom-mainnet.gateway.pokt.network/v1/lb/62759259ea1b320039c9e7ac"); + this.add("https://rpc.ankr.com/fantom"); + this.add("https://rpc2.fantom.network"); + this.add("https://rpcapi.fantom.network"); + this.add("https://fantom-mainnet.public.blastapi.io"); + + //this.add("https://rpc.fantom.network"); // invalid cert + //this.add("https://rpc3.fantom.network"); // unstable + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://ftmscan.com"); + }}, + new ArrayList() {{ + this.add("https://faucet.fantom.network/"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/250"); + }}, + generateFantomTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.FANTOM, fantom); + + // fantomtest + EVMChainInfo fantomtest = new EVMChainInfo( + EVMChain.FANTOMTEST.toString(), + "Fantom Test Network", + 4002L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Fantom Native Token", "FTM", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://fantom.api.onfinality.io/public"); + this.add("https://fantom-testnet.public.blastapi.io"); + this.add("https://rpc.testnet.fantom.network"); + this.add("https://rpc.ankr.com/fantom_testnet"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://testnet.ftmscan.com/"); + }}, + new ArrayList() {{ + this.add("https://faucet.fantom.network/"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/4002"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.FANTOMTEST, fantomtest); + + // harmony, https://chainlist.org/chain/1666600000 + EVMChainInfo harmony = new EVMChainInfo( + EVMChain.HARMONY.toString(), + "Harmony Mainnet Shard 0", + 1666600000L, + BlockchainType.BORKED.toString(), // address convertion oneXXXX + new EVMCurrency("Harmony Native Token", "ONE", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://api.harmony.one"); + this.add("https://harmony-0-rpc.gateway.pokt.network"); + this.add("https://harmony-mainnet.chainstacklabs.com"); + this.add("https://api.s0.t.hmny.io"); + this.add("https://rpc.ankr.com/harmony"); + this.add("https://a.api.s0.t.hmny.io"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://explorer.harmony.one"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/1666600000"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.HARMONY, harmony); + + // etho + EVMChainInfo etho = new EVMChainInfo( + EVMChain.ETHO.toString(), + "ETHO Network", + 1313114L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("ETHO Native Token", "ETHO", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + //this.add("https://rpc.ether1.org"); // discontinued + this.add("https://rpc.ethoprotocol.com"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://explorer.ethoprotocol.com"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/1313114"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.ETHO, etho); + + // bsc + EVMChainInfo bsc = new EVMChainInfo( + EVMChain.BSC.toString(), + "Binance Smart Chain Mainnet", + 56L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Binance Chain Native Token", "BNB", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "500000", //500k units + new ArrayList() {{ + this.add("https://bsc-dataseed.binance.org"); + this.add("https://bsc-dataseed1.binance.org"); + this.add("https://bsc-dataseed2.binance.org"); + this.add("https://bsc-dataseed3.binance.org"); + this.add("https://bsc-dataseed4.binance.org"); + this.add("https://bsc-dataseed1.defibit.io"); + this.add("https://bsc-dataseed2.defibit.io"); + this.add("https://bsc-dataseed3.defibit.io"); + this.add("https://bsc-dataseed4.defibit.io"); + this.add("https://bsc-dataseed1.ninicoin.io"); + this.add("https://bsc-dataseed2.ninicoin.io"); + this.add("https://bsc-dataseed3.ninicoin.io"); + this.add("https://bsc-dataseed4.ninicoin.io"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://bscscan.com"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/56"); + }}, + generateBSCTokenIndex(), + generateBSCNFTIndex()); + networks.put(EVMChain.BSC, bsc); + + // bsctest + EVMChainInfo bsctest = new EVMChainInfo( + EVMChain.BSCTEST.toString(), + "Binance Smart Chain Testnet", + 97L, + BlockchainType.BORKED.toString(), // execution reverted for simple interaction? + new EVMCurrency("Binance Chain Test Native Token", "tBNB", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://data-seed-prebsc-1-s1.binance.org:8545"); + this.add("https://data-seed-prebsc-1-s2.binance.org:8545"); + this.add("https://data-seed-prebsc-1-s3.binance.org:8545"); + this.add("https://data-seed-prebsc-2-s2.binance.org:8545"); + this.add("https://bsc-testnet.public.blastapi.io"); + this.add("https://bsc-testnet.publicnode.com"); + this.add("https://bsc-testnet.blockpi.network/v1/rpc/public"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://testnet.bscscan.com"); + }}, + new ArrayList() {{ + this.add("https://testnet.binance.org/faucet-smart"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/97"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.BSCTEST, bsctest); + + // metis + EVMChainInfo metis = new EVMChainInfo( + EVMChain.METIS.toString(), + "Metis Mainnet", + 1088L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Metis Native Token", "METIS", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://andromeda.metis.io/?owner=1088"); + this.add("https://metis-mainnet.public.blastapi.io"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://andromeda-explorer.metis.io/"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/1088"); + }}, + generateMetisTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.METIS, metis); + + // metisgoerli + EVMChainInfo metisgoerli = new EVMChainInfo( + EVMChain.METISSTARDUSTTEST.toString(), + "Metis Stardust Testnet", + 599L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Metis Goerli Test Token", "METIS", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://goerli.gateway.metisdevops.link"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://goerli.explorer.metisdevops.link"); + }}, + new ArrayList() {{ + this.add("https://goerli.faucet.metisdevops.link/"); + this.add("bridge assets from goerli https://bridge.metis.io/home"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/599"); + }}, + generateMetisTestTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.METISSTARDUSTTEST, metisgoerli); + + // aurora + EVMChainInfo aurora = new EVMChainInfo( + EVMChain.AURORA.toString(), + "Aurora Mainnet", + 1313161554L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Aurora Token", "AETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://mainnet.aurora.dev"); + this.add("https://1rpc.io/aurora"); + this.add("https://aurora.drpc.org"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://aurorascan.dev/"); + this.add("https://explorer.mainnet.aurora.dev/"); + this.add("https://explorer.aurorachain.io/"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/1313161554"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.AURORA, aurora); + + // aurora_test + EVMChainInfo aurora_test = new EVMChainInfo( + EVMChain.AURORATEST.toString(), + "Aurora Testnet", + 1313161555L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("Aurora Token", "AETH", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://endpoints.omniatech.io/v1/aurora/testnet/public"); + this.add("https://1rpc.io/aurora"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://explorer.testnet.aurora.dev/"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/1313161555"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.AURORATEST, aurora_test); + + // ganache + EVMChainInfo ganache8545_1337 = new EVMChainInfo( + EVMChain.GANACHE8545_1337.toString(), + "Ganache Test Chain, default local port 8545 and chainid 1337", + 1337L, + BlockchainType.LOCAL.toString(), + new EVMCurrency("Development Test Token", "ETH", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("http://127.0.0.1:8545"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://blockexplorer.x"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://gsthina.medium.com/the-default-chain-id-for-ganache-metamask-is-1337-can-you-try-to-override-it-de5ad1bcb3ab"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.GANACHE8545_1337, ganache8545_1337); + + // ganache + EVMChainInfo ganache7545 = new EVMChainInfo( + EVMChain.GANACHE7545_1337.toString(), + "Ganache Test Chain, default local port 7545 and chainid 1337", + 1337L, + BlockchainType.LOCAL.toString(), + new EVMCurrency("Development Test Token", "ETH", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("http://127.0.0.1:7545"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://blockexplorer.x"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://gsthina.medium.com/the-default-chain-id-for-ganache-metamask-is-1337-can-you-try-to-override-it-de5ad1bcb3ab"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.GANACHE7545_1337, ganache7545); + + // ganache + EVMChainInfo ganache8545_5777 = new EVMChainInfo( + EVMChain.GANACHE8545_5777.toString(), + "Ganache Test Chain, default local port 8545 and chainid 5777", + 5777L, + BlockchainType.LOCAL.toString(), + new EVMCurrency("Development Test Token", "ETH", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("http://127.0.0.1:8545"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://blockexplorer.x"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://gsthina.medium.com/the-default-chain-id-for-ganache-metamask-is-1337-can-you-try-to-override-it-de5ad1bcb3ab"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.GANACHE8545_5777, ganache8545_5777); + + // ganache + EVMChainInfo ganache7545_5777 = new EVMChainInfo( + EVMChain.GANACHE7545_5777.toString(), + "Ganache Test Chain, default local port 7545 and chainid 5777", + 5777L, + BlockchainType.LOCAL.toString(), + new EVMCurrency("Development Test Token", "ETH", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("http://127.0.0.1:7545"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://blockexplorer.x"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://gsthina.medium.com/the-default-chain-id-for-ganache-metamask-is-1337-can-you-try-to-override-it-de5ad1bcb3ab"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.GANACHE7545_5777, ganache7545_5777); + + // hardhat + EVMChainInfo hardhat443_31337 = new EVMChainInfo( + EVMChain.HARDHAT443_31337.toString(), + "Hardhat Test Chain, default local https port 443 and chainid 31337", + 31337L, + BlockchainType.LOCAL.toString(), + new EVMCurrency("Development Test Token", "ETH", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://localhost"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://blockexplorer.x"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://hardhat.org/hardhat-network/docs/reference"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.HARDHAT443_31337, hardhat443_31337); + + // hardhat + EVMChainInfo hardhat8545_31337 = new EVMChainInfo( + EVMChain.HARDHAT8545_31337.toString(), + "Hardhat Test Chain, default local port 8545 and chainid 31337", + 31337L, + BlockchainType.LOCAL.toString(), + new EVMCurrency("Development Test Token", "ETH", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("http://127.0.0.1:8545"); + this.add("http://127.0.0.1:8545/rpc"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://blockexplorer.x"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://hardhat.org/hardhat-network/docs/reference"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.HARDHAT8545_31337, hardhat8545_31337); + + // celo + EVMChainInfo celo = new EVMChainInfo( + EVMChain.CELO.toString(), + "Celo Mainnet", + 42220L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("CELO Native Token", "CELO", 18), + EVMPriceMechanism.EIP1559.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://forno.celo.org"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://explorer.celo.org"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/42220"); + }}, + generateCeloTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.CELO, celo); + + // base + EVMChainInfo base = new EVMChainInfo( + EVMChain.BASE.toString(), + "BASE Mainnet", + 8453L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("BASE Native Token", "ETH", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://base.blockpi.network/v1/rpc/public"); + this.add("https://developer-access-mainnet.base.org"); + this.add("https://base-mainnet.public.blastapi.io"); + this.add("https://base.meowrpc.com"); + this.add("https://base.publicnode.com"); + this.add("https://1rpc.io/base"); + this.add("https://mainnet.base.org"); + this.add("https://rpc.notadegen.com/base"); + this.add("https://base-mainnet.diamondswap.org/rpc"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://basescan.org"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/8453"); + this.add("https://base.org/"); + }}, + generateBaseTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.BASE, base); + + // klaytn + EVMChainInfo klay = new EVMChainInfo( + EVMChain.KLAYTN.toString(), + "KLAYTN Mainnet", + 8217L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("KLAYTN Native Token", "KLAY", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://public-node-api.klaytnapi.com/v1/cypress"); + this.add("https://klaytn.blockpi.network/v1/rpc/public"); + this.add("https://klaytn.api.onfinality.io/public"); + this.add("https://klaytn.drpc.org"); + + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://scope.klaytn.com"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://chainlist.org/chain/8217"); + this.add("https://medium.com/klaytn/how-to-add-klaytn-to-metamask-b3bdd970c0e8"); + }}, + generateKlaytnTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.KLAYTN, klay); + + // borachain + EVMChainInfo borachain = new EVMChainInfo( + EVMChain.BORACHAIN.toString(), + "Bora Chain, gaming side-chain of KLAYTN", + 77001L, + BlockchainType.PUBLIC.toString(), + new EVMCurrency("BORAChain Native Token", "BGAS", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://public-node.api.boraportal.io/bora/mainnet"); // fails to reply to node rpc version + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://scope.boraportal.com/"); + }}, + new ArrayList() {{ + this.add("faucet-to-be-inserted"); + }}, + new ArrayList() {{ + this.add("https://medium.com/@DAO_FE/1-add-rpc-network-name-borachain-mainnet-network-url-https-public-node-api-boraportal-io-b-59f422588926"); + }}, + generateBorachainTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.BORACHAIN, borachain); + + // shardeum15 + EVMChainInfo shardeum15 = new EVMChainInfo( + EVMChain.SHARDEUMLIBERTY1xTEST.toString(), + "Shardeum Liberty 1.5", + 8080L, + BlockchainType.BORKED.toString(), // very unstable atm, inconsistent results + new EVMCurrency("Shardeum Native Token", "SHM", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://liberty10.shardeum.org"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://explorer.liberty10.shardeum.org"); + }}, + new ArrayList() {{ + this.add("https://docs.shardeum.org/faucet/claim"); + }}, + new ArrayList() {{ + this.add("https://docs.shardeum.org/wallets/MetaMask/add-shardeum-network"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.SHARDEUMLIBERTY1xTEST, shardeum15); + + // shardeum20 + EVMChainInfo shardeum20 = new EVMChainInfo( + EVMChain.SHARDEUMLIBERTY2xTEST.toString(), + "Shardeum Liberty 2.0", + 8081L, + BlockchainType.BORKED.toString(), // very unstable atm + new EVMCurrency("Shardeum Native Token", "SHM", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://liberty20.shardeum.org"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://explorer.liberty20.shardeum.org"); + }}, + new ArrayList() {{ + this.add("https://docs.shardeum.org/faucet/claim"); + }}, + new ArrayList() {{ + this.add("https://docs.shardeum.org/wallets/MetaMask/add-shardeum-network"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.SHARDEUMLIBERTY2xTEST, shardeum20); + + // shardeum20 + EVMChainInfo shardeumsphinx10 = new EVMChainInfo( + EVMChain.SHARDEUMSPHINX1xTEST.toString(), + "Shardeum Sphinx 1.x", + 8082L, + BlockchainType.BORKED.toString(), // very unstable atm + new EVMCurrency("Shardeum Native Token", "SHM", 18), + EVMPriceMechanism.LEGACY.toString(), + "30000000000", //30 gwei + null, // enforced min gasprice + "300000", //300k units + new ArrayList() {{ + this.add("https://sphinx.shardeum.org"); + }}, + new ArrayList(), // archive nodes (if available) + new ArrayList(), // flashbot nodes (if available) + new ArrayList(), // flashbot relay nodes (if available) + new ArrayList() {{ + this.add("https://explorer-sphinx.shardeum.org"); + }}, + new ArrayList() {{ + this.add("https://docs.shardeum.org/faucet/claim"); + }}, + new ArrayList() {{ + this.add("https://docs.shardeum.org/wallets/MetaMask/add-shardeum-network"); + }}, + generateDummyTokenIndex(), + generateDummyNFTIndex()); + networks.put(EVMChain.SHARDEUMSPHINX1xTEST, shardeumsphinx10); + + return new EVMChainIndex(networks); + + } + + public static String generateEVMChainIndexJSON() { + EVMChainIndex idx = generateEVMChainIndex(); + return JSONUtils.createJSONFromPOJO(idx); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateFantomTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // stg + EVMERC20TokenInfo stg = new EVMERC20TokenInfo( + FantomERC20Token.STG.toString(), + "0x2f6f07cdcf3588944bf4c42ac74ff24bf56e7590", + "StarGate token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.FANTOM.toString(), + new ArrayList() {{ + this.add("https://ftmscan.com/address/0x2f6f07cdcf3588944bf4c42ac74ff24bf56e7590"); + this.add("https://www.coingecko.com/en/coins/stargate-finance"); + }}); + tokens.put(FantomERC20Token.STG.toString(), stg); + + // usdc + EVMERC20TokenInfo usdc = new EVMERC20TokenInfo( + FantomERC20Token.USDC.toString(), + "0x04068da6c83afcfa0e13ba15a6696662335d5b75", + "USDC stablecoin token", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.FANTOM.toString(), + new ArrayList() {{ + this.add("https://ftmscan.com/address/0x04068da6c83afcfa0e13ba15a6696662335d5b75"); + this.add("https://www.coingecko.com/en/coins/usd-coin"); + }}); + tokens.put(FantomERC20Token.USDC.toString(), usdc); + + // multi + EVMERC20TokenInfo multi = new EVMERC20TokenInfo( + FantomERC20Token.MULTI.toString(), + "0x9fb9a33956351cf4fa040f65a13b835a3c8764e3", + "Multichain token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.FANTOM.toString(), + new ArrayList() {{ + this.add("https://ftmscan.com/address/0x9fb9a33956351cf4fa040f65a13b835a3c8764e3"); + this.add("https://www.coingecko.com/en/coins/multichain"); + }}); + tokens.put(FantomERC20Token.MULTI.toString(), multi); + + // dai + EVMERC20TokenInfo dai = new EVMERC20TokenInfo( + FantomERC20Token.DAI.toString(), + "0x8d11ec38a3eb5e956b052f67da8bdc9bef8abf3e", + "DAI stablecoin token", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.FANTOM.toString(), + new ArrayList() {{ + this.add("https://ftmscan.com/address/0x8d11ec38a3eb5e956b052f67da8bdc9bef8abf3e"); + this.add("https://www.coingecko.com/en/coins/dai"); + }}); + tokens.put(FantomERC20Token.DAI.toString(), dai); + + // usdt + EVMERC20TokenInfo usdt = new EVMERC20TokenInfo( + FantomERC20Token.USDT.toString(), + "0x049d68029688eabf473097a2fc38ef61633a3c7a", + "Tether stablecoin token", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.FANTOM.toString(), + new ArrayList() {{ + this.add("https://ftmscan.com/address/0x049d68029688eabf473097a2fc38ef61633a3c7a"); + this.add("https://www.coingecko.com/en/coins/tether"); + }}); + tokens.put(FantomERC20Token.USDT.toString(), usdt); + + // spookyswap_ftm_multi + EVMERC20TokenInfo spookyswap_ftm_multi = new EVMERC20TokenInfo( + FantomERC20Token.SPOOKYSWAP_FTM_MULTI_LP.toString(), + "0x297C8990134bf1eE08aE5D8805042fbac8781201", + "Spookyswap FTM+MULTI LP token", + 18, + TokenCategory.LIQUIDITY_PROVIDER.toString(), + EVMChain.FANTOM.toString(), + new ArrayList() {{ + this.add("https://ftmscan.com/token/0x297c8990134bf1ee08ae5d8805042fbac8781201?a=0xf0803b4cf6359d64913ec6a0b8227640afe69b2a"); + this.add("https://spooky.fi/#/add/FTM/0x9Fb9a33956351cf4fa040f65A13b835A3C8764E3"); + }}); + tokens.put(FantomERC20Token.SPOOKYSWAP_FTM_MULTI_LP.toString(), spookyswap_ftm_multi); + + // test + EVMERC20TokenInfo test = new EVMERC20TokenInfo( + FantomERC20Token.TEST.toString(), + "0x62b65f4b89e9a56b687ccebb57b4afeafa933894", + //"0x62b65f4b89e9a56b687ccebb57b4afeafa933894", // BLOOM scam token + "TEST token", + 18, + TokenCategory.TEST.toString(), + EVMChain.FANTOM.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0xMOJO"); + }}); + tokens.put(FantomERC20Token.TEST.toString(), test); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateGoerliTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // mantle + EVMERC20TokenInfo mantle = new EVMERC20TokenInfo( + GoerliERC20Token.MNT.toString(), + "0xc1dC2d65A2243c22344E725677A3E3BEBD26E604", + "Mantle ERC-20 token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.GOERLITEST.toString(), + new ArrayList() {{ + this.add("https://goerli.etherscan.io/token/0xc1dC2d65A2243c22344E725677A3E3BEBD26E604"); + }}); + tokens.put(GoerliERC20Token.MNT.toString(), mantle); + + // zeta + EVMERC20TokenInfo zeta = new EVMERC20TokenInfo( + GoerliERC20Token.ZETA.toString(), + "0xCc7bb2D219A0FC08033E130629C2B854b7bA9195", + "ZETA swap/bridge gas token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.GOERLITEST.toString(), + new ArrayList() {{ + this.add("https://goerli.etherscan.io/token/0xCc7bb2D219A0FC08033E130629C2B854b7bA9195"); + }}); + tokens.put(GoerliERC20Token.ZETA.toString(), zeta); + + + // usdc + EVMERC20TokenInfo usdc = new EVMERC20TokenInfo( + GoerliERC20Token.USDC.toString(), + "0x07865c6e87b9f70255377e024ace6630c1eaa37f", + "USDC Stable token", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.GOERLITEST.toString(), + new ArrayList() {{ + this.add("https://goerli.etherscan.io/token/0x07865c6e87b9f70255377e024ace6630c1eaa37f"); + }}); + tokens.put(GoerliERC20Token.USDC.toString(), usdc); + + // weth + EVMERC20TokenInfo weth = new EVMERC20TokenInfo( + GoerliERC20Token.WETH.toString(), + "0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6", + "Wrapped ETH token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.GOERLITEST.toString(), + new ArrayList() {{ + this.add("https://goerli.etherscan.io/address/0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6"); + }}); + tokens.put(GoerliERC20Token.WETH.toString(), weth); + + // dai + EVMERC20TokenInfo dai = new EVMERC20TokenInfo( + GoerliERC20Token.DAI.toString(), + "0x11fe4b6ae13d2a6055c8d9cf65c55bac32b5d844", + "DAI USD stablecoin token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.GOERLITEST.toString(), + new ArrayList() {{ + this.add("https://goerli.etherscan.io/address/0x11fe4b6ae13d2a6055c8d9cf65c55bac32b5d844"); + }}); + tokens.put(GoerliERC20Token.DAI.toString(), dai); + + // tst4 + EVMERC20TokenInfo tst4 = new EVMERC20TokenInfo( + GoerliERC20Token.TST4.toString(), + "0x3f152b63ec5ca5831061b2dccfb29a874c317502", + "Official Goerli ERC-20 TST token", + 18, + TokenCategory.TEST.toString(), + EVMChain.GOERLITEST.toString(), + new ArrayList() {{ + this.add("https://goerli.etherscan.io/token/0x3f152b63ec5ca5831061b2dccfb29a874c317502"); + }}); + tokens.put(GoerliERC20Token.TST4.toString(), tst4); + + // tstv4 + EVMERC20TokenInfo tstv4 = new EVMERC20TokenInfo( + GoerliERC20Token.TSTv4.toString(), + "0x499d11E0b6eAC7c0593d8Fb292DCBbF815Fb29Ae", + "Goerli ERC-20 TST token", + 18, + TokenCategory.TEST.toString(), + EVMChain.GOERLITEST.toString(), + new ArrayList() {{ + this.add("https://goerli.etherscan.io/token/0x499d11E0b6eAC7c0593d8Fb292DCBbF815Fb29Ae"); + }}); + tokens.put(GoerliERC20Token.TSTv4.toString(), tstv4); + + // test + EVMERC20TokenInfo test = new EVMERC20TokenInfo( + GoerliERC20Token.TEST.toString(), + "0x3f152b63ec5ca5831061b2dccfb29a874c317502", + //"0x3f152b63ec5ca5831061b2dccfb29a874c317502", //... + "TEST token", + 18, + TokenCategory.TEST.toString(), + EVMChain.GOERLITEST.toString(), + new ArrayList() {{ + this.add("https://goerli.etherscan.io/token/0xMOJO"); + }}); + tokens.put(GoerliERC20Token.TEST.toString(), test); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateKlaytnTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // ksp + EVMERC20TokenInfo ksp = new EVMERC20TokenInfo( + KlaytnKIP7Token.KSP.toString(), + "0xc6a2ad8cc6e4a7e08fc37cc5954be07d499e7654", + "Klay Swap token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.KLAYTN.toString(), + new ArrayList() {{ + this.add("https://scope.klaytn.com/token/0xc6a2ad8cc6e4a7e08fc37cc5954be07d499e7654"); + this.add("https://www.coingecko.com/en/coins/klayswap-protocol"); + }}); + tokens.put(KlaytnKIP7Token.KSP.toString(), ksp); + + // wemix + EVMERC20TokenInfo wemix = new EVMERC20TokenInfo( + KlaytnKIP7Token.WEMIX.toString(), + "0x5096db80b21ef45230c9e423c373f1fc9c0198dd", + "WEMIX game token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.KLAYTN.toString(), + new ArrayList() {{ + this.add("https://scope.klaytn.com/token/0x5096db80b21ef45230c9e423c373f1fc9c0198dd"); + this.add("https://www.coingecko.com/en/coins/wemix-token"); + }}); + tokens.put(KlaytnKIP7Token.WEMIX.toString(), wemix); + + // bora + EVMERC20TokenInfo bora = new EVMERC20TokenInfo( + KlaytnKIP7Token.BORA.toString(), + "0x02cbe46fb8a1f579254a9b485788f2d86cad51aa", + "BORA game token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.KLAYTN.toString(), + new ArrayList() {{ + this.add("https://scope.klaytn.com/token/0x02cbe46fb8a1f579254a9b485788f2d86cad51aa"); + this.add("https://www.coingecko.com/en/coins/bora"); + }}); + tokens.put(KlaytnKIP7Token.BORA.toString(), bora); + + // test + EVMERC20TokenInfo test = new EVMERC20TokenInfo( + KlaytnKIP7Token.TEST.toString(), + "0x7f1712f846a69bf2a9dbc4d48f45f1d52ca32e28", + //"0x7f1712f846a69bf2a9dbc4d48f45f1d52ca32e28", // UFO token :) + "TEST token", + 18, + TokenCategory.TEST.toString(), + EVMChain.KLAYTN.toString(), + new ArrayList() {{ + this.add("https://scope.klaytn.com/token/0xMOJO"); + }}); + tokens.put(KlaytnKIP7Token.TEST.toString(), test); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateMetisTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // usdt + EVMERC20TokenInfo usdt = new EVMERC20TokenInfo( + MetisERC20Token.USDT.toString(), + "0xbB06DCA3AE6887fAbF931640f67cab3e3a16F4dC", + "USDT stable token", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.METIS.toString(), + new ArrayList() {{ + this.add("https://andromeda-explorer.metis.io/token/0xbB06DCA3AE6887fAbF931640f67cab3e3a16F4dC"); + }}); + tokens.put(MetisERC20Token.USDT.toString(), usdt); + + // usdc + EVMERC20TokenInfo usdc = new EVMERC20TokenInfo( + MetisERC20Token.USDC.toString(), + "0xEA32A96608495e54156Ae48931A7c20f0dcc1a21", + "USDC stable token", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.METIS.toString(), + new ArrayList() {{ + this.add("https://andromeda-explorer.metis.io/address/0xEA32A96608495e54156Ae48931A7c20f0dcc1a21"); + }}); + tokens.put(MetisERC20Token.USDC.toString(), usdc); + + // VAMM_METIS_USDC_LP + EVMERC20TokenInfo vamm_metis_usdc_lp = new EVMERC20TokenInfo( + MetisERC20Token.HERMES_M_USDC_LP.toString(), + "0x5ab390084812E145b619ECAA8671d39174a1a6d1", + "VolatileV1 AMM - Metis/m.USDC LP token", + 18, + TokenCategory.LIQUIDITY_PROVIDER.toString(), + EVMChain.METIS.toString(), + new ArrayList() {{ + this.add("https://andromeda-explorer.metis.io/address/0x5ab390084812E145b619ECAA8671d39174a1a6d1"); + }}); + tokens.put(MetisERC20Token.HERMES_M_USDC_LP.toString(), vamm_metis_usdc_lp); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateMetisTestTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // weth + EVMERC20TokenInfo weth = new EVMERC20TokenInfo( + MetisERC20Token.WETH.toString(), + "0x420000000000000000000000000000000000000A", + "Wrapped ETH token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.METISSTARDUSTTEST.toString(), + new ArrayList() {{ + this.add("https://bscscan.com/address/0x420000000000000000000000000000000000000A"); + this.add("https://www.coingecko.com/en/coins/weth"); + }}); + tokens.put(MetisERC20Token.WETH.toString(), weth); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateMumbaiTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // ricochet fTUSDx + EVMERC20TokenInfo ricochet_tusd = new EVMERC20TokenInfo( + MumbaiERC20Token.RICOCHET_fTUSDx.toString(), + "0x918E0d5C96cAC79674E2D38066651212be3C9C48", + "Ricochet fTUSD token, fTUSDx", + 18, + TokenCategory.DEFI.toString(), + EVMChain.MUMBAITEST.toString(), + new ArrayList() {{ + this.add("https://mumbai.polygonscan.com/token/0x918E0d5C96cAC79674E2D38066651212be3C9C48"); + this.add("https://docs.superfluid.finance/superfluid/developers/networks"); + }}); + tokens.put(MumbaiERC20Token.RICOCHET_fTUSDx.toString(), ricochet_tusd); + + // fTUSD + EVMERC20TokenInfo ftusd = new EVMERC20TokenInfo( + MumbaiERC20Token.fTUSD.toString(), + "0xA794C9ee519FD31BbCE643e8D8138f735E97D1DB", + "Flux fTUSD stablecoin", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.MUMBAITEST.toString(), + new ArrayList() {{ + this.add("https://mumbai.polygonscan.com/token/0xA794C9ee519FD31BbCE643e8D8138f735E97D1DB"); + this.add("https://docs.superfluid.finance/superfluid/developers/networks"); + }}); + tokens.put(MumbaiERC20Token.fTUSD.toString(), ftusd); + + // ricochet fDAIx + EVMERC20TokenInfo ricochet_fdai = new EVMERC20TokenInfo( + MumbaiERC20Token.RICOCHET_fDAIx.toString(), + "0x15F0Ca26781C3852f8166eD2ebce5D18265cceb7", + "Ricochet fDAI token, fDAIx", + 18, + TokenCategory.DEFI.toString(), + EVMChain.MUMBAITEST.toString(), + new ArrayList() {{ + this.add("https://mumbai.polygonscan.com/token/0x15F0Ca26781C3852f8166eD2ebce5D18265cceb7"); + this.add("https://docs.superfluid.finance/superfluid/developers/networks"); + }}); + tokens.put(MumbaiERC20Token.RICOCHET_fDAIx.toString(), ricochet_fdai); + + // fDAI + EVMERC20TokenInfo fdaix = new EVMERC20TokenInfo( + MumbaiERC20Token.fDAI.toString(), + "0x15F0Ca26781C3852f8166eD2ebce5D18265cceb7", + "Flux fDAI stablecoin", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.MUMBAITEST.toString(), + new ArrayList() {{ + this.add("https://mumbai.polygonscan.com/token/0x15F0Ca26781C3852f8166eD2ebce5D18265cceb7"); + this.add("https://docs.superfluid.finance/superfluid/developers/networks"); + }}); + tokens.put(MumbaiERC20Token.fDAI.toString(), fdaix); + + // ricochet MATICx + EVMERC20TokenInfo ricochet_maticx = new EVMERC20TokenInfo( + MumbaiERC20Token.RICOCHET_MATICx.toString(), + "0x96B82B65ACF7072eFEb00502F45757F254c2a0D4", + "Ricochet MATIC token, MATICx", + 18, + TokenCategory.DEFI.toString(), + EVMChain.MUMBAITEST.toString(), + new ArrayList() {{ + this.add("https://mumbai.polygonscan.com/token/0x96B82B65ACF7072eFEb00502F45757F254c2a0D4"); + this.add("https://docs.superfluid.finance/superfluid/developers/networks"); + }}); + tokens.put(MumbaiERC20Token.RICOCHET_MATICx.toString(), ricochet_maticx); + + // ricochet fUSDCx + EVMERC20TokenInfo ricochet_fusdcx = new EVMERC20TokenInfo( + MumbaiERC20Token.RICOCHET_fUSDCx.toString(), + "0x42bb40bF79730451B11f6De1CbA222F17b87Afd7", + "Ricochet fUSDC token, fUSDCx", + 18, // !!!!!!! + TokenCategory.DEFI.toString(), + EVMChain.MUMBAITEST.toString(), + new ArrayList() {{ + this.add("https://mumbai.polygonscan.com/token/0x42bb40bF79730451B11f6De1CbA222F17b87Afd7"); + this.add("https://docs.superfluid.finance/superfluid/developers/networks"); + }}); + tokens.put(MumbaiERC20Token.RICOCHET_fUSDCx.toString(), ricochet_fusdcx); + + // fUSDC + EVMERC20TokenInfo fusdc = new EVMERC20TokenInfo( + MumbaiERC20Token.fUSDC.toString(), + "0xbe49ac1EadAc65dccf204D4Df81d650B50122aB2", + "Flux fUSDC token", + 18, // !!!!!! + TokenCategory.DEFI.toString(), + EVMChain.MUMBAITEST.toString(), + new ArrayList() {{ + this.add("https://mumbai.polygonscan.com/token/0xbe49ac1EadAc65dccf204D4Df81d650B50122aB2"); + this.add("https://docs.superfluid.finance/superfluid/developers/networks"); + }}); + tokens.put(MumbaiERC20Token.fUSDC.toString(), fusdc); + + // link + EVMERC20TokenInfo link = new EVMERC20TokenInfo( + MumbaiERC20Token.LINK.toString(), + "0x326C977E6efc84E512bB9C30f76E30c160eD06FB", + "LINK token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.MUMBAITEST.toString(), + new ArrayList() {{ + this.add("https://mumbai.polygonscan.com/token/0x326c977e6efc84e512bb9c30f76e30c160ed06fb"); + this.add("https://www.coingecko.com/en/coins/chainlink"); + }}); + tokens.put(MumbaiERC20Token.LINK.toString(), link); + + // tst + EVMERC20TokenInfo tst = new EVMERC20TokenInfo( + MumbaiERC20Token.TST.toString(), + "0x2d7882bedcbfddce29ba99965dd3cdf7fcb10a1e", + "Official Mumbai ERC-20 TST token", + 18, + TokenCategory.TEST.toString(), + EVMChain.MUMBAITEST.toString(), + new ArrayList() {{ + this.add("https://mumbai.polygonscan.com/address/0x2d7882bedcbfddce29ba99965dd3cdf7fcb10a1e"); + }}); + tokens.put(MumbaiERC20Token.TST.toString(), tst); + + // derc20 + EVMERC20TokenInfo derc20 = new EVMERC20TokenInfo( + MumbaiERC20Token.DERC20.toString(), + "0x2d7882bedcbfddce29ba99965dd3cdf7fcb10a1e", + "Official Mumbai ERC-20 Dummy ERC20 token", + 18, + TokenCategory.TEST.toString(), + EVMChain.MUMBAITEST.toString(), + new ArrayList() {{ + this.add("https://mumbai.polygonscan.com/token/0xfe4f5145f6e09952a5ba9e956ed0c25e3fa4c7f1"); + }}); + tokens.put(MumbaiERC20Token.DERC20.toString(), derc20); + + // test + EVMERC20TokenInfo test = new EVMERC20TokenInfo( + MumbaiERC20Token.TEST.toString(), + "0xeedb61304686f4b544baa1cb19f87c30bb8d38b9", + //"0xeedb61304686f4b544baa1cb19f87c30bb8d38b9", // FAN :) + "TEST token", + 18, + TokenCategory.TEST.toString(), + EVMChain.MUMBAITEST.toString(), + new ArrayList() {{ + this.add("https://mumbai.polygonscan.com/token/0xMOJO"); + }}); + tokens.put(MumbaiERC20Token.TEST.toString(), test); + + return new ERC20TokenIndex(tokens); + } + + public static String generateNFTIndexJSON(EVMNFTIndex idx) { + return JSONUtils.createJSONFromPOJO(idx); + } + + @SuppressWarnings("serial") + public static EVMNFTIndex generatePolygonNFTIndex() { + HashMap erc721tokens = new HashMap<>(); + HashMap erc1155tokens = new HashMap<>(); + + // mycryptoheroes + EVMERC721TokenInfo mch = new EVMERC721TokenInfo( + PolygonERC721Token.MYCRYPTOHEROES.toString(), + "0x77bd275ff2b3dc007475aac9ce7f408f5a800188", + 16765971L, + "My Crypto Heroes NFT", + TokenCategory.GAMING.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x77bd275ff2b3dc007475aac9ce7f408f5a800188"); + }}); + erc721tokens.put(PolygonERC721Token.MYCRYPTOHEROES.toString(), mch); + + // trump + EVMERC721TokenInfo trump = new EVMERC721TokenInfo( + PolygonERC721Token.TRUMP.toString(), + "0x24a11e702cd90f034ea44faf1e180c0c654ac5d9", + 0L, + "Trump Digital Trading Card NFT", + TokenCategory.SCAM.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x24a11e702cd90f034ea44faf1e180c0c654ac5d9"); + }}); + erc721tokens.put(PolygonERC721Token.TRUMP.toString(), trump); + + // uniswap v3 position + EVMERC721TokenInfo uniswap_v3_pos = new EVMERC721TokenInfo( + PolygonERC721Token.UNISWAPV3_POSITION.toString(), + "0xC36442b4a4522E871399CD717aBDD847Ab11FE88", + 0L, + "Uniswap v3 position NFT", + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0xc36442b4a4522e871399cd717abdd847ab11fe88"); + }}); + erc721tokens.put(PolygonERC721Token.UNISWAPV3_POSITION.toString(), uniswap_v3_pos); + + // unioverse + EVMERC721TokenInfo unioverse = new EVMERC721TokenInfo( + PolygonERC721Token.UNIOVERSE.toString(), + "0xed55e4477b795eaa9bb4bca24df42214e1a05c18", + 0L, + "Unioverse Collectibles", + TokenCategory.NFT.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0xed55e4477b795eaa9bb4bca24df42214e1a05c18"); + }}); + erc721tokens.put(PolygonERC721Token.UNIOVERSE.toString(), unioverse); + + // uapx alien + EVMERC721TokenInfo uapxalien = new EVMERC721TokenInfo( + PolygonERC721Token.UAPX_ALIEN.toString(), + "0xd8f000eac06cebab3b967eeb137fbcac842a1472", + 0L, + "UAPx alien NFT (formerly Terra)", + TokenCategory.NFT.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0xd8f000eac06cebab3b967eeb137fbcac842a1472"); + }}); + erc721tokens.put(PolygonERC721Token.UAPX_ALIEN.toString(), uapxalien); + + // uapx ship + EVMERC721TokenInfo uapxship = new EVMERC721TokenInfo( + PolygonERC721Token.UAPX_SHIP.toString(), + "0x2148da6c55c10ea3d9b33311d19a065592abd24b", + 0L, + "UAPx ship NFT (formerly Terra)", + TokenCategory.NFT.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x2148da6c55c10ea3d9b33311d19a065592abd24b"); + }}); + erc721tokens.put(PolygonERC721Token.UAPX_SHIP.toString(), uapxship); + + // uapx song + EVMERC721TokenInfo uapxsong = new EVMERC721TokenInfo( + PolygonERC721Token.UAPX_SONG.toString(), + "0x86c47873dd7d2186f5bd87da4757aecf1e16ac2e", + 0L, + "UAPx song NFT (formerly Terra)", + TokenCategory.NFT.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x86c47873dd7d2186f5bd87da4757aecf1e16ac2e"); + }}); + erc721tokens.put(PolygonERC721Token.UAPX_SONG.toString(), uapxsong); + + // aaveogotchi_land + EVMERC721TokenInfo aaveogotchi_land = new EVMERC721TokenInfo( + PolygonERC721Token.AAVEGOTCHI_LAND.toString(), + "0x1d0360bac7299c86ec8e99d0c1c9a95fefaf2a11", + 0L, + "AAvegotchi game LAND NFT", + TokenCategory.GAMING.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x1d0360bac7299c86ec8e99d0c1c9a95fefaf2a11"); + }}, + new ArrayList() {{ + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.GHST.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.KEK.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.ALPHA.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.FOMO.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.FUD.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.GLTR.toString()); + }}); + erc721tokens.put(PolygonERC721Token.AAVEGOTCHI_LAND.toString(), aaveogotchi_land); + + // aavegotchi + EVMERC721TokenInfo aaveogotchi = new EVMERC721TokenInfo( + PolygonERC721Token.AAVEGOTCHI.toString(), + "0x86935f11c86623dec8a25696e1c19a8659cbf95d", + 0L, + "AAvegotchi game NFT", + TokenCategory.GAMING.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0x86935f11c86623dec8a25696e1c19a8659cbf95d"); + }}, + new ArrayList() {{ + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.GHST.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.KEK.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.ALPHA.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.FOMO.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.FUD.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.GLTR.toString()); + }}); + erc721tokens.put(PolygonERC721Token.AAVEGOTCHI.toString(), aaveogotchi); + + // aavegotchi_install + EVMERC1155TokenInfo aavegotchi_install = new EVMERC1155TokenInfo( + PolygonERC1155Token.AAVEGOTCHI_INSTALLATION.toString(), + "0x9216c31d8146bcb3ea5a9162dc1702e8aedca355", + 0L, + "AAvegotchi game land installation NFT", + TokenCategory.GAMING.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x9216c31d8146bcb3ea5a9162dc1702e8aedca355"); + this.add("https://opensea.io/collection/gotchiverse-installations"); + }}, + new ArrayList() {{ + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.GHST.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.KEK.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.ALPHA.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.FOMO.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.FUD.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.GLTR.toString()); + }}); + erc1155tokens.put(PolygonERC1155Token.AAVEGOTCHI_INSTALLATION.toString(), aavegotchi_install); + + // aavegotchi_gmi + EVMERC721TokenInfo aavegotchi_gmi = new EVMERC721TokenInfo( + PolygonERC721Token.AAVEGOTCHI_GMI.toString(), + "0x3f0e22b827e51ff567d7388c2b598e2eabfa74be", + 0L, + "AAvegotchi GMI NFT", + TokenCategory.GAMING.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x3f0e22b827e51ff567d7388c2b598e2eabfa74be"); + }}, + new ArrayList() {{ + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.GHST.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.KEK.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.ALPHA.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.FOMO.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.FUD.toString()); + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.GLTR.toString()); + }}); + erc721tokens.put(PolygonERC721Token.AAVEGOTCHI_GMI.toString(), aavegotchi_gmi); + + // unstoppable domains + EVMERC721TokenInfo unstoppable = new EVMERC721TokenInfo( + PolygonERC721Token.UNSTOPPABLE_DOMAIN.toString(), + "0xa9a6a3626993d487d2dbda3173cf58ca1a9d9e9f", + 0L, + "Unstoppable domains NFT", + TokenCategory.GAMING.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0xa9a6a3626993d487d2dbda3173cf58ca1a9d9e9f"); + }}); + erc721tokens.put(PolygonERC721Token.UNSTOPPABLE_DOMAIN.toString(), unstoppable); + + // lensprotocolprofile + EVMERC721TokenInfo lensprotocolprofile = new EVMERC721TokenInfo( + PolygonERC721Token.LENSPROTOCOLPROFILE.toString(), + "0xdb46d1dc155634fbc732f92e853b10b288ad5a1d", + 0L, + "Lens Protocol Profile NFT", + TokenCategory.GAMING.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0xdb46d1dc155634fbc732f92e853b10b288ad5a1d"); + }}); + erc721tokens.put(PolygonERC721Token.LENSPROTOCOLPROFILE.toString(), lensprotocolprofile); + + // sandboxland + EVMERC721TokenInfo sandboxland = new EVMERC721TokenInfo( + PolygonERC721Token.SANDBOX_LAND.toString(), + "0x9d305a42a3975ee4c1c57555bed5919889dce63f", + 0L, + "The Sandbox LAND NFT", + TokenCategory.GAMING.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x9d305a42a3975ee4c1c57555bed5919889dce63f"); + this.add("https://opensea.io/collection/sandbox"); + }}, + new ArrayList() {{ + this.add(EVMChain.POLYGON.toString() + ":" + PolygonERC20Token.SAND.toString()); + }}); + erc721tokens.put(PolygonERC721Token.SANDBOX_LAND.toString(), sandboxland); + + return new EVMNFTIndex(erc721tokens, erc1155tokens); + } + + + @SuppressWarnings("serial") + public static EVMNFTIndex generateGoerliNFTIndex() { + HashMap erc721tokens = new HashMap<>(); + HashMap erc1155tokens = new HashMap<>(); + + // multifaucetNFT + EVMERC721TokenInfo multifaucetNFT = new EVMERC721TokenInfo( + GoerliERC721Token.MFNFT.toString(), + "0xf5de760f2e916647fd766b4ad9e85ff943ce3a2b", + 0L, + "MultiFaucet NFT", + TokenCategory.DEFI.toString(), + EVMChain.GOERLITEST.toString(), + new ArrayList() {{ + this.add("https://goerli.etherscan.io/token/0xf5de760f2e916647fd766b4ad9e85ff943ce3a2b"); + }}); + erc721tokens.put(GoerliERC721Token.MFNFT.toString(), multifaucetNFT); + + return new EVMNFTIndex(erc721tokens, erc1155tokens); + } + + + @SuppressWarnings("serial") + public static ERC20TokenIndex generatePolygonTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // dquick + EVMERC20TokenInfo dquick = new EVMERC20TokenInfo( + PolygonERC20Token.dQUICK.toString(), + "0x958d208cdf087843e9ad98d23823d32e17d723a1", + "Dragon QUICK token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0x958d208cdf087843e9ad98d23823d32e17d723a1"); + this.add("https://www.coingecko.com/en/exchanges/quickswap"); + }}); + tokens.put(PolygonERC20Token.dQUICK.toString(), dquick); + + // maticx + EVMERC20TokenInfo maticx = new EVMERC20TokenInfo( + PolygonERC20Token.MATICX.toString(), + "0xfa68fb4628dff1028cfec22b4162fccd0d45efb6", + "Stader Liquid Staking Matic (PoS) token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0xfa68fb4628dff1028cfec22b4162fccd0d45efb6"); + this.add("https://www.coingecko.com/en/coins/stader-maticx"); + }}); + tokens.put(PolygonERC20Token.MATICX.toString(), maticx); + + // reth + EVMERC20TokenInfo reth = new EVMERC20TokenInfo( + PolygonERC20Token.rETH.toString(), + "0x0266f4f08d82372cf0fcbccc0ff74309089c74d1", + "Rocketpool ETH token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0x0266f4f08d82372cf0fcbccc0ff74309089c74d1"); + this.add("https://rocketpool.net/"); + }}); + tokens.put(PolygonERC20Token.rETH.toString(), reth); + + // virtuswap + EVMERC20TokenInfo virtuswap = new EVMERC20TokenInfo( + PolygonERC20Token.VRSW.toString(), + "0x57999936fc9a9ec0751a8d146cce11901be8bed0", + "Virtuswap token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0x57999936fc9a9ec0751a8d146cce11901be8bed0"); + }}); + tokens.put(PolygonERC20Token.VRSW.toString(), virtuswap); + + // bgem + EVMERC20TokenInfo bgem = new EVMERC20TokenInfo( + PolygonERC20Token.BGEM.toString(), + "0x1386617A1Bb2A6AA712AB3616bCAF1211152D1e8", + "BitGem gaming token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0x1386617A1Bb2A6AA712AB3616bCAF1211152D1e8"); + this.add("https://boomland.io/daily"); + }}); + tokens.put(PolygonERC20Token.BGEM.toString(), bgem); + + // ricochet WBTCx + EVMERC20TokenInfo ricochet_wbtcx = new EVMERC20TokenInfo( + PolygonERC20Token.RICOCHET_WBTCx.toString(), + "0x4086eBf75233e8492F1BCDa41C7f2A8288c2fB92", + "Ricochet WBTC token, WBTCx", + 18, + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0x4086eBf75233e8492F1BCDa41C7f2A8288c2fB92"); + this.add("https://docs.superfluid.finance/superfluid/developers/networks"); + }}); + tokens.put(PolygonERC20Token.RICOCHET_WBTCx.toString(), ricochet_wbtcx); + + // ricochet DAIx + EVMERC20TokenInfo ricochet_daix = new EVMERC20TokenInfo( + PolygonERC20Token.RICOCHET_DAIx.toString(), + "0x8f3cf7ad23cd3cadbd9735aff958023239c6a063", + "Ricochet DAI token, DAIx", + 18, + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0x8f3cf7ad23cd3cadbd9735aff958023239c6a063"); + this.add("https://docs.superfluid.finance/superfluid/developers/networks"); + }}); + tokens.put(PolygonERC20Token.RICOCHET_DAIx.toString(), ricochet_daix); + + // ricochet ETHx + EVMERC20TokenInfo ricochet_ethx = new EVMERC20TokenInfo( + PolygonERC20Token.RICOCHET_ETHx.toString(), + "0x27e1e4E6BC79D93032abef01025811B7E4727e85", + "Ricochet ETH token, ETHx", + 18, + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0x27e1e4E6BC79D93032abef01025811B7E4727e85"); + this.add("https://docs.superfluid.finance/superfluid/developers/networks"); + }}); + tokens.put(PolygonERC20Token.RICOCHET_ETHx.toString(), ricochet_ethx); + + // ricochet MATICx + EVMERC20TokenInfo ricochet_maticx = new EVMERC20TokenInfo( + PolygonERC20Token.RICOCHET_MATICx.toString(), + "0x3aD736904E9e65189c3000c7DD2c8AC8bB7cD4e3", + "Ricochet MATIC token, MATICx", + 18, + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0x3aD736904E9e65189c3000c7DD2c8AC8bB7cD4e3"); + this.add("https://docs.superfluid.finance/superfluid/developers/networks"); + }}); + tokens.put(PolygonERC20Token.RICOCHET_MATICx.toString(), ricochet_maticx); + + // ricochet USDCx + EVMERC20TokenInfo ricochet_usdcx = new EVMERC20TokenInfo( + PolygonERC20Token.RICOCHET_USDCx.toString(), + "0xcaa7349cea390f89641fe306d93591f87595dc1f", + "Ricochet USDC token, USDCx", + 18, // !!!!!!!! + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0xcaa7349cea390f89641fe306d93591f87595dc1f"); + this.add("https://docs.superfluid.finance/superfluid/developers/networks"); + }}); + tokens.put(PolygonERC20Token.RICOCHET_USDCx.toString(), ricochet_usdcx); + + // ricochet + EVMERC20TokenInfo ricochet = new EVMERC20TokenInfo( + PolygonERC20Token.RICOCHET.toString(), + "0x263026e7e53dbfdce5ae55ade22493f828922965", + "Ricochet reward token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x263026e7e53dbfdce5ae55ade22493f828922965"); + this.add("https://www.coingecko.com/en/coins/ricochet"); + }}); + tokens.put(PolygonERC20Token.RICOCHET.toString(), ricochet); + + // cxdoge + EVMERC20TokenInfo cxdoge = new EVMERC20TokenInfo( + PolygonERC20Token.CXDOGE.toString(), + "0x9bd9ad490dd3a52f096d229af4483b94d63be618", + "CelsiusX Wrapped DOGE token (wrecked)", + 18, + TokenCategory.WRECKED.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x9bd9ad490dd3a52f096d229af4483b94d63be618"); + this.add("https://www.coingecko.com/en/coins/celsiusx-wrapped-doge"); + }}); + tokens.put(PolygonERC20Token.CXDOGE.toString(), cxdoge); + + // synapse + EVMERC20TokenInfo syn = new EVMERC20TokenInfo( + PolygonERC20Token.SYNAPSE.toString(), + "0xf8f9efc0db77d8881500bb06ff5d6abc3070e695", + "Synapse Defi token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0xf8f9efc0db77d8881500bb06ff5d6abc3070e695"); + this.add("https://www.coingecko.com/en/coins/synapse"); + }}); + tokens.put(PolygonERC20Token.SYNAPSE.toString(), syn); + + // ghst + EVMERC20TokenInfo ghst = new EVMERC20TokenInfo( + PolygonERC20Token.GHST.toString(), + "0x385eeac5cb85a38a9a07a70c73e0a3271cfb54a7", + "Aavegotchi GHST game token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x385eeac5cb85a38a9a07a70c73e0a3271cfb54a7"); + this.add("https://www.coingecko.com/en/coins/aavegotchi"); + }}); + tokens.put(PolygonERC20Token.GHST.toString(), ghst); + + // tower + EVMERC20TokenInfo tower = new EVMERC20TokenInfo( + PolygonERC20Token.TOWER.toString(), + "0x2bc07124d8dac638e290f401046ad584546bc47b", + "Crazy Defense Heroes game token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x2bc07124d8dac638e290f401046ad584546bc47b"); + this.add("https://www.coingecko.com/en/coins/tower"); + }}); + tokens.put(PolygonERC20Token.TOWER.toString(), tower); + + + // lucha + EVMERC20TokenInfo lucha = new EVMERC20TokenInfo( + PolygonERC20Token.LUCHA.toString(), + "0x6749441fdc8650b5b5a854ed255c82ef361f1596", + "Luchadores game token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x6749441fdc8650b5b5a854ed255c82ef361f1596"); + this.add("https://www.coingecko.com/en/coins/lucha"); + }}); + tokens.put(PolygonERC20Token.LUCHA.toString(), lucha); + + // aghst + EVMERC20TokenInfo aghst = new EVMERC20TokenInfo( + PolygonERC20Token.AGHST.toString(), + "0x8eb270e296023e9d92081fdf967ddd7878724424", + "AAve Aavegotchi GHST game token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x8eb270e296023e9d92081fdf967ddd7878724424"); + this.add("https://www.coingecko.com/en/coins/aavegotchi"); + }}); + tokens.put(PolygonERC20Token.AGHST.toString(), aghst); + + // kek + EVMERC20TokenInfo kek = new EVMERC20TokenInfo( + PolygonERC20Token.KEK.toString(), + "0x42e5e06ef5b90fe15f853f59299fc96259209c5c", + "Aavegotchi KEK game token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x42e5e06ef5b90fe15f853f59299fc96259209c5c"); + this.add("https://www.coingecko.com/en/coins/aavegotchi-kek"); + }}); + tokens.put(PolygonERC20Token.KEK.toString(), kek); + + // gltr + EVMERC20TokenInfo gltr = new EVMERC20TokenInfo( + PolygonERC20Token.GLTR.toString(), + "0x3801c3b3b5c98f88a9c9005966aa96aa440b9afc", + "GAX Liquidity Token Reward, Aavegotchi game token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0x3801c3b3b5c98f88a9c9005966aa96aa440b9afc"); + this.add("https://www.coingecko.com/en/coins/gax-liquidity-token-reward"); + }}); + tokens.put(PolygonERC20Token.GLTR.toString(), gltr); + + // alpha + EVMERC20TokenInfo alpha = new EVMERC20TokenInfo( + PolygonERC20Token.ALPHA.toString(), + "0x6a3e7c3c6ef65ee26975b12293ca1aad7e1daed2", + "Aavegotchi ALPHA game token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x6a3e7c3c6ef65ee26975b12293ca1aad7e1daed2"); + this.add("https://www.coingecko.com/en/coins/aavegotchi-alpha"); + }}); + tokens.put(PolygonERC20Token.ALPHA.toString(), alpha); + + // fud + EVMERC20TokenInfo fud = new EVMERC20TokenInfo( + PolygonERC20Token.FUD.toString(), + "0x403e967b044d4be25170310157cb1a4bf10bdd0f", + "Aavegotchi FUD game token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x403e967b044d4be25170310157cb1a4bf10bdd0f"); + this.add("https://www.coingecko.com/en/coins/aavegotchi-fud"); + }}); + tokens.put(PolygonERC20Token.FUD.toString(), fud); + + // fomo + EVMERC20TokenInfo fomo = new EVMERC20TokenInfo( + PolygonERC20Token.FOMO.toString(), + "0x44a6e0be76e1d9620a7f76588e4509fe4fa8e8c8", + "Aavegotchi FOMO game token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x44a6e0be76e1d9620a7f76588e4509fe4fa8e8c8"); + this.add("https://www.coingecko.com/en/coins/aavegotchi-fomo"); + }}); + tokens.put(PolygonERC20Token.FOMO.toString(), fomo); + + // sand + EVMERC20TokenInfo sand = new EVMERC20TokenInfo( + PolygonERC20Token.SAND.toString(), + "0xbbba073c31bf03b8acf7c28ef0738decf3695683", + "The Sandbox SAND game token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0xbbba073c31bf03b8acf7c28ef0738decf3695683"); + this.add("https://www.coingecko.com/en/coins/the-sandbox"); + }}); + tokens.put(PolygonERC20Token.SAND.toString(), sand); + + // modefi + EVMERC20TokenInfo modefi = new EVMERC20TokenInfo( + PolygonERC20Token.MOD.toString(), + "0x8346ab8d5ea7a9db0209aed2d1806afa0e2c4c21", + "MOD token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://www.coingecko.com/en/coins/modefi"); + this.add("https://polygonscan.com/token/0x8346ab8d5ea7a9db0209aed2d1806afa0e2c4c21"); + this.add("https://modefi.io/"); + }}); + tokens.put(PolygonERC20Token.MOD.toString(), modefi); + + // idex + EVMERC20TokenInfo idex = new EVMERC20TokenInfo( + PolygonERC20Token.IDEX.toString(), + "0x9cb74c8032b007466865f060ad2c46145d45553d", + "IDEX token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0x9cb74c8032b007466865f060ad2c46145d45553d"); + }}); + tokens.put(PolygonERC20Token.IDEX.toString(), idex); + + // titan + EVMERC20TokenInfo titan = new EVMERC20TokenInfo( + PolygonERC20Token.TITAN.toString(), + "0xaaa5b9e6c589642f98a1cda99b9d024b8407285a", + "IRON TITAN scam token", + 18, + TokenCategory.SCAM.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0xaaa5b9e6c589642f98a1cda99b9d024b8407285a"); + }}); + tokens.put(PolygonERC20Token.TITAN.toString(), titan); + + // stg + EVMERC20TokenInfo stg = new EVMERC20TokenInfo( + PolygonERC20Token.STG.toString(), + "0x2f6f07cdcf3588944bf4c42ac74ff24bf56e7590", + "StarGate token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0x2f6f07cdcf3588944bf4c42ac74ff24bf56e7590"); + this.add("https://www.coingecko.com/en/coins/stargate-finance"); + }}); + tokens.put(PolygonERC20Token.STG.toString(), stg); + + // wmatic/ghst quickswap LP + EVMERC20TokenInfo quickswap_awmatic_ghst_lp = new EVMERC20TokenInfo( + PolygonERC20Token.QUICKSWAP_aWMATIC_GHST_LP.toString(), + "0x2ef46196d7d25b5111ca1fcba206b248fee32d8d", + "WMATIC/GHST Quickswap Pool token", + 18, + TokenCategory.LIQUIDITY_PROVIDER.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0x2ef46196d7d25b5111ca1fcba206b248fee32d8d"); + }}); + tokens.put(PolygonERC20Token.QUICKSWAP_aWMATIC_GHST_LP.toString(), quickswap_awmatic_ghst_lp); + + // usdc stargate LP // staking contract: https://polygonscan.com/address/0x8731d54e9d02c286767d56ac03e8037c07e01e98#code + EVMERC20TokenInfo susdc = new EVMERC20TokenInfo( + PolygonERC20Token.STARGATE_USDC_LP.toString(), + "0x1205f31718499dbf1fca446663b532ef87481fe1", + "StarGate USDC Pool token", + 6, + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0x1205f31718499dbf1fca446663b532ef87481fe1"); + }}); + tokens.put(PolygonERC20Token.STARGATE_USDC_LP.toString(), susdc); + + // link + EVMERC20TokenInfo link = new EVMERC20TokenInfo( + PolygonERC20Token.LINK.toString(), + "0x53e0bca35ec356bd5dddfebbd1fc0fd03fabad39", + "LINK token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x53e0bca35ec356bd5dddfebbd1fc0fd03fabad39"); + this.add("https://www.coingecko.com/en/coins/chainlink"); + }}); + tokens.put(PolygonERC20Token.LINK.toString(), link); + + // amlink + EVMERC20TokenInfo amlink = new EVMERC20TokenInfo( + PolygonERC20Token.amLINK.toString(), + "0x0ca2e42e8c21954af73bc9af1213e4e81d6a669a", + "Aave LINK token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0x0ca2e42e8c21954af73bc9af1213e4e81d6a669a"); + this.add("https://www.coingecko.com/en/coins/chainlink"); + }}); + tokens.put(PolygonERC20Token.amLINK.toString(), amlink); + + // amwmatic + EVMERC20TokenInfo amwmatic = new EVMERC20TokenInfo( + PolygonERC20Token.amWMATIC.toString(), + "0x8df3aad3a84da6b69a4da8aec3ea40d9091b2ac4", + "Aave WMATIC token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0x8df3aad3a84da6b69a4da8aec3ea40d9091b2ac4"); + this.add("https://www.coingecko.com/en/coins/aave-polygon-wmatic"); + }}); + tokens.put(PolygonERC20Token.amWMATIC.toString(), amwmatic); + + // wmatic + EVMERC20TokenInfo wmatic = new EVMERC20TokenInfo( + PolygonERC20Token.WMATIC.toString(), + "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270", + "WMATIC token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270"); + this.add("https://www.coingecko.com/en/coins/wmatic"); + }}); + tokens.put(PolygonERC20Token.WMATIC.toString(), wmatic); + + // weth + EVMERC20TokenInfo weth = new EVMERC20TokenInfo( + PolygonERC20Token.WETH.toString(), + "0x7ceb23fd6bc0add59e62ac25578270cff1b9f619", + "Wrapped ETH token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0x7ceb23fd6bc0add59e62ac25578270cff1b9f619"); + this.add("https://www.coingecko.com/en/coins/weth"); + }}); + tokens.put(PolygonERC20Token.WETH.toString(), weth); + + // usdc + EVMERC20TokenInfo usdc = new EVMERC20TokenInfo( + PolygonERC20Token.USDC.toString(), + "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", + "USDC stablecoin token", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x2791bca1f2de4661ed88a30c99a7a9449aa84174"); + this.add("https://www.coingecko.com/en/coins/usd-coin"); + }}); + tokens.put(PolygonERC20Token.USDC.toString(), usdc); + + // dai + EVMERC20TokenInfo dai = new EVMERC20TokenInfo( + PolygonERC20Token.DAI.toString(), + "0x8f3cf7ad23cd3cadbd9735aff958023239c6a063", + "DAI stablecoin token", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x8f3cf7ad23cd3cadbd9735aff958023239c6a063"); + this.add("https://www.coingecko.com/en/coins/dai"); + }}); + tokens.put(PolygonERC20Token.DAI.toString(), dai); + + EVMERC20TokenInfo gdai = new EVMERC20TokenInfo( + PolygonERC20Token.gDAI.toString(), + "0x91993f2101cc758d0deb7279d41e880f7defe827", + "GAINS Network DAI token", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0x91993f2101cc758d0deb7279d41e880f7defe827"); + }}); + tokens.put(PolygonERC20Token.gDAI.toString(), gdai); + + // usdt + EVMERC20TokenInfo usdt = new EVMERC20TokenInfo( + PolygonERC20Token.USDT.toString(), + "0xc2132d05d31c914a87c6611c10748aeb04b58e8f", + "Tether stablecoin token", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/address/0xc2132d05d31c914a87c6611c10748aeb04b58e8f"); + this.add("https://www.coingecko.com/en/coins/tether"); + }}); + tokens.put(PolygonERC20Token.USDT.toString(), usdt); + + // roll + EVMERC20TokenInfo roll = new EVMERC20TokenInfo( + PolygonERC20Token.ROLL.toString(), + "0xC68e83a305b0FaD69E264A1769a0A070F190D2d6", + "ROLL SCAM token", + 18, + TokenCategory.DUST.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0xc68e83a305b0fad69e264a1769a0a070f190d2d6#comments"); + this.add("https://polyroll.org/"); + }}); + tokens.put(PolygonERC20Token.ROLL.toString(), roll); + + // Sandbox WMATIC+SAND LP Token + EVMERC20TokenInfo sandbox_wmatic_sand_lp = new EVMERC20TokenInfo( + PolygonERC20Token.SANDBOX_WMATIC_SAND_LP.toString(), + "0x4ab071c42c28c4858c4bac171f06b13586b20f30", + "Sandbox WMATIC+SAND LP Token", + 18, + TokenCategory.LIQUIDITY_PROVIDER.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0x4ab071c42c28c4858c4bac171f06b13586b20f30"); + this.add("https://medium.com/sandbox-game/introducing-msand-matic-staking-at-the-sandbox-319f983d20a4"); + }}); + tokens.put(PolygonERC20Token.SANDBOX_WMATIC_SAND_LP.toString(), sandbox_wmatic_sand_lp); + + // test + EVMERC20TokenInfo test = new EVMERC20TokenInfo( + PolygonERC20Token.TEST.toString(), + "0x23D29D30e35C5e8D321e1dc9A8a61BFD846D4C5C", + //"0x23D29D30e35C5e8D321e1dc9A8a61BFD846D4C5C", // HEX :) + "TEST token", + 18, + TokenCategory.TEST.toString(), + EVMChain.POLYGON.toString(), + new ArrayList() {{ + this.add("https://polygonscan.com/token/0xMOJO"); + }}); + tokens.put(PolygonERC20Token.TEST.toString(), test); + + return new ERC20TokenIndex(tokens); + } + + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateArbitrumONETokenIndex() { + + HashMap tokens = new HashMap<>(); + + // reth + EVMERC20TokenInfo reth = new EVMERC20TokenInfo( + ArbitrumONEERC20Token.rETH.toString(), + "0xEC70Dcb4A1EFa46b8F2D97C310C9c4790ba5ffA8", + "Rocketpool ETH token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.ARBITRUMONE.toString(), + new ArrayList() {{ + this.add("https://arbiscan.io/address/0xec70dcb4a1efa46b8f2d97c310c9c4790ba5ffa8"); + this.add("https://rocketpool.net/"); + }}); + tokens.put(ArbitrumONEERC20Token.rETH.toString(), reth); + + // magic + EVMERC20TokenInfo magic = new EVMERC20TokenInfo( + ArbitrumONEERC20Token.MAGIC.toString(), + "0x539bde0d7dbd336b79148aa742883198bbf60342", + "MAGIC gaming token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.ARBITRUMONE.toString(), + new ArrayList() {{ + this.add("https://arbiscan.io/address/0x539bde0d7dbd336b79148aa742883198bbf60342"); + this.add("https://www.coingecko.com/en/coins/magic"); + }}); + tokens.put(ArbitrumONEERC20Token.MAGIC.toString(), magic); + + // usdce + EVMERC20TokenInfo usdce = new EVMERC20TokenInfo( + ArbitrumONEERC20Token.USDCe.toString(), + "0xff970a61a04b1ca14834a43f5de4533ebddb5cc8", + "Bridged USDC stablecoin token (USDC.e)", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.ARBITRUMONE.toString(), + new ArrayList() {{ + this.add("https://arbiscan.io/address/0xff970a61a04b1ca14834a43f5de4533ebddb5cc8"); + this.add("https://www.coingecko.com/en/coins/usd-coin-ethereum-bridged"); + }}); + tokens.put(ArbitrumONEERC20Token.USDCe.toString(), usdce); + + // usdc + EVMERC20TokenInfo usdc = new EVMERC20TokenInfo( + ArbitrumONEERC20Token.USDC.toString(), + "0xaf88d065e77c8cc2239327c5edb3a432268e5831", + "USDC stablecoin token", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.ARBITRUMONE.toString(), + new ArrayList() {{ + this.add("https://arbiscan.io/address/0xaf88d065e77c8cc2239327c5edb3a432268e5831"); + this.add("https://www.coingecko.com/en/coins/usd-coin"); + }}); + tokens.put(ArbitrumONEERC20Token.USDC.toString(), usdc); + + + // dai + EVMERC20TokenInfo dai = new EVMERC20TokenInfo( + ArbitrumONEERC20Token.DAI.toString(), + "0xda10009cbd5d07dd0cecc66161fc93d7c9000da1", + "DAI stablecoin token", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.ARBITRUMONE.toString(), + new ArrayList() {{ + this.add("https://arbiscan.io/address/0xda10009cbd5d07dd0cecc66161fc93d7c9000da1"); + this.add("https://www.coingecko.com/en/coins/dai"); + }}); + tokens.put(ArbitrumONEERC20Token.DAI.toString(), dai); + + // bal + EVMERC20TokenInfo bal = new EVMERC20TokenInfo( + ArbitrumONEERC20Token.BAL.toString(), + "0x040d1edc9569d4bab2d15287dc5a4f10f56a56b8", + "Balancer DEFI GOV token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.ARBITRUMONE.toString(), + new ArrayList() {{ + this.add("https://arbiscan.io/token/0x040d1edc9569d4bab2d15287dc5a4f10f56a56b8"); + }}); + tokens.put(ArbitrumONEERC20Token.BAL.toString(), bal); + + // arb + EVMERC20TokenInfo arb = new EVMERC20TokenInfo( + ArbitrumONEERC20Token.ARBITRUM.toString(), + "0x912ce59144191c1204e64559fe8253a0e49e6548", + "Arbitrum GOV token", + 18, + TokenCategory.GOVERNANCE.toString(), + EVMChain.ARBITRUMONE.toString(), + new ArrayList() {{ + this.add("https://arbiscan.io/address/0x912ce59144191c1204e64559fe8253a0e49e6548"); + }}); + tokens.put(ArbitrumONEERC20Token.ARBITRUM.toString(), arb); + + // bal_5050_magic_usdc_lp + EVMERC20TokenInfo bal_5050_magic_usdc_lp = new EVMERC20TokenInfo( + ArbitrumONEERC20Token.BAL_MAGICUSDC_LP.toString(), + "0xb3028ca124b80cfe6e9ca57b70ef2f0ccc41ebd4", + "Balancer 50/50 MAGIC/USDC LP token", + 18, + TokenCategory.LIQUIDITY_PROVIDER.toString(), + EVMChain.ARBITRUMONE.toString(), + new ArrayList() {{ + this.add("https://arbiscan.io/token/0xb3028ca124b80cfe6e9ca57b70ef2f0ccc41ebd4"); + }}); + tokens.put(ArbitrumONEERC20Token.BAL_MAGICUSDC_LP.toString(), bal_5050_magic_usdc_lp); + + // gdai + EVMERC20TokenInfo gdai = new EVMERC20TokenInfo( + ArbitrumONEERC20Token.gDAI.toString(), + "0xd85E038593d7A098614721EaE955EC2022B9B91B", + "GAINS Network DAI token", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.ARBITRUMONE.toString(), + new ArrayList() {{ + this.add("https://arbiscan.io/address/0xd85e038593d7a098614721eae955ec2022b9b91b"); + }}); + tokens.put(ArbitrumONEERC20Token.gDAI.toString(), gdai); + + // usdt + EVMERC20TokenInfo usdt = new EVMERC20TokenInfo( + ArbitrumONEERC20Token.USDT.toString(), + "0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9", + "Tether stablecoin token", + 6, // !!!!! + TokenCategory.STABLECOIN.toString(), + EVMChain.ARBITRUMONE.toString(), + new ArrayList() {{ + this.add("https://arbiscan.io/address/0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9"); + this.add("https://www.coingecko.com/en/coins/tether"); + }}); + tokens.put(ArbitrumONEERC20Token.USDT.toString(), usdt); + + // gns + EVMERC20TokenInfo gns = new EVMERC20TokenInfo( + ArbitrumONEERC20Token.GNS.toString(), + "0x18c11fd286c5ec11c3b683caa813b77f5163a122", + "Gains token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.ARBITRUMONE.toString(), + new ArrayList() {{ + this.add("https://arbiscan.io/address/0x18c11fd286c5ec11c3b683caa813b77f5163a122"); + this.add("https://www.coingecko.com/en/coins/gains-network"); + }}); + tokens.put(ArbitrumONEERC20Token.GNS.toString(), gns); + + // gmx + EVMERC20TokenInfo gmx = new EVMERC20TokenInfo( + ArbitrumONEERC20Token.GMX.toString(), + "0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a", + "GMX token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.ARBITRUMONE.toString(), + new ArrayList() {{ + this.add("https://arbiscan.io/address/0xfc5a1a6eb076a2c7ad06ed22c90d7e710e35ad0a"); + this.add("https://www.coingecko.com/en/coins/gmx"); + }}); + tokens.put(ArbitrumONEERC20Token.GMX.toString(), gmx); + + // dmt + EVMERC20TokenInfo dmt = new EVMERC20TokenInfo( + ArbitrumONEERC20Token.DMT.toString(), + "0x8b0e6f19ee57089f7649a455d89d7bc6314d04e8", + "DMT gaming token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.ARBITRUMONE.toString(), + new ArrayList() {{ + this.add("https://arbiscan.io/token/0x8b0e6f19ee57089f7649a455d89d7bc6314d04e8"); + this.add("https://www.coingecko.com/en/coins/dream-machine-token"); + }}); + tokens.put(ArbitrumONEERC20Token.DMT.toString(), dmt); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateWemixTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // klay + EVMERC20TokenInfo klay = new EVMERC20TokenInfo( + WemixERC20Token.KLAY.toString(), + "0x461d52769884ca6235B685EF2040F47d30C94EB5", + "Wrapped KLAY token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.WEMIX.toString(), + new ArrayList() {{ + this.add("https://explorer.wemix.com/address/0x461d52769884ca6235B685EF2040F47d30C94EB5"); + }}); + tokens.put(WemixERC20Token.KLAY.toString(), klay); + + // wemix $ + EVMERC20TokenInfo wemix$ = new EVMERC20TokenInfo( + WemixERC20Token.WEMIX$.toString(), + "0x8e81fcc2d4a3baa0ee9044e0d7e36f59c9bba9c1", + "WEMIX USD token", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.WEMIX.toString(), + new ArrayList() {{ + this.add("https://explorer.wemix.com/token/0x8e81fcc2d4a3baa0ee9044e0d7e36f59c9bba9c1/transfers"); + }}); + tokens.put(WemixERC20Token.WEMIX$.toString(), wemix$); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateMilkomedaC1TokenIndex() { + + HashMap tokens = new HashMap<>(); + + // wada + EVMERC20TokenInfo wada = new EVMERC20TokenInfo( + MilkomedaC1ERC20Token.WADA.toString(), + "0xAE83571000aF4499798d1e3b0fA0070EB3A3E3F9", + "Wrapped ADA token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.MILKOMEDAC1.toString(), + new ArrayList() {{ + this.add("https://explorer-mainnet-cardano-evm.c1.milkomeda.com/address/0xAE83571000aF4499798d1e3b0fA0070EB3A3E3F9"); + }}); + tokens.put(MilkomedaC1ERC20Token.WADA.toString(), wada); + + // blues + EVMERC20TokenInfo blues = new EVMERC20TokenInfo( + MilkomedaC1ERC20Token.BLUES.toString(), + "0x8c008BBA2Dd56b99f4A6aB276bE3a478cB075F0C", + "Blueshift token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.MILKOMEDAC1.toString(), + new ArrayList() {{ + this.add("https://explorer-mainnet-cardano-evm.c1.milkomeda.com/address/0x8c008BBA2Dd56b99f4A6aB276bE3a478cB075F0C"); + }}); + tokens.put(MilkomedaC1ERC20Token.BLUES.toString(), blues); + + // Blueshift LP Token 006 + EVMERC20TokenInfo blueshift_lp_006 = new EVMERC20TokenInfo( + MilkomedaC1ERC20Token.BLUESHIFT_mADA_BLUES_LP.toString(), + "0x4a2360fD03eD50C9496cbEB4FD3e1776FA90F04c", + "Blueshift LP 006 (mADA/BLUES) token", + 18, + TokenCategory.LIQUIDITY_PROVIDER.toString(), + EVMChain.MILKOMEDAC1.toString(), + new ArrayList() {{ + this.add("https://explorer-mainnet-cardano-evm.c1.milkomeda.com/address/0x4a2360fD03eD50C9496cbEB4FD3e1776FA90F04c"); + }}); + tokens.put(MilkomedaC1ERC20Token.BLUESHIFT_mADA_BLUES_LP.toString(), blueshift_lp_006); + + + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateMilkomedaA1TokenIndex() { + + HashMap tokens = new HashMap<>(); + + // usdc + EVMERC20TokenInfo usdc = new EVMERC20TokenInfo( + MilkomedaA1ERC20Token.USDC.toString(), + "0xBc31960A049Fe10297Ed8432Fb61DD734fEAd4ea", + "USDC stable token", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.MILKOMEDAA1.toString(), + new ArrayList() {{ + this.add("https://explorer-mainnet-algorand-rollup.a1.milkomeda.com/address/0xBc31960A049Fe10297Ed8432Fb61DD734fEAd4ea"); + }}); + tokens.put(MilkomedaA1ERC20Token.USDC.toString(), usdc); + + // blues + EVMERC20TokenInfo blues = new EVMERC20TokenInfo( + MilkomedaA1ERC20Token.USDC.toString(), + "0xc9BAA8cfdDe8E328787E29b4B078abf2DaDc2055", + "BlueShift DEFI token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.MILKOMEDAA1.toString(), + new ArrayList() {{ + this.add("https://explorer-mainnet-algorand-rollup.a1.milkomeda.com/address/0xc9BAA8cfdDe8E328787E29b4B078abf2DaDc2055"); + }}); + tokens.put(MilkomedaA1ERC20Token.BLUES.toString(), blues); + + return new ERC20TokenIndex(tokens); + } + + public static String generateTokenIndexJSON(ERC20TokenIndex idx) { + return JSONUtils.createJSONFromPOJO(idx); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateZkSyncTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // zkusd + EVMERC20TokenInfo zkusd = new EVMERC20TokenInfo( + ZkSyncERC20Token.zkUSD.toString(), + "0xfC7E56298657B002b3e656400E746b7212912757", + "zkUSD stablecoin token", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.ZKSYNCERA.toString(), + new ArrayList() {{ + this.add("https://explorer.zksync.io/address/0xfC7E56298657B002b3e656400E746b7212912757"); + }}); + tokens.put(ZkSyncERC20Token.zkUSD.toString(), zkusd); + + // usdc + EVMERC20TokenInfo usdc = new EVMERC20TokenInfo( + ZkSyncERC20Token.USDC.toString(), + "0x3355df6D4c9C3035724Fd0e3914dE96A5a83aaf4", + "USDC stablecoin token", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.ZKSYNCERA.toString(), + new ArrayList() {{ + this.add("https://explorer.zksync.io/address/0x3355df6D4c9C3035724Fd0e3914dE96A5a83aaf4"); + this.add("https://www.coingecko.com/en/coins/usd-coin"); + }}); + tokens.put(ZkSyncERC20Token.USDC.toString(), usdc); + + // mute + EVMERC20TokenInfo mute = new EVMERC20TokenInfo( + ZkSyncERC20Token.MUTE.toString(), + "0x0e97C7a0F8B2C9885C8ac9fC6136e829CbC21d42", + "MUTE token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.ZKSYNCERA.toString(), + new ArrayList() {{ + this.add("https://explorer.zksync.io/address/0x0e97C7a0F8B2C9885C8ac9fC6136e829CbC21d42"); + this.add("https://www.coingecko.com/en/coins/mute"); + }}); + tokens.put(ZkSyncERC20Token.MUTE.toString(), mute); + + // ysync + EVMERC20TokenInfo ysync = new EVMERC20TokenInfo( + ZkSyncERC20Token.YSYNC.toString(), + "0xE0eF1c039a36eC77339E7277ECd4D48e57b61eec", + "YSYNC token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.ZKSYNCERA.toString(), + new ArrayList() {{ + this.add("https://explorer.zksync.io/address/0xE0eF1c039a36eC77339E7277ECd4D48e57b61eec"); + this.add("https://syncswap.xyz"); + }}); + tokens.put(ZkSyncERC20Token.YSYNC.toString(), ysync); + + // syncswap_lp_usdc_weth + EVMERC20TokenInfo syncswap_lp_usdc_weth = new EVMERC20TokenInfo( + ZkSyncERC20Token.SYNCSWAP_USDC_WETH_LP.toString(), + "0x80115c708E12eDd42E504c1cD52Aea96C547c05c", + "Syncswap USDC/WETH LP position", + 18, + TokenCategory.DEFI.toString(), + EVMChain.ZKSYNCERA.toString(), + new ArrayList() {{ + this.add("https://explorer.zksync.io/address/0x80115c708E12eDd42E504c1cD52Aea96C547c05c"); + this.add("https://syncswap.xyz"); + }}); + tokens.put(ZkSyncERC20Token.SYNCSWAP_USDC_WETH_LP.toString(), syncswap_lp_usdc_weth); + + // furucombo + EVMERC20TokenInfo furucombo = new EVMERC20TokenInfo( + ZkSyncERC20Token.COMBO.toString(), + "0xc2B13Bb90E33F1E191b8aA8F44Ce11534D5698E3", + "COMBO token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.ZKSYNCERA.toString(), + new ArrayList() {{ + this.add("https://explorer.zksync.io/address/0xc2B13Bb90E33F1E191b8aA8F44Ce11534D5698E3"); + this.add("https://www.coingecko.com/en/coins/furucombo"); + }}); + tokens.put(ZkSyncERC20Token.COMBO.toString(), furucombo); + + // perp + EVMERC20TokenInfo perp = new EVMERC20TokenInfo( + ZkSyncERC20Token.PERP.toString(), + "0x42c1c56be243c250AB24D2ecdcC77F9cCAa59601", + "PERP token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.ZKSYNCERA.toString(), + new ArrayList() {{ + this.add("https://explorer.zksync.io/address/0x42c1c56be243c250AB24D2ecdcC77F9cCAa59601"); + this.add("https://www.coingecko.com/en/coins/perpetual-protocol"); + }}); + tokens.put(ZkSyncERC20Token.PERP.toString(), perp); + + // zat + EVMERC20TokenInfo zat = new EVMERC20TokenInfo( + ZkSyncERC20Token.ZAT.toString(), + "0x47EF4A5641992A72CFd57b9406c9D9cefEE8e0C4", + "zkApes token", + 18, + TokenCategory.GAMING.toString(), + EVMChain.ZKSYNCERA.toString(), + new ArrayList() {{ + this.add("https://explorer.zksync.io/address/0x47EF4A5641992A72CFd57b9406c9D9cefEE8e0C4"); + this.add("https://zkape.io"); + }}); + tokens.put(ZkSyncERC20Token.ZAT.toString(), zat); + + // velocore + EVMERC20TokenInfo vc = new EVMERC20TokenInfo( + ZkSyncERC20Token.VC.toString(), + "0x99bBE51be7cCe6C8b84883148fD3D12aCe5787F2", + "Velocore token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.ZKSYNCERA.toString(), + new ArrayList() {{ + this.add("https://explorer.zksync.io/address/0x99bBE51be7cCe6C8b84883148fD3D12aCe5787F2"); + this.add("https://zksync-v2.velocore.xyz"); + }}); + tokens.put(ZkSyncERC20Token.VC.toString(), vc); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateMoonbeamTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // mGLMR + EVMERC20TokenInfo moonwell_glmr = new EVMERC20TokenInfo( + MoonbeamERC20Token.mGLMR.toString(), + "0x091608f4e4a15335145be0A279483C0f8E4c7955", + "Moonwell GLMR token", + 8, + TokenCategory.DEFI.toString(), + EVMChain.MOONBEAM.toString(), + new ArrayList() {{ + this.add("https://moonscan.io/token/0x091608f4e4a15335145be0a279483c0f8e4c7955"); + this.add("https://moonwell.fi/artemis/GLMR"); + }}); + tokens.put(MoonbeamERC20Token.mGLMR.toString(), moonwell_glmr); + + // well + EVMERC20TokenInfo well = new EVMERC20TokenInfo( + MoonbeamERC20Token.WELL.toString(), + "0x511ab53f793683763e5a8829738301368a2411e3", + "Moonwell WELL token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.MOONBEAM.toString(), + new ArrayList() {{ + this.add("https://moonscan.io/address/0x511ab53f793683763e5a8829738301368a2411e3"); + this.add("https://www.coingecko.com/en/coins/moonwell"); + }}); + tokens.put(MoonbeamERC20Token.WELL.toString(), well); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generatePulsechainTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // plsx + EVMERC20TokenInfo plsx = new EVMERC20TokenInfo( + PulsechainERC20Token.PLSX.toString(), + "0x95B303987A60C71504D99Aa1b13B4DA07b0790ab", + "Pulsechain PLSX token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.PULSECHAIN.toString(), + new ArrayList() {{ + this.add("https://scan.pulsechain.com/address/0x95B303987A60C71504D99Aa1b13B4DA07b0790ab"); + }}); + tokens.put(PulsechainERC20Token.PLSX.toString(), plsx); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateLineaTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // weth + EVMERC20TokenInfo weth = new EVMERC20TokenInfo( + LineaERC20Token.WETH.toString(), + "0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f", + "WETH token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.LINEA.toString(), + new ArrayList() {{ + this.add("https://lineascan.build/address/0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f"); + }}); + tokens.put(LineaERC20Token.WETH.toString(), weth); + + // matic + EVMERC20TokenInfo matic = new EVMERC20TokenInfo( + LineaERC20Token.MATIC.toString(), + "0x265b25e22bcd7f10a5bd6e6410f10537cc7567e8", + "MATIC token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.LINEA.toString(), + new ArrayList() {{ + this.add("https://lineascan.build/token/0x265b25e22bcd7f10a5bd6e6410f10537cc7567e8"); + }}); + tokens.put(LineaERC20Token.MATIC.toString(), matic); + + // USDC + EVMERC20TokenInfo usdc = new EVMERC20TokenInfo( + LineaERC20Token.USDC.toString(), + "0x176211869ca2b568f2a7d4ee941e073a821ee1ff", + "USDC stable token", + 6, + TokenCategory.DEFI.toString(), + EVMChain.LINEA.toString(), + new ArrayList() {{ + this.add("https://lineascan.build/token/0x176211869ca2b568f2a7d4ee941e073a821ee1ff"); + }}); + tokens.put(LineaERC20Token.USDC.toString(), usdc); + + // LVC + EVMERC20TokenInfo lvc = new EVMERC20TokenInfo( + LineaERC20Token.LVC.toString(), + "0xcc22f6aa610d1b2a0e89ef228079cb3e1831b1d1", + "Velocore token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.LINEA.toString(), + new ArrayList() {{ + this.add("https://lineascan.build/token/0xcc22f6aa610d1b2a0e89ef228079cb3e1831b1d1"); + }}); + tokens.put(LineaERC20Token.LVC.toString(), lvc); + + // veLVC + EVMERC20TokenInfo velvc = new EVMERC20TokenInfo( + LineaERC20Token.veLVC.toString(), + "0xaec06345b26451bda999d83b361beaad6ea93f87", + "Locked Velocore token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.LINEA.toString(), + new ArrayList() {{ + this.add("https://lineascan.build/token/0xaec06345b26451bda999d83b361beaad6ea93f87"); + }}); + tokens.put(LineaERC20Token.veLVC.toString(), velvc); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateKavaTestTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // usdc + EVMERC20TokenInfo usdc = new EVMERC20TokenInfo( + KavaTestERC20Token.USDC.toString(), + "0x43D8814FdFB9B8854422Df13F1c66e34E4fa91fD", + "USDC token", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.KAVATEST.toString(), + new ArrayList() {{ + this.add("https://explorer.testnet.kava.io/address/0x43D8814FdFB9B8854422Df13F1c66e34E4fa91fD"); + }}); + tokens.put(KavaTestERC20Token.USDC.toString(), usdc); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateOptimismTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // SNX + EVMERC20TokenInfo snx = new EVMERC20TokenInfo( + OptimismERC20Token.SNX.toString(), + "0x8700daec35af8ff88c16bdf0418774cb3d7599b4", + "SNX token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.OPTIMISM.toString(), + new ArrayList() {{ + this.add("https://optimistic.etherscan.io/token/0x8700daec35af8ff88c16bdf0418774cb3d7599b4"); + }}); + tokens.put(OptimismERC20Token.SNX.toString(), snx); + + // SDS + EVMERC20TokenInfo sds = new EVMERC20TokenInfo( + OptimismERC20Token.SDS.toString(), + "0x45c55bf488d3cb8640f12f63cbedc027e8261e79", + "Synthetix Debt Shares token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.OPTIMISM.toString(), + new ArrayList() {{ + this.add("https://optimistic.etherscan.io/token/0x45c55bf488d3cb8640f12f63cbedc027e8261e79"); + }}); + tokens.put(OptimismERC20Token.SDS.toString(), sds); + + // SNX + EVMERC20TokenInfo susd = new EVMERC20TokenInfo( + OptimismERC20Token.SUSD.toString(), + "0x8c6f28f2f1a3c87f0f938b96d27520d9751ec8d9", + "sUSD stablecoin token", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.OPTIMISM.toString(), + new ArrayList() {{ + this.add("https://optimistic.etherscan.io/token/0x8c6f28f2f1a3c87f0f938b96d27520d9751ec8d9"); + }}); + tokens.put(OptimismERC20Token.SUSD.toString(), susd); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateConfluxTestnetTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // USDT + EVMERC20TokenInfo usdt = new EVMERC20TokenInfo( + ConfluxTestnetERC20Token.USDT.toString(), + "0x7d682e65efc5c13bf4e394b8f376c48e6bae0355", + "Tether stable coin", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.CONFLUXTEST.toString(), + new ArrayList() {{ + this.add("https://evmtestnet.confluxscan.net/address/0x7d682e65efc5c13bf4e394b8f376c48e6bae0355"); + }}); + tokens.put(ConfluxTestnetERC20Token.USDT.toString(), usdt); + + // VST + EVMERC20TokenInfo vswap = new EVMERC20TokenInfo( + ConfluxTestnetERC20Token.VSWAP.toString(), + "0x2c0230516cfcddcd2a5256400c4593deaa243259", + "Vswap token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.CONFLUXTEST.toString(), + new ArrayList() {{ + this.add("https://evmtestnet.confluxscan.io/address/0x2c0230516cfcddcd2a5256400c4593deaa243259"); + this.add("https://app-testnet.vswap.finance"); + }}); + tokens.put(ConfluxTestnetERC20Token.VSWAP.toString(), vswap); + + // WETH + EVMERC20TokenInfo weth = new EVMERC20TokenInfo( + ConfluxTestnetERC20Token.WETH.toString(), + "0xcd71270f82f319e0498ff98af8269c3f0d547c65", + "Wrapped ETH token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.CONFLUXTEST.toString(), + new ArrayList() {{ + this.add("https://evmtestnet.confluxscan.io/address/0xcd71270f82f319e0498ff98af8269c3f0d547c65"); + }}); + tokens.put(ConfluxTestnetERC20Token.WETH.toString(), weth); + + // USDC + EVMERC20TokenInfo usdc = new EVMERC20TokenInfo( + ConfluxTestnetERC20Token.USDC.toString(), + "0x349298b0e20df67defd6efb8f3170cf4a32722ef", + "USDC stable coin", + 18, // !!! + TokenCategory.STABLECOIN.toString(), + EVMChain.CONFLUXTEST.toString(), + new ArrayList() {{ + this.add("https://evmtestnet.confluxscan.io/address/0x349298b0e20df67defd6efb8f3170cf4a32722ef"); + }}); + tokens.put(ConfluxTestnetERC20Token.USDC.toString(), usdc); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateConfluxTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // USDT + EVMERC20TokenInfo usdt = new EVMERC20TokenInfo( + ConfluxERC20Token.USDT.toString(), + "0xfe97e85d13abd9c1c33384e796f10b73905637ce", + "Tether stable token", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.CONFLUX.toString(), + new ArrayList() {{ + this.add("https://evm.confluxscan.io/token/0xfe97e85d13abd9c1c33384e796f10b73905637ce"); + }}); + tokens.put(ConfluxERC20Token.USDT.toString(), usdt); + + // WCFX + EVMERC20TokenInfo wcfx = new EVMERC20TokenInfo( + ConfluxERC20Token.WCFX.toString(), + "0x14b2d3bc65e74dae1030eafd8ac30c533c976a9b", + "Wrapped Conflux token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.CONFLUX.toString(), + new ArrayList() {{ + this.add("https://evm.confluxscan.io/token/0x14b2d3bc65e74dae1030eafd8ac30c533c976a9b"); + }}); + tokens.put(ConfluxERC20Token.WCFX.toString(), wcfx); + + // PPI + EVMERC20TokenInfo swappi = new EVMERC20TokenInfo( + ConfluxERC20Token.PPI.toString(), + "0x22f41abf77905f50df398f21213290597e7414dd", + "Swappi token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.CONFLUX.toString(), + new ArrayList() {{ + this.add("https://evm.confluxscan.io/token/0x22f41abf77905f50df398f21213290597e7414dd"); + this.add("https://app.swappi.io/"); + }}); + tokens.put(ConfluxERC20Token.PPI.toString(), swappi); + + // ve_swappi + EVMERC20TokenInfo ve_swappi = new EVMERC20TokenInfo( + ConfluxERC20Token.vePPI.toString(), + "0xf270e44105c1270bc7a4ffedbcb699486ada7a6a", + "Swappi Vote Escrowed token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.CONFLUX.toString(), + new ArrayList() {{ + this.add("https://evm.confluxscan.io/address/0xf270e44105c1270bc7a4ffedbcb699486ada7a6a"); + }}); + tokens.put(ConfluxERC20Token.vePPI.toString(), ve_swappi); + + // swappi_cfx_ppi_lp + EVMERC20TokenInfo swappi_cfx_ppi_lp = new EVMERC20TokenInfo( + ConfluxERC20Token.SWAPPI_CFX_PPI_LP.toString(), + "0x1112a6c61a2eec4bd3aec78bd5bf3396bdd37d57", + "Swappi CFX-PPI LP token", + 18, + TokenCategory.LIQUIDITY_PROVIDER.toString(), + EVMChain.CONFLUX.toString(), + new ArrayList() {{ + this.add("https://evm.confluxscan.io/token/0x1112a6c61a2eec4bd3aec78bd5bf3396bdd37d57"); + }}); + tokens.put(ConfluxERC20Token.SWAPPI_CFX_PPI_LP.toString(), swappi_cfx_ppi_lp); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateZKEVMTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // dai + EVMERC20TokenInfo dai = new EVMERC20TokenInfo( + ZKEVMERC20Token.DAI.toString(), + "0xc5015b9d9161dca7e18e32f6f25c4ad850731fd4", + "DAI stablecoin token", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.ZKEVM.toString(), + new ArrayList() {{ + this.add("https://zkevm.polygonscan.com/address/0xc5015b9d9161dca7e18e32f6f25c4ad850731fd4"); + this.add("https://www.coingecko.com/en/coins/dai"); + }}); + tokens.put(ZKEVMERC20Token.DAI.toString(), dai); + + // usdc + EVMERC20TokenInfo usdc = new EVMERC20TokenInfo( + ZKEVMERC20Token.USDC.toString(), + "0xa8ce8aee21bc2a48a5ef670afcc9274c7bbbc035", + "USDC stablecoin token", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.ZKEVM.toString(), + new ArrayList() {{ + this.add("https://zkevm.polygonscan.com/token/0xa8ce8aee21bc2a48a5ef670afcc9274c7bbbc035"); + this.add("https://www.coingecko.com/en/coins/usd-coin"); + }}); + tokens.put(ZKEVMERC20Token.USDC.toString(), usdc); + + // usdt + EVMERC20TokenInfo usdt = new EVMERC20TokenInfo( + ZKEVMERC20Token.USDT.toString(), + "0x1e4a5963abfd975d8c9021ce480b42188849d41d", + "USDT stablecoin token", + 6, // !! + TokenCategory.STABLECOIN.toString(), + EVMChain.ZKEVM.toString(), + new ArrayList() {{ + this.add("https://zkevm.polygonscan.com/token/0x1e4a5963abfd975d8c9021ce480b42188849d41d"); + this.add("https://www.coingecko.com/en/coins/tether"); + }}); + tokens.put(ZKEVMERC20Token.USDT.toString(), usdt); + + // ausdc_dai + EVMERC20TokenInfo ausdc_dai = new EVMERC20TokenInfo( + ZKEVMERC20Token.GAMMA_aUSDC_DAI_LP.toString(), + "0xafad6e114cfbc8a19e91b8d7d04da740a7698595", + "aUSDC-DAI LP token", + 18, + TokenCategory.LIQUIDITY_PROVIDER.toString(), + EVMChain.ZKEVM.toString(), + new ArrayList() {{ + this.add("https://zkevm.polygonscan.com/token/0xafad6e114cfbc8a19e91b8d7d04da740a7698595"); + }}); + tokens.put(ZKEVMERC20Token.GAMMA_aUSDC_DAI_LP.toString(), ausdc_dai); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static EVMNFTIndex generateMantleNFTIndex() { + HashMap erc721tokens = new HashMap<>(); + HashMap erc1155tokens = new HashMap<>(); + + // MTK + EVMERC721TokenInfo citizen = new EVMERC721TokenInfo( + MantleERC721Token.CITIZEN.toString(), + "0x7cf4aC414C94E03Ecb2A7d6EA8F79087453cAEf0", + 0L, + "Citizen of Mantle", + TokenCategory.CHAINMASCOT.toString(), + EVMChain.MANTLE.toString(), + new ArrayList() {{ + this.add("https://explorer.mantle.xyz/token/0x7cf4aC414C94E03Ecb2A7d6EA8F79087453cAEf0"); + this.add("https://journey.mantle.xyz/"); + }}); + erc721tokens.put(MantleERC721Token.CITIZEN.toString(), citizen); + + return new EVMNFTIndex(erc721tokens, erc1155tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateCoreTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // USDT + EVMERC20TokenInfo usdt = new EVMERC20TokenInfo( + CoreERC20Token.USDT.toString(), + "0x900101d06a7426441ae63e9ab3b9b0f63be145f1", + "Tether stable token", + 6, // !!! + TokenCategory.STABLECOIN.toString(), + EVMChain.CORE.toString(), + new ArrayList() {{ + this.add("https://scan.coredao.org/token/0x900101d06a7426441ae63e9ab3b9b0f63be145f1"); + }}); + tokens.put(CoreERC20Token.USDT.toString(), usdt); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static EVMNFTIndex generateMilkomedaC1NFTIndex() { + HashMap erc721tokens = new HashMap<>(); + HashMap erc1155tokens = new HashMap<>(); + + // paima_volcaneers + EVMERC721TokenInfo paima_volcaneers = new EVMERC721TokenInfo( + MilkomedaC1ERC721Token.PAIMA_VOLCANEERS.toString(), + "0xa335d662BB47409e04F06dC7Fd03cEc854530172", + 0L, + "Paima Volcaneers (PV)", + TokenCategory.GAMING.toString(), + EVMChain.MILKOMEDAC1.toString(), + new ArrayList() {{ + this.add("https://explorer-mainnet-cardano-evm.c1.milkomeda.com/address/0xa335d662BB47409e04F06dC7Fd03cEc854530172"); + }}); + erc721tokens.put(MilkomedaC1ERC721Token.PAIMA_VOLCANEERS.toString(), paima_volcaneers); + + return new EVMNFTIndex(erc721tokens, erc1155tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateBaseTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // zkusd + EVMERC20TokenInfo weth = new EVMERC20TokenInfo( + BaseERC20Token.WETH.toString(), + "0x4200000000000000000000000000000000000006", + "Wrapped ETH token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.BASE.toString(), + new ArrayList() {{ + this.add("https://basescan.org/address/0x4200000000000000000000000000000000000006"); + }}); + tokens.put(BaseERC20Token.WETH.toString(), weth); + + // dai + EVMERC20TokenInfo dai = new EVMERC20TokenInfo( + BaseERC20Token.DAI.toString(), + "0x50c5725949a6f0c72e6c4a641f24049a917db0cb", + "DAI stablecoin token", + 18, + TokenCategory.STABLECOIN.toString(), + EVMChain.BASE.toString(), + new ArrayList() {{ + this.add("https://basescan.org/address/0x50c5725949a6f0c72e6c4a641f24049a917db0cb"); + this.add("https://www.coingecko.com/en/coins/dai"); + }}); + tokens.put(BaseERC20Token.DAI.toString(), dai); + + // aero + EVMERC20TokenInfo aero = new EVMERC20TokenInfo( + BaseERC20Token.AERO.toString(), + "0x940181a94a35a4569e4529a3cdfb74e38fd98631", + "AERO DEFI token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.BASE.toString(), + new ArrayList() {{ + this.add("https://basescan.org/address/0x940181a94a35a4569e4529a3cdfb74e38fd98631"); + }}); + tokens.put(BaseERC20Token.AERO.toString(), aero); + + // aerodome_lp_dai_weth + EVMERC20TokenInfo aerodome_lp_dai_weth = new EVMERC20TokenInfo( + BaseERC20Token.AERODOME_DAI_WETH_LP.toString(), + "0x9287c921f5d920ceee0d07d7c58d476e46acc640", + "Aerodome Finance DAI/WETH LP position", + 18, + TokenCategory.LIQUIDITY_PROVIDER.toString(), + EVMChain.BASE.toString(), + new ArrayList() {{ + this.add("https://basescan.org/token/0x9287c921f5d920ceee0d07d7c58d476e46acc640"); + this.add("https://aerodrome.finance/"); + }}); + tokens.put(BaseERC20Token.AERODOME_DAI_WETH_LP.toString(), aerodome_lp_dai_weth); + + // aerodome_lp_aero_weth + EVMERC20TokenInfo aerodome_lp_aero_weth = new EVMERC20TokenInfo( + BaseERC20Token.AERODOME_AERO_WETH_LP.toString(), + "0x7f670f78b17dec44d5ef68a48740b6f8849cc2e6", + "Aerodome Finance AERO/WETH LP position", + 18, + TokenCategory.LIQUIDITY_PROVIDER.toString(), + EVMChain.BASE.toString(), + new ArrayList() {{ + this.add("https://basescan.org/token/0x7f670f78b17dec44d5ef68a48740b6f8849cc2e6"); + this.add("https://aerodrome.finance/"); + }}); + tokens.put(BaseERC20Token.AERODOME_AERO_WETH_LP.toString(), aerodome_lp_aero_weth); + + + // usdc + EVMERC20TokenInfo usdc = new EVMERC20TokenInfo( + BaseERC20Token.USDC.toString(), + "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "USDC stablecoin token", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.BASE.toString(), + new ArrayList() {{ + this.add("https://basescan.org/address/0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"); + this.add("https://www.coingecko.com/en/coins/usd-coin"); + }}); + tokens.put(BaseERC20Token.USDC.toString(), usdc); + + // usdbc + EVMERC20TokenInfo usdbc = new EVMERC20TokenInfo( + BaseERC20Token.USDbC.toString(), + "0xd9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca", + "USDbC stablecoin token", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.BASE.toString(), + new ArrayList() {{ + this.add("https://basescan.org/address/0xd9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca"); + }}); + tokens.put(BaseERC20Token.USDbC.toString(), usdbc); + + return new ERC20TokenIndex(tokens); + + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateScrollTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // USDC + EVMERC20TokenInfo usdc = new EVMERC20TokenInfo( + ScrollERC20Token.USDC.toString(), + "0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4", + "USDC stable token", + 6, + TokenCategory.DEFI.toString(), + EVMChain.SCROLL.toString(), + new ArrayList() {{ + this.add("https://blockscout.scroll.io/address/0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4"); + }}); + tokens.put(ScrollERC20Token.USDC.toString(), usdc); + + // PAPYRUS + EVMERC20TokenInfo papyrus = new EVMERC20TokenInfo( + ScrollERC20Token.PAPYRUS.toString(), + "0x0Fc479e2f9b7310BfB1Db606CF565deA6910eedc", + "Papyrus token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.SCROLL.toString(), + new ArrayList() {{ + this.add("https://blockscout.scroll.io/address/0x0Fc479e2f9b7310BfB1Db606CF565deA6910eedc"); + }}); + tokens.put(ScrollERC20Token.PAPYRUS.toString(), papyrus); + + // gPAPYRUS + EVMERC20TokenInfo gpapyrus = new EVMERC20TokenInfo( + ScrollERC20Token.gPAPYRUS.toString(), + "0xf4BA885557b8E0dCE70e14CCD1a4A73E4a09793e", + "Papyrus locked token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.SCROLL.toString(), + new ArrayList() {{ + this.add("https://blockscout.scroll.io/address/0xf4BA885557b8E0dCE70e14CCD1a4A73E4a09793e"); + }}); + tokens.put(ScrollERC20Token.gPAPYRUS.toString(), gpapyrus); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateMantleTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // USDT + EVMERC20TokenInfo usdt = new EVMERC20TokenInfo( + MantleERC20Token.USDT.toString(), + "0x201EBa5CC46D216Ce6DC03F6a759e8E766e956aE", + "Tether stable coin", + 6, // !!! + TokenCategory.STABLECOIN.toString(), + EVMChain.MANTLE.toString(), + new ArrayList() {{ + this.add("https://explorer.mantle.xyz/token/0x201EBa5CC46D216Ce6DC03F6a759e8E766e956aE"); + }}); + tokens.put(MantleERC20Token.USDT.toString(), usdt); + + // WETH + EVMERC20TokenInfo weth = new EVMERC20TokenInfo( + MantleERC20Token.WETH.toString(), + "0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111", + "Wrapped ETH token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.MANTLE.toString(), + new ArrayList() {{ + this.add("https://explorer.mantle.xyz/token/0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111"); + this.add("https://www.coingecko.com/en/coins/wrapped-ether-mantle-bridge"); + }}); + tokens.put(MantleERC20Token.WETH.toString(), weth); + + // USDC + EVMERC20TokenInfo usdc = new EVMERC20TokenInfo( + MantleERC20Token.USDC.toString(), + "0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9", + "USDC stable coin", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.MANTLE.toString(), + new ArrayList() {{ + this.add("https://explorer.mantle.xyz/address/0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9"); + }}); + tokens.put(MantleERC20Token.USDC.toString(), usdc); + + return new ERC20TokenIndex(tokens); + } + + @SuppressWarnings("serial") + public static EVMNFTIndex generateLineaNFTIndex() { + HashMap erc721tokens = new HashMap<>(); + HashMap erc1155tokens = new HashMap<>(); + + // HorizonDEX LP + EVMERC721TokenInfo horizondexLP = new EVMERC721TokenInfo( + LineaERC721Token.HRZNLP.toString(), + "0x438670d41d5118003b2f42cc0466fbadd760dbf4", + 0L, + "HorizonDEX Reinvestment Token", + TokenCategory.LIQUIDITY_PROVIDER.toString(), + EVMChain.LINEA.toString(), + new ArrayList() {{ + this.add("https://lineascan.build/token/0x438670d41d5118003b2f42cc0466fbadd760dbf4"); + }}); + erc721tokens.put(LineaERC721Token.HRZNLP.toString(), horizondexLP); + + // BattleMon PickAxe + EVMERC721TokenInfo bm_pickaxe = new EVMERC721TokenInfo( + LineaERC721Token.BATTLEMON_PAXE.toString(), + "0x35d42d4bdc36cfe33a5ea6672a1b81752a963d6d", + 0L, + "BattleMon PickAxe", + TokenCategory.GAMING.toString(), + EVMChain.LINEA.toString(), + new ArrayList() {{ + this.add("https://lineascan.build/token/0x35d42d4bdc36cfe33a5ea6672a1b81752a963d6d"); + this.add("https://battlemon.com/"); + }}); + erc721tokens.put(LineaERC721Token.BATTLEMON_PAXE.toString(), bm_pickaxe); + + // BattleMon Lemon GEM + EVMERC721TokenInfo bm_lemon_gem = new EVMERC721TokenInfo( + LineaERC721Token.BATTLEMON_LGEM.toString(), + "0x6bf309ad2b7c0ebe44e69a53bb2cced79f17fc66", + 0L, + "BattleMon Lemon GEM", + TokenCategory.GAMING.toString(), + EVMChain.LINEA.toString(), + new ArrayList() {{ + this.add("https://lineascan.build/token/0x6bf309ad2b7c0ebe44e69a53bb2cced79f17fc66"); + this.add("https://battlemon.com/"); + }}); + erc721tokens.put(LineaERC721Token.BATTLEMON_LGEM.toString(), bm_lemon_gem); + + return new EVMNFTIndex(erc721tokens, erc1155tokens); + } + + @SuppressWarnings("serial") + public static ERC20TokenIndex generateMantleTestnetTokenIndex() { + + HashMap tokens = new HashMap<>(); + + // USDT + EVMERC20TokenInfo usdt = new EVMERC20TokenInfo( + MantleTestnetERC20Token.USDT.toString(), + "0x093790D873e87B45Cee9CA70B12056C705861ecD", + "Tether stable coin", + 6, // !!! + TokenCategory.STABLECOIN.toString(), + EVMChain.MANTLETEST.toString(), + new ArrayList() {{ + this.add("https://explorer.testnet.mantle.xyz/token/0x093790D873e87B45Cee9CA70B12056C705861ecD"); + }}); + tokens.put(MantleTestnetERC20Token.USDT.toString(), usdt); + + // WETH + EVMERC20TokenInfo weth = new EVMERC20TokenInfo( + MantleTestnetERC20Token.WETH.toString(), + "0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111", + "Wrapped ETH token", + 18, + TokenCategory.DEFI.toString(), + EVMChain.MANTLETEST.toString(), + new ArrayList() {{ + this.add("https://explorer.testnet.mantle.xyz/token/0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111"); + }}); + tokens.put(MantleTestnetERC20Token.WETH.toString(), weth); + + // USDC + EVMERC20TokenInfo usdc = new EVMERC20TokenInfo( + MantleTestnetERC20Token.USDC.toString(), + "0xbAF72402f98f16e77638Ce5FCC5689CD1627E8ff", + "USDC stable coin", + 6, + TokenCategory.STABLECOIN.toString(), + EVMChain.MANTLETEST.toString(), + new ArrayList() {{ + this.add("https://explorer.testnet.mantle.xyz/token/0xbAF72402f98f16e77638Ce5FCC5689CD1627E8ff/"); + }}); + tokens.put(MantleTestnetERC20Token.USDC.toString(), usdc); + + return new ERC20TokenIndex(tokens); + } + +} diff --git a/src/main/java/crypto/forestfish/objects/embedded/ipfs/IPFSDetails.java b/src/main/java/crypto/forestfish/objects/embedded/ipfs/IPFSDetails.java new file mode 100644 index 0000000..2a276c4 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/embedded/ipfs/IPFSDetails.java @@ -0,0 +1,64 @@ +package crypto.forestfish.objects.embedded.ipfs; + +import java.util.ArrayList; +import crypto.forestfish.objects.ipfs.model.IPFSNetwork; + +public class IPFSDetails { + + @SuppressWarnings("serial") + public static IPFSNetwork network = new IPFSNetwork( + "IPFS", + new ArrayList() {{ + + // https://ipfs.github.io/public-gateway-checker/ + this.add("https://gateway.ipfs.io/ipfs/"); + this.add("https://cloudflare-ipfs.com/ipfs/"); + this.add("https://jorropo.net/ipfs/"); + this.add("https://dweb.link/ipfs/"); + this.add("https://ipfs.eternum.io/ipfs/"); + this.add("https://gateway.pinata.cloud/ipfs/"); + this.add("https://w3s.link/ipfs/"); + this.add("https://ipfs.joaoleitao.org/ipfs/"); + this.add("https://4everland.io/ipfs/"); + this.add("https://hub.textile.io/ipfs/"); + this.add("https://via0.com/ipfs/"); + this.add("https://ipfs.runfission.com/ipfs/"); + this.add("https://cf-ipfs.com/ipfs/"); + this.add("https://ipfs.eth.aragon.network/ipfs/"); + this.add("https://nftstorage.link/ipfs/"); + this.add("https://ipfs.litnet.work/ipfs/"); + this.add("https://video.oneloveipfs.com/ipfs/"); + this.add("https://ipfs.jpu.jp/ipfs/"); + this.add("https://c4rex.co/ipfs/"); + this.add("https://ipfs-gateway.cloud/ipfs/"); + this.add("https://hardbin.com/ipfs/"); + this.add("https://bitkubipfs.io/ipfs/"); + this.add("https://gateway.ipfs.io/ipfs/"); + this.add("https://gateway.pinata.cloud/ipfs/"); + this.add("https://ipfs-pin.com/ipfs/"); + this.add("https://4everland.io/ipfs/"); + this.add("https://nftstorage.link/ipfs/"); + this.add("https://secure-authentication-meks-fixed083633980e.infura-ipfs.io/ipfs/"); + this.add("https://cloudflare-ipfs.com/ipfs/"); + this.add("https://dweb.link/ipfs/"); + this.add("https://www.protocolops.net/ipfs/"); + this.add("https://filesclouddsss.infura-ipfs.io/ipfs/"); + this.add("https://hardbin.com/ipfs/"); + this.add("https://w3s.link/ipfs/"); + this.add("https://l1s.saturn.ms/ipfs/"); + this.add("https://skywalker.infura-ipfs.io/ipfs/"); + this.add("https://portal.infura-ipfs.io/ipfs/"); + this.add("https://logsdomino.infura-ipfs.io/ipfs/"); + this.add("https://ipfs.eth.aragon.network/ipfs/"); + this.add("https://cf-ipfs.com/ipfs/"); + this.add("https://eu.starton-ipfs.com/ipfs/"); + this.add("https://fleek.ipfs.io/ipfs/"); + this.add("https://www.cloudflare-ipfs.com/ipfs/"); + this.add("https://infura-ipfs.io/ipfs/"); + this.add("https://ipfs.fleek.co/ipfs/"); + this.add("https://ipfs.io/ipfs/"); + }}, + "bafybeifx7yeb55armcsxwwitkymga5xf53dxiarykms3ygqic223w5sk3m#x-ipfs-companion-no-redirect" + ); + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/ERC20Transaction.java b/src/main/java/crypto/forestfish/objects/evm/ERC20Transaction.java new file mode 100644 index 0000000..1101efa --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/ERC20Transaction.java @@ -0,0 +1,187 @@ +package crypto.forestfish.objects.evm; + +public class ERC20Transaction { + + private String blockNumber = null; + private String timeStamp = null; + private String hash = null; + private String nonce = null; + private String blockHash = null; + private String transactionIndex = null; + private String from = null; + private String to = null; + private String value = null; + private Double valueD = null; + private String gas = null; + private String gasPrice = null; + private String isError = null; + private String txreceipt_status = null; + private String input = null; + private String contractAddress = null; + private String cumulativeGasUsed = null; + private String gasUsed = null; + private String confirmations = null; + + public ERC20Transaction() { + super(); + } + + public void update() { + if (null != this.value) { + this.valueD = Double.parseDouble("" + this.value)/1000000000000000000d; + } + } + + public String getBlockNumber() { + return blockNumber; + } + + public void setBlockNumber(String blockNumber) { + this.blockNumber = blockNumber; + } + + public String getTimeStamp() { + return timeStamp; + } + + public void setTimeStamp(String timeStamp) { + this.timeStamp = timeStamp; + } + + public String getHash() { + return hash; + } + + public void setHash(String hash) { + this.hash = hash; + } + + public String getNonce() { + return nonce; + } + + public void setNonce(String nonce) { + this.nonce = nonce; + } + + public String getBlockHash() { + return blockHash; + } + + public void setBlockHash(String blockHash) { + this.blockHash = blockHash; + } + + public String getTransactionIndex() { + return transactionIndex; + } + + public void setTransactionIndex(String transactionIndex) { + this.transactionIndex = transactionIndex; + } + + public String getFrom() { + return from; + } + + public void setFrom(String from) { + this.from = from; + } + + public String getTo() { + return to; + } + + public void setTo(String to) { + this.to = to; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getGas() { + return gas; + } + + public void setGas(String gas) { + this.gas = gas; + } + + public String getGasPrice() { + return gasPrice; + } + + public void setGasPrice(String gasPrice) { + this.gasPrice = gasPrice; + } + + public String getIsError() { + return isError; + } + + public void setIsError(String isError) { + this.isError = isError; + } + + public String getTxreceipt_status() { + return txreceipt_status; + } + + public void setTxreceipt_status(String txreceipt_status) { + this.txreceipt_status = txreceipt_status; + } + + public String getInput() { + return input; + } + + public void setInput(String input) { + this.input = input; + } + + public String getContractAddress() { + return contractAddress; + } + + public void setContractAddress(String contractAddress) { + this.contractAddress = contractAddress; + } + + public String getCumulativeGasUsed() { + return cumulativeGasUsed; + } + + public void setCumulativeGasUsed(String cumulativeGasUsed) { + this.cumulativeGasUsed = cumulativeGasUsed; + } + + public String getGasUsed() { + return gasUsed; + } + + public void setGasUsed(String gasUsed) { + this.gasUsed = gasUsed; + } + + public String getConfirmations() { + return confirmations; + } + + public void setConfirmations(String confirmations) { + this.confirmations = confirmations; + } + + public Double getValueD() { + return valueD; + } + + public void setValueD(Double valueD) { + this.valueD = valueD; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/EVMAccountBalance.java b/src/main/java/crypto/forestfish/objects/evm/EVMAccountBalance.java new file mode 100644 index 0000000..f4117f8 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/EVMAccountBalance.java @@ -0,0 +1,87 @@ +package crypto.forestfish.objects.evm; + +import crypto.forestfish.objects.evm.model.chain.EVMCurrency; + +public class EVMAccountBalance { + + private boolean isEmpty = true; + private String balanceInWEI; // BigInteger + private String balanceInGWEI; // BigDecimal + private String balanceInETH; // BigDecimal + private EVMCurrency currency; + + public EVMAccountBalance() { + super(); + } + + public EVMAccountBalance(String balanceInWEI, String balanceInGWEI, String balanceInETH, EVMCurrency currency, boolean isEmpty) { + super(); + this.balanceInWEI = balanceInWEI; + this.balanceInGWEI = balanceInGWEI; + this.balanceInETH = balanceInETH; + this.currency = currency; + this.isEmpty = isEmpty; + } + + public String getBalanceInWEI() { + return balanceInWEI; + } + + public void setBalanceInWEI(String balanceInWEI) { + this.balanceInWEI = balanceInWEI; + } + + public String getBalanceInETH() { + return balanceInETH; + } + + public String getBalanceInETHPrettyPrint() { + if (balanceInETH.startsWith("0.00")) { + return "..." + this.balanceInETH; + } else { + return this.balanceInETH; + } + } + + public void setBalanceInETH(String balanceInETH) { + this.balanceInETH = balanceInETH; + } + + public EVMCurrency getCurrency() { + return currency; + } + + public void setCurrency(EVMCurrency currency) { + this.currency = currency; + } + + public boolean isEmpty() { + return isEmpty; + } + + public void setEmpty(boolean isEmpty) { + this.isEmpty = isEmpty; + } + + public String getBalanceInGWEI() { + return balanceInGWEI; + } + + public String getBalanceInGWEIPrettyPrint() { + if (this.getCurrency().getDecimal() == 18) { + return this.balanceInGWEI; + } else { + return "-"; + } + } + + public void setBalanceInGWEI(String balanceInGWEI) { + this.balanceInGWEI = balanceInGWEI; + } + + @Override + public String toString() { + return "balanceInWEI=" + this.balanceInWEI + " balanceInGWEI=" + this.balanceInGWEI + " balanceInETH=" + this.balanceInETH + " currency.decimal=" + this.currency.getDecimal() + " currency.symbol=" + this.currency.getSymbol() + " isEmpty= " + this.isEmpty; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/EVMChainPortfolio.java b/src/main/java/crypto/forestfish/objects/evm/EVMChainPortfolio.java new file mode 100644 index 0000000..d4eb95b --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/EVMChainPortfolio.java @@ -0,0 +1,87 @@ +package crypto.forestfish.objects.evm; + +import java.util.HashMap; + +public class EVMChainPortfolio { + + private String account_address; + private String chain; + private EVMAccountBalance nativeBalance; + private String txCount; + private HashMap erc20tokens = new HashMap<>(); + private HashMap erc721tokens = new HashMap<>(); + private HashMap erc1155tokens = new HashMap<>(); + + public EVMChainPortfolio() { + super(); + } + + public EVMChainPortfolio(String _account_address, String chain, EVMAccountBalance _nativeBalance, String _txCount, HashMap _erc20tokens, HashMap _erc721tokens, HashMap _erc1155tokens) { + super(); + this.account_address = _account_address; + this.chain = chain; + this.nativeBalance = _nativeBalance; + this.txCount = _txCount; + this.erc20tokens = _erc20tokens; + this.erc721tokens = _erc721tokens; + this.erc1155tokens = _erc1155tokens; + } + + public EVMAccountBalance getNativeBalance() { + return nativeBalance; + } + + public void setNativeBalance(EVMAccountBalance nativeBalance) { + this.nativeBalance = nativeBalance; + } + + public HashMap getErc20tokens() { + return erc20tokens; + } + + public void setErc20tokens(HashMap erc20tokens) { + this.erc20tokens = erc20tokens; + } + + public HashMap getErc721tokens() { + return erc721tokens; + } + + public void setErc721tokens(HashMap erc721tokens) { + this.erc721tokens = erc721tokens; + } + + + public String getChain() { + return chain; + } + + public void setChain(String chain) { + this.chain = chain; + } + + public String getAccount_address() { + return account_address; + } + + public void setAccount_address(String account_address) { + this.account_address = account_address; + } + + public HashMap getErc1155tokens() { + return erc1155tokens; + } + + public void setErc1155tokens(HashMap erc1155tokens) { + this.erc1155tokens = erc1155tokens; + } + + public String getTxCount() { + return txCount; + } + + public void setTxCount(String txCount) { + this.txCount = txCount; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/EVMChainPortfolioDiff.java b/src/main/java/crypto/forestfish/objects/evm/EVMChainPortfolioDiff.java new file mode 100644 index 0000000..b8a8dea --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/EVMChainPortfolioDiff.java @@ -0,0 +1,87 @@ +package crypto.forestfish.objects.evm; + +import java.util.HashMap; + +public class EVMChainPortfolioDiff { + + private String account_address; + private String chain; + private EVMAccountBalance nativeBalance; + private String txCount; + private HashMap erc20tokens = new HashMap<>(); + private HashMap erc721tokens = new HashMap<>(); + private HashMap erc1155tokens = new HashMap<>(); + + public EVMChainPortfolioDiff() { + super(); + } + + public EVMChainPortfolioDiff(String account_address, String chain, EVMAccountBalance nativeBalance, String txCount, HashMap erc20tokens, HashMap erc721tokens, HashMap erc1155tokens) { + super(); + this.account_address = account_address; + this.chain = chain; + this.nativeBalance = nativeBalance; + this.txCount = txCount; + this.erc20tokens = erc20tokens; + this.erc721tokens = erc721tokens; + this.erc1155tokens = erc1155tokens; + } + + public EVMAccountBalance getNativeBalance() { + return nativeBalance; + } + + public void setNativeBalance(EVMAccountBalance nativeBalance) { + this.nativeBalance = nativeBalance; + } + + public HashMap getErc20tokens() { + return erc20tokens; + } + + public void setErc20tokens(HashMap erc20tokens) { + this.erc20tokens = erc20tokens; + } + + public HashMap getErc721tokens() { + return erc721tokens; + } + + public void setErc721tokens(HashMap erc721tokens) { + this.erc721tokens = erc721tokens; + } + + + public String getChain() { + return chain; + } + + public void setChain(String chain) { + this.chain = chain; + } + + public String getAccount_address() { + return account_address; + } + + public void setAccount_address(String account_address) { + this.account_address = account_address; + } + + public HashMap getErc1155tokens() { + return erc1155tokens; + } + + public void setErc1155tokens(HashMap erc1155tokens) { + this.erc1155tokens = erc1155tokens; + } + + public String getTxCount() { + return txCount; + } + + public void setTxCount(String txCount) { + this.txCount = txCount; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/EVMKnownAccountAddress.java b/src/main/java/crypto/forestfish/objects/evm/EVMKnownAccountAddress.java new file mode 100644 index 0000000..354d556 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/EVMKnownAccountAddress.java @@ -0,0 +1,58 @@ +package crypto.forestfish.objects.evm; + +import java.util.ArrayList; + +import crypto.forestfish.enums.AddressCategory; + +public class EVMKnownAccountAddress { + + private String name; + private String address; + private AddressCategory category; + private ArrayList origins = new ArrayList(); + + public EVMKnownAccountAddress(String name, String address, AddressCategory category, ArrayList origins) { + super(); + this.name = name; + this.address = address; + this.category = category; + this.origins = origins; + } + + public EVMKnownAccountAddress() { + super(); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public ArrayList getOrigins() { + return origins; + } + + public void setOrigins(ArrayList origins) { + this.origins = origins; + } + + public AddressCategory getCategory() { + return category; + } + + public void setCategory(AddressCategory category) { + this.category = category; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/EVMKnownCustomContractAddress.java b/src/main/java/crypto/forestfish/objects/evm/EVMKnownCustomContractAddress.java new file mode 100644 index 0000000..fd175df --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/EVMKnownCustomContractAddress.java @@ -0,0 +1,69 @@ +package crypto.forestfish.objects.evm; + +import java.util.ArrayList; + +import crypto.forestfish.enums.CustomContractCategory; +import crypto.forestfish.enums.evm.EVMChain; + +public class EVMKnownCustomContractAddress { + + private String name; + private String address; + private EVMChain chain; + private CustomContractCategory category; + private ArrayList origins = new ArrayList(); + + public EVMKnownCustomContractAddress(String name, String address, EVMChain chain, CustomContractCategory category, ArrayList origins) { + super(); + this.name = name; + this.address = address; + this.chain = chain; + this.category = category; + this.origins = origins; + } + + public EVMKnownCustomContractAddress() { + super(); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public ArrayList getOrigins() { + return origins; + } + + public void setOrigins(ArrayList origins) { + this.origins = origins; + } + + public CustomContractCategory getCategory() { + return category; + } + + public void setCategory(CustomContractCategory category) { + this.category = category; + } + + public EVMChain getChain() { + return chain; + } + + public void setChain(EVMChain chain) { + this.chain = chain; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/EVMLocalWallet.java b/src/main/java/crypto/forestfish/objects/evm/EVMLocalWallet.java new file mode 100644 index 0000000..608f429 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/EVMLocalWallet.java @@ -0,0 +1,262 @@ +package crypto.forestfish.objects.evm; + +import java.io.File; +import java.io.IOException; +import java.math.BigInteger; +import java.security.SecureRandom; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.web3j.crypto.Bip32ECKeyPair; +import org.web3j.crypto.Bip39Wallet; +import org.web3j.crypto.exception.CipherException; +import org.web3j.utils.Numeric; +import org.web3j.crypto.Credentials; +import org.web3j.crypto.ECKeyPair; +import org.web3j.crypto.MnemonicUtils; +import org.web3j.crypto.WalletUtils; +import crypto.forestfish.enums.AccountOrigin; +import crypto.forestfish.objects.embedded.BlockchainDetailsGeneric; +import crypto.forestfish.utils.EVMUtils; +import crypto.forestfish.utils.StringsUtils; +import crypto.forestfish.utils.SystemUtils; + +public class EVMLocalWallet { + + private static final Logger LOGGER = LoggerFactory.getLogger(EVMLocalWallet.class); + + private static final int PRIVATE_KEY_RADIX = 16; + + private String walletName; + private String walletPassword; + + // only used during account creation + private Credentials credentials = null; + private Bip39Wallet walletBIP39 = null; + + public EVMLocalWallet(String _wallet_name, AccountOrigin _wallet_origin, String _wallet_password) { + super(); + this.walletName = _wallet_name; + this.walletPassword = _wallet_password; + + File walletDirectory = new File(".evm/wallets/" + _wallet_name); + if (!walletDirectory.exists()) walletDirectory.mkdirs(); + + if (walletDirectory.listFiles().length == 0) { + + // INTENTION TO LOAD FROM EXISTING WALLET FAILED + if (_wallet_origin == AccountOrigin.EXISTING_LOCALWALLETFILE) { + LOGGER.error("The local wallet file " + _wallet_name + " does not exist"); + SystemUtils.halt(); + + // CREATE A NEW WALLET + } else if (_wallet_origin == AccountOrigin.NEW_LOCALWALLETFILE) { + + byte[] initialEntropy = new byte[16]; + SecureRandom secureRandom = new SecureRandom(); + secureRandom.nextBytes(initialEntropy); + String generated_mnemonic = MnemonicUtils.generateMnemonic(initialEntropy); + + LOGGER.info("Creating wallet from generated mnemonic \"" + generated_mnemonic + "\""); + byte[] seed = MnemonicUtils.generateSeed(generated_mnemonic, ""); + Bip32ECKeyPair masterKeypair = Bip32ECKeyPair.generateKeyPair(seed); + Bip32ECKeyPair childKeypair = Bip32ECKeyPair.deriveKeyPair(masterKeypair, BlockchainDetailsGeneric.derivationPathETH0); + this.credentials = Credentials.create(childKeypair); + System.out.println(" * This mnemonic gives us the address: " + this.credentials.getAddress()); + + try { + // Create the wallet file + WalletUtils.generateWalletFile(_wallet_password, childKeypair, walletDirectory, false); + } catch (IOException e) { + LOGGER.error("e: " + e.getMessage()); + SystemUtils.halt(); + } catch (CipherException e) { + LOGGER.error("e: " + e.getMessage()); + SystemUtils.halt(); + } + + } else if (_wallet_origin == AccountOrigin.RECOVERY_MNEMONIC) { + LOGGER.error("You need to use a different constructor if you are creating a wallet from a mnemonic"); + SystemUtils.halt(); + } else { + LOGGER.warn("Not sure how to proceed, no existing wallet and we need passphrase/mnemonic to proceed since we are not ordered to create a brand new wallet"); + SystemUtils.halt(); + } + + } else { + if (walletDirectory.listFiles().length != 1) { + LOGGER.warn("More than one wallet file? Cannot handle this atm."); + SystemUtils.halt(); + } + LOGGER.debug("Found an existing wallet!"); + try { + this.credentials = WalletUtils.loadCredentials(_wallet_password, walletDirectory.listFiles()[0]); + } catch (IOException e) { + LOGGER.warn("e: " + e.getMessage()); + SystemUtils.halt(); + } catch (CipherException e) { + LOGGER.warn("e: " + e.getMessage()); + SystemUtils.halt(); + } + } + + } + + public EVMLocalWallet(String _walletname, AccountOrigin _wallet_origin, String _wallet_password, String _secret) { + super(); + this.walletName = _walletname; + this.walletPassword = _wallet_password; + + File walletDirectory = new File(".evm/wallets/" + _walletname); + if (!walletDirectory.exists()) walletDirectory.mkdirs(); + + if (walletDirectory.listFiles().length == 0) { + + // No existing wallet so assume mnemonic creation in scope + if (_wallet_origin == AccountOrigin.RECOVERY_MNEMONIC) { + + if (EVMUtils.isValidMnemonic(_secret)) { + LOGGER.error("No/invalid mnemonic provided, will not attempt to create wallet" ); + SystemUtils.halt(); + } + + if (walletDirectory.listFiles().length > 1) { + LOGGER.warn("More than one wallet file? Cannot handle this atm. walletDirectory: " + walletDirectory.getName()); + SystemUtils.halt(); + } else if (walletDirectory.listFiles().length == 1) { + LOGGER.debug("Found an existing wallet with name " + _walletname + ". Going to use this first."); + try { + this.credentials = WalletUtils.loadCredentials(_wallet_password, walletDirectory.listFiles()[0]); + } catch (IOException e) { + LOGGER.warn("e: " + e.getMessage()); + SystemUtils.halt(); + } catch (CipherException e) { + LOGGER.warn("e: " + e.getMessage()); + SystemUtils.halt(); + } + } else { + + LOGGER.debug("Recovering wallet from mnemonic .. " + StringsUtils.cutStringFromLeft(_secret, 3) + "..."); + byte[] seed = MnemonicUtils.generateSeed(_secret, ""); + Bip32ECKeyPair masterKeypair = Bip32ECKeyPair.generateKeyPair(seed); + Bip32ECKeyPair childKeypair = Bip32ECKeyPair.deriveKeyPair(masterKeypair, BlockchainDetailsGeneric.derivationPathETH0); + this.credentials = Credentials.create(childKeypair); + System.out.println(" * This mnemonic gives us the address: " + this.credentials.getAddress()); + + try { + // Create the wallet file + WalletUtils.generateWalletFile(_wallet_password, childKeypair, walletDirectory, false); + this.credentials = WalletUtils.loadCredentials(_wallet_password, walletDirectory); + } catch (IOException e) { + LOGGER.error("e: " + e.getMessage()); + SystemUtils.halt(); + } catch (CipherException e) { + LOGGER.error("e: " + e.getMessage()); + SystemUtils.halt(); + } + + } + } else if (_wallet_origin == AccountOrigin.PRIVATEKEY) { + + if (walletDirectory.listFiles().length > 1) { + LOGGER.warn("More than one wallet file? Cannot handle this atm. walletDirectory: " + walletDirectory.getName()); + SystemUtils.halt(); + } else if (walletDirectory.listFiles().length == 1) { + LOGGER.debug("Found an existing wallet with name " + _walletname + ". Going to use this first."); + try { + this.credentials = WalletUtils.loadCredentials(_wallet_password, walletDirectory.listFiles()[0]); + } catch (IOException e) { + LOGGER.warn("e: " + e.getMessage()); + SystemUtils.halt(); + } catch (CipherException e) { + LOGGER.warn("e: " + e.getMessage()); + SystemUtils.halt(); + } + } else { + + if (!EVMUtils.isValidPrivateKey(_secret)) { + LOGGER.error("No/invalid private key provided, will not attempt to create wallet" ); + //SystemUtils.halt(); + } + + if (_secret.startsWith("0x")) _secret = _secret.replaceFirst("0x", ""); + LOGGER.info("Recovering wallet from privatekey .. " + StringsUtils.cutStringFromLeft(_secret, 3) + "..."); + + this.credentials = Credentials.create(_secret); + LOGGER.info(" * This private key gives us the address: " + this.credentials.getAddress()); + ECKeyPair keyPair = ECKeyPair.create(Numeric.toBigInt(_secret)); + + try { + // Create the wallet file + WalletUtils.generateWalletFile(_wallet_password, keyPair, walletDirectory, false); + } catch (IOException e) { + LOGGER.error("e: " + e.getMessage()); + SystemUtils.halt(); + } catch (CipherException e) { + LOGGER.error("e: " + e.getMessage()); + SystemUtils.halt(); + } + + } + + } else { + LOGGER.error("Not sure how to proceed, no existing wallet and we need no use of mnemonic to proceed??"); + SystemUtils.halt(); + } + + } else { + if (walletDirectory.listFiles().length != 1) { + LOGGER.warn("More than one wallet file? Cannot handle this atm."); + SystemUtils.halt(); + } + LOGGER.debug("Found an existing wallet with name " + _walletname + ". Will use this first."); + try { + this.credentials = WalletUtils.loadCredentials(_wallet_password, walletDirectory.listFiles()[0]); + } catch (IOException e) { + LOGGER.error("e: " + e.getMessage()); + SystemUtils.halt(); + } catch (CipherException e) { + LOGGER.error("e: " + e.getMessage()); + SystemUtils.halt(); + } + } + + } + + public String getWalletName() { + return walletName; + } + + public void setWalletName(String walletName) { + this.walletName = walletName; + } + + public String getWalletPassword() { + return walletPassword; + } + + public void setWalletPassword(String walletPassword) { + this.walletPassword = walletPassword; + } + + public Credentials getCredentials() { + return credentials; + } + + public void setCredentials(Credentials credentials) { + this.credentials = credentials; + } + + public Bip39Wallet getWalletBIP39() { + return walletBIP39; + } + + public void setWalletBIP39(Bip39Wallet walletBIP39) { + this.walletBIP39 = walletBIP39; + } + + // convenience + public String getAddress() { + return this.getCredentials().getAddress(); + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/EVMNativeValue.java b/src/main/java/crypto/forestfish/objects/evm/EVMNativeValue.java new file mode 100644 index 0000000..02be96d --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/EVMNativeValue.java @@ -0,0 +1,34 @@ +package crypto.forestfish.objects.evm; + +import java.math.BigDecimal; + +import org.web3j.utils.Convert.Unit; + +public class EVMNativeValue { + + private BigDecimal val; + private Unit unit; + + public EVMNativeValue(BigDecimal val, Unit unit) { + super(); + this.val = val; + this.unit = unit; + } + + public BigDecimal getVal() { + return val; + } + + public void setVal(BigDecimal val) { + this.val = val; + } + + public Unit getUnit() { + return unit; + } + + public void setUnit(Unit unit) { + this.unit = unit; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/EVMNftAccountBalance.java b/src/main/java/crypto/forestfish/objects/evm/EVMNftAccountBalance.java new file mode 100644 index 0000000..eaa0e3f --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/EVMNftAccountBalance.java @@ -0,0 +1,35 @@ +package crypto.forestfish.objects.evm; + +public class EVMNftAccountBalance { + + private boolean isEmpty = true; + private String balance; + + public EVMNftAccountBalance() { + super(); + } + + public EVMNftAccountBalance(String balance, boolean isEmpty) { + super(); + this.balance = balance; + this.isEmpty = isEmpty; + } + + public boolean isEmpty() { + return isEmpty; + } + + public void setEmpty(boolean isEmpty) { + this.isEmpty = isEmpty; + } + + public String getBalance() { + return balance; + } + + public void setBalance(String balance) { + this.balance = balance; + } + + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/EVMPortfolio.java b/src/main/java/crypto/forestfish/objects/evm/EVMPortfolio.java new file mode 100644 index 0000000..ca01c7a --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/EVMPortfolio.java @@ -0,0 +1,59 @@ +package crypto.forestfish.objects.evm; + +import java.util.HashMap; + +import org.web3j.crypto.Credentials; + +import crypto.forestfish.enums.evm.EVMChain; + +public class EVMPortfolio { + + private String account_address; + private HashMap chainportfolio = new HashMap<>(); + private Credentials cred; + private Long timestamp_in_seconds; + + public EVMPortfolio() { + super(); + } + + public EVMPortfolio(String _account_address, HashMap _chainportfolio, Long _timestamp_in_seconds) { + super(); + this.account_address = _account_address; + this.chainportfolio = _chainportfolio; + this.timestamp_in_seconds = _timestamp_in_seconds; + } + + public HashMap getChainportfolio() { + return chainportfolio; + } + + public void setChainportfolio(HashMap _chainportfolio) { + this.chainportfolio = _chainportfolio; + } + + public String getAccount_address() { + return account_address; + } + + public void setAccount_address(String _account_address) { + this.account_address = _account_address; + } + + public Credentials getCred() { + return cred; + } + + public void setCred(Credentials cred) { + this.cred = cred; + } + + public Long getTimestamp_in_seconds() { + return timestamp_in_seconds; + } + + public void setTimestamp_in_seconds(Long timestamp_in_seconds) { + this.timestamp_in_seconds = timestamp_in_seconds; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/EVMPortfolioDiff.java b/src/main/java/crypto/forestfish/objects/evm/EVMPortfolioDiff.java new file mode 100644 index 0000000..05575ef --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/EVMPortfolioDiff.java @@ -0,0 +1,39 @@ +package crypto.forestfish.objects.evm; + +import java.util.HashMap; + +import crypto.forestfish.enums.evm.EVMChain; + +public class EVMPortfolioDiff { + + private String account_address; + private HashMap chainportfolio_diff = new HashMap<>(); + + public EVMPortfolioDiff() { + super(); + } + + public EVMPortfolioDiff(String _account_address, HashMap _chainportfolio_diff) { + super(); + this.account_address = _account_address; + this.chainportfolio_diff = _chainportfolio_diff; + } + + + public String getAccount_address() { + return account_address; + } + + public void setAccount_address(String _account_address) { + this.account_address = _account_address; + } + + public HashMap getChainportfolio_diff() { + return chainportfolio_diff; + } + + public void setChainportfolio_diff(HashMap chainportfolio_diff) { + this.chainportfolio_diff = chainportfolio_diff; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/EVMPortfolioDiffResult.java b/src/main/java/crypto/forestfish/objects/evm/EVMPortfolioDiffResult.java new file mode 100644 index 0000000..d02c5a4 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/EVMPortfolioDiffResult.java @@ -0,0 +1,34 @@ +package crypto.forestfish.objects.evm; + +public class EVMPortfolioDiffResult { + + private String portfolio_full_str; + private EVMPortfolioDiff portfolio_diff; + + public EVMPortfolioDiffResult() { + super(); + } + + public EVMPortfolioDiffResult(String _portfolio_full_str, EVMPortfolioDiff _portfolio_diff) { + super(); + this.portfolio_full_str = _portfolio_full_str; + this.portfolio_diff = _portfolio_diff; + } + + public String getPortfolio_full_str() { + return portfolio_full_str; + } + + public void setPortfolio_full_str(String portfolio_full_str) { + this.portfolio_full_str = portfolio_full_str; + } + + public EVMPortfolioDiff getPortfolio_diff() { + return portfolio_diff; + } + + public void setPortfolio_diff(EVMPortfolioDiff portfolio_diff) { + this.portfolio_diff = portfolio_diff; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/EVMPortfolioSimple.java b/src/main/java/crypto/forestfish/objects/evm/EVMPortfolioSimple.java new file mode 100644 index 0000000..3bf2031 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/EVMPortfolioSimple.java @@ -0,0 +1,38 @@ +package crypto.forestfish.objects.evm; + +import java.util.HashMap; + +import crypto.forestfish.enums.evm.EVMChain; + +public class EVMPortfolioSimple { + + private String account_address; + private HashMap chainportfolio = new HashMap<>(); + + public EVMPortfolioSimple() { + super(); + } + + public EVMPortfolioSimple(String _account_address, HashMap _chainportfolio) { + super(); + this.account_address = _account_address; + this.chainportfolio = _chainportfolio; + } + + public HashMap getChainportfolio() { + return chainportfolio; + } + + public void setChainportfolio(HashMap _chainportfolio) { + this.chainportfolio = _chainportfolio; + } + + public String getAccount_address() { + return account_address; + } + + public void setAccount_address(String _account_address) { + this.account_address = _account_address; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/EVMProviderException.java b/src/main/java/crypto/forestfish/objects/evm/EVMProviderException.java new file mode 100644 index 0000000..d3531b0 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/EVMProviderException.java @@ -0,0 +1,86 @@ +package crypto.forestfish.objects.evm; + +import crypto.forestfish.enums.ExceptionType; + +public class EVMProviderException { + + private boolean switchNode = false; + private boolean nodeInteraction = false; + private boolean sleepBeforeRetry = false; + private boolean increaseGasPrice = false; + private int sleepTimeInSecondsRecommended = 5; + private ExceptionType exceptionType = ExceptionType.UNKNOWN; + private boolean timeout = false; + + public EVMProviderException() { + super(); + } + + public EVMProviderException(ExceptionType _exceptionType, boolean _nodeInteraction, boolean _sleepBeforeRetry, boolean _increaseGasPrice, int _sleepTimeInSecondsRecommended, boolean _switchNode, boolean _timeout) { + super(); + this.exceptionType = _exceptionType; + this.nodeInteraction = _nodeInteraction; + this.sleepBeforeRetry = _sleepBeforeRetry; + this.increaseGasPrice = _increaseGasPrice; + this.sleepTimeInSecondsRecommended = _sleepTimeInSecondsRecommended; + this.switchNode = _switchNode; + this.timeout = _timeout; + } + + public boolean isNodeInteraction() { + return nodeInteraction; + } + + public void setNodeInteraction(boolean nodeInteraction) { + this.nodeInteraction = nodeInteraction; + } + + public boolean isSleepBeforeRetry() { + return sleepBeforeRetry; + } + + public void setSleepBeforeRetry(boolean sleepBeforeRetry) { + this.sleepBeforeRetry = sleepBeforeRetry; + } + + public int getSleepTimeInSecondsRecommended() { + return sleepTimeInSecondsRecommended; + } + + public void setSleepTimeInSecondsRecommended(int sleepTimeInSecondsRecommended) { + this.sleepTimeInSecondsRecommended = sleepTimeInSecondsRecommended; + } + + public ExceptionType getExceptionType() { + return exceptionType; + } + + public void setExceptionType(ExceptionType exceptionType) { + this.exceptionType = exceptionType; + } + + public boolean isSwitchNode() { + return switchNode; + } + + public void setSwitchNode(boolean switchNode) { + this.switchNode = switchNode; + } + + public boolean isIncreaseGasPrice() { + return increaseGasPrice; + } + + public void setIncreaseGasPrice(boolean increaseGasPrice) { + this.increaseGasPrice = increaseGasPrice; + } + + public boolean isTimeout() { + return timeout; + } + + public void setTimeout(boolean timeout) { + this.timeout = timeout; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/EVMProviderExceptionActionState.java b/src/main/java/crypto/forestfish/objects/evm/EVMProviderExceptionActionState.java new file mode 100644 index 0000000..622a5c5 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/EVMProviderExceptionActionState.java @@ -0,0 +1,59 @@ +package crypto.forestfish.objects.evm; + +import java.math.BigInteger; + +import crypto.forestfish.objects.evm.connector.EVMBlockChainConnector; + +public class EVMProviderExceptionActionState { + + private boolean increaseGasPrice = false; + private BigInteger suggestedGasPriceIncreaseInWEI = BigInteger.valueOf(0); + + private boolean newEVMBlockChainConnector = false; + private EVMBlockChainConnector connector = null; + + public EVMProviderExceptionActionState() { + super(); + } + + public EVMProviderExceptionActionState(boolean increaseGasPrice, BigInteger suggestedGasPriceIncreaseInWEI, boolean newEVMBlockChainConnector, EVMBlockChainConnector connector) { + super(); + this.increaseGasPrice = increaseGasPrice; + this.suggestedGasPriceIncreaseInWEI = suggestedGasPriceIncreaseInWEI; + this.newEVMBlockChainConnector = newEVMBlockChainConnector; + this.connector = connector; + } + + public boolean isIncreaseGasPrice() { + return increaseGasPrice; + } + + public void setIncreaseGasPrice(boolean increaseGasPrice) { + this.increaseGasPrice = increaseGasPrice; + } + + public BigInteger getSuggestedGasPriceIncreaseInWEI() { + return suggestedGasPriceIncreaseInWEI; + } + + public void setSuggestedGasPriceIncreaseInWEI(BigInteger suggestedGasPriceIncreaseInWEI) { + this.suggestedGasPriceIncreaseInWEI = suggestedGasPriceIncreaseInWEI; + } + + public boolean isNewEVMBlockChainConnector() { + return newEVMBlockChainConnector; + } + + public void setNewEVMBlockChainConnector(boolean newEVMBlockChainConnector) { + this.newEVMBlockChainConnector = newEVMBlockChainConnector; + } + + public EVMBlockChainConnector getConnector() { + return connector; + } + + public void setConnector(EVMBlockChainConnector connector) { + this.connector = connector; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/EVMTransactionExceptionEvent.java b/src/main/java/crypto/forestfish/objects/evm/EVMTransactionExceptionEvent.java new file mode 100644 index 0000000..04ff3bc --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/EVMTransactionExceptionEvent.java @@ -0,0 +1,96 @@ +package crypto.forestfish.objects.evm; + +import crypto.forestfish.enums.ExceptionType; + +public class EVMTransactionExceptionEvent { + + private boolean switchNode = false; + private boolean nodeInteraction = false; + private boolean sleepBeforeRetry = false; + private boolean doubleGasPrice = false; + private boolean doubleGasLimit = false; + private int sleepTimeInSecondsRecommended = 5; + private ExceptionType exceptionType = ExceptionType.UNKNOWN; + private boolean dupTransaction = false; + + public EVMTransactionExceptionEvent() { + super(); + } + + public EVMTransactionExceptionEvent(ExceptionType _exceptionType, boolean _nodeInteraction, boolean _sleepBeforeRetry, boolean _doubleGasPrice, boolean _doubleGasLimit, int _sleepTimeInSecondsRecommended, boolean _switchNode, boolean _dupTransaction) { + super(); + this.exceptionType = _exceptionType; + this.nodeInteraction = _nodeInteraction; + this.sleepBeforeRetry = _sleepBeforeRetry; + this.doubleGasPrice = _doubleGasPrice; + this.doubleGasLimit = _doubleGasLimit; + this.sleepTimeInSecondsRecommended = _sleepTimeInSecondsRecommended; + this.switchNode = _switchNode; + this.dupTransaction = _dupTransaction; + } + + public boolean isNodeInteraction() { + return nodeInteraction; + } + + public void setNodeInteraction(boolean nodeInteraction) { + this.nodeInteraction = nodeInteraction; + } + + public boolean isSleepBeforeRetry() { + return sleepBeforeRetry; + } + + public void setSleepBeforeRetry(boolean sleepBeforeRetry) { + this.sleepBeforeRetry = sleepBeforeRetry; + } + + public int getSleepTimeInSecondsRecommended() { + return sleepTimeInSecondsRecommended; + } + + public void setSleepTimeInSecondsRecommended(int sleepTimeInSecondsRecommended) { + this.sleepTimeInSecondsRecommended = sleepTimeInSecondsRecommended; + } + + public ExceptionType getExceptionType() { + return exceptionType; + } + + public void setExceptionType(ExceptionType exceptionType) { + this.exceptionType = exceptionType; + } + + public boolean isSwitchNode() { + return switchNode; + } + + public void setSwitchNode(boolean switchNode) { + this.switchNode = switchNode; + } + + public boolean isDoubleGasPrice() { + return doubleGasPrice; + } + + public void setDoubleGasPrice(boolean doubleGasPrice) { + this.doubleGasPrice = doubleGasPrice; + } + + public boolean isDupTransaction() { + return dupTransaction; + } + + public void setDupTransaction(boolean dupTransaction) { + this.dupTransaction = dupTransaction; + } + + public boolean isDoubleGasLimit() { + return doubleGasLimit; + } + + public void setDoubleGasLimit(boolean doubleGasLimit) { + this.doubleGasLimit = doubleGasLimit; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/EVMWalletBalanceReply.java b/src/main/java/crypto/forestfish/objects/evm/EVMWalletBalanceReply.java new file mode 100644 index 0000000..55b0846 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/EVMWalletBalanceReply.java @@ -0,0 +1,75 @@ +package crypto.forestfish.objects.evm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.fastjson.JSON; + +public class EVMWalletBalanceReply { + + private static final Logger LOGGER = LoggerFactory.getLogger(EVMWalletBalanceReply.class); + + private String status = null; + private String message = null; + private String result = null; + private Double balance = null; + + public EVMWalletBalanceReply() { + super(); + } + + public void update() { + if (null != this.result) { + this.balance = Double.parseDouble("" + this.result)/1000000000000000000d; + } + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getResult() { + return result; + } + + public void setResult(String result) { + this.result = result; + } + + public Double getBalance() { + return balance; + } + + public void setBalance(Double balance) { + this.balance = balance; + } + + @Override + public String toString() { + return "status=" + this.status + " message=" + this.message + " result=" + this.result + " balance=" + this.balance; + } + + public static EVMWalletBalanceReply parseReply(String jsonSTR) { + EVMWalletBalanceReply ev = null; + try { + ev = JSON.parseObject(jsonSTR, EVMWalletBalanceReply.class); + } catch (Exception e) { + LOGGER.error("Exception during JSON parsing: " + e.getClass() + ": " + e.getMessage(), e); + LOGGER.error("JSON string for above error: " + jsonSTR); + } + return ev; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/EVMWalletTxHistoryReply.java b/src/main/java/crypto/forestfish/objects/evm/EVMWalletTxHistoryReply.java new file mode 100644 index 0000000..974c63f --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/EVMWalletTxHistoryReply.java @@ -0,0 +1,48 @@ +package crypto.forestfish.objects.evm; + +import java.util.ArrayList; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.fastjson.JSON; + +public class EVMWalletTxHistoryReply { + + private static final Logger LOGGER = LoggerFactory.getLogger(EVMWalletTxHistoryReply.class); + + private String status = null; + private String message = null; + private ArrayList result = new ArrayList(); + + public String getStatus() { + return status; + } + public void setStatus(String status) { + this.status = status; + } + public String getMessage() { + return message; + } + public void setMessage(String message) { + this.message = message; + } + public ArrayList getResult() { + return result; + } + public void setResult(ArrayList result) { + this.result = result; + } + + public static EVMWalletTxHistoryReply parseReply(String jsonSTR) { + EVMWalletTxHistoryReply ev = null; + try { + ev = JSON.parseObject(jsonSTR, EVMWalletTxHistoryReply.class); + } catch (Exception e) { + LOGGER.error("Exception during JSON parsing: " + e.getClass() + ": " + e.getMessage(), e); + LOGGER.error("JSON string for above error: " + jsonSTR); + } + return ev; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/NonceCheckStatus.java b/src/main/java/crypto/forestfish/objects/evm/NonceCheckStatus.java new file mode 100644 index 0000000..a2ce962 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/NonceCheckStatus.java @@ -0,0 +1,30 @@ +package crypto.forestfish.objects.evm; + +public class NonceCheckStatus { + + private PendingTxStatus status; + private boolean earlyexit = false; + + public NonceCheckStatus(PendingTxStatus status, boolean earlyexit) { + super(); + this.status = status; + this.earlyexit = earlyexit; + } + + public PendingTxStatus getStatus() { + return status; + } + + public void setStatus(PendingTxStatus status) { + this.status = status; + } + + public boolean isEarlyexit() { + return earlyexit; + } + + public void setEarlyexit(boolean earlyexit) { + this.earlyexit = earlyexit; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/PendingTxStatus.java b/src/main/java/crypto/forestfish/objects/evm/PendingTxStatus.java new file mode 100644 index 0000000..236206a --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/PendingTxStatus.java @@ -0,0 +1,57 @@ +package crypto.forestfish.objects.evm; + +import java.math.BigInteger; + +public class PendingTxStatus { + + private boolean pending; + private BigInteger nonce_latest; + private BigInteger nonce_pending; + private Long nonce_diff; + + public PendingTxStatus() { + super(); + } + + public PendingTxStatus(boolean _pending, BigInteger _nonce_latest, BigInteger _nonce_pending, Long _nonce_diff) { + super(); + this.pending = _pending; + this.nonce_latest = _nonce_latest; + this.nonce_pending = _nonce_pending; + this.nonce_diff = _nonce_diff; + } + + public boolean isPending() { + return pending; + } + + public void setPending(boolean pending) { + this.pending = pending; + } + + public BigInteger getNonce_latest() { + return nonce_latest; + } + + public void setNonce_latest(BigInteger nonce_latest) { + this.nonce_latest = nonce_latest; + } + + public BigInteger getNonce_pending() { + return nonce_pending; + } + + public void setNonce_pending(BigInteger nonce_pending) { + this.nonce_pending = nonce_pending; + } + + public Long getNonce_diff() { + return nonce_diff; + } + + public void setNonce_diff(Long nonce_diff) { + this.nonce_diff = nonce_diff; + } + +} + diff --git a/src/main/java/crypto/forestfish/objects/evm/SimpleWallet.java b/src/main/java/crypto/forestfish/objects/evm/SimpleWallet.java new file mode 100644 index 0000000..fa968f7 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/SimpleWallet.java @@ -0,0 +1,46 @@ +package crypto.forestfish.objects.evm; + +import org.web3j.crypto.Credentials; + +public class SimpleWallet { + + private String mnemonic; + private Credentials cred0; + private String privkey0; + + public SimpleWallet() { + super(); + } + + public SimpleWallet(String _mnemonic, Credentials _cred0, String _privkey0) { + super(); + this.mnemonic = _mnemonic; + this.cred0 = _cred0; + this.privkey0 = _privkey0; + } + + public String getMnemonic() { + return mnemonic; + } + + public void setMnemonic(String mnemonic) { + this.mnemonic = mnemonic; + } + + public Credentials getCred0() { + return cred0; + } + + public void setCred0(Credentials cred0) { + this.cred0 = cred0; + } + + public String getPrivkey0() { + return privkey0; + } + + public void setPrivkey0(String privkey0) { + this.privkey0 = privkey0; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/connector/EVMBlockChainConnector.java b/src/main/java/crypto/forestfish/objects/evm/connector/EVMBlockChainConnector.java new file mode 100644 index 0000000..d61a1b7 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/connector/EVMBlockChainConnector.java @@ -0,0 +1,319 @@ +package crypto.forestfish.objects.evm.connector; + +import java.util.HashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.web3j.protocol.Web3j; +import org.web3j.protocol.http.HttpService; + +import crypto.forestfish.enums.evm.EVMChain; +import crypto.forestfish.objects.evm.model.chain.EVMChainInfo; +import crypto.forestfish.utils.*; + +public class EVMBlockChainConnector { + + private static final Logger LOGGER = LoggerFactory.getLogger(EVMBlockChainConnector.class); + + private EVMChain chain; + private EVMChainInfo chaininfo; + private String current_nodeURL; + private String current_blockexplorerURL; + private Web3j provider_instance; + + private HashMap deadnodes = new HashMap<>(); + + // call defaults + int callRetryThreshold = 3; + int confirmTimeInSecondsBeforeRetry = 20; + boolean haltOnFailedCall = true; + + // tx defaults + int txRetryThreshold = 3; + + public EVMBlockChainConnector(EVMChain _chain, String _forced_nodeURL) { + super(); + this.chain = _chain; + this.chaininfo = EVMUtils.getEVMChainInfo(_chain); + + boolean initialization_complete = false; + int randomAttemptCounter = 0; + while (!initialization_complete && (randomAttemptCounter<=10)) { + Web3j web3j_cand = Web3j.build(new HttpService(_forced_nodeURL)); + long init = System.currentTimeMillis(); + Long latestblocknr = EVMUtils.getLatestBlockNumberFromNodeAsHealthCheck(this.chain, _forced_nodeURL, web3j_cand); + //System.out.println("latestblocknr: " + latestblocknr); + long resp = System.currentTimeMillis() - init; + if ( (null != latestblocknr) && (latestblocknr>0L)) { + LOGGER.info("node URL " + _forced_nodeURL + " looks fine for " + this.chain); + LOGGER.info("latestblock='" + latestblocknr + "', response_time=" + resp + " ms"); + this.provider_instance = web3j_cand; + this.current_nodeURL = _forced_nodeURL; + initialization_complete = true; + } else { + LOGGER.info("Failed attempt using node " + _forced_nodeURL + ", randomAttemptCounter=" + randomAttemptCounter); + } + randomAttemptCounter++; + } + } + + public EVMBlockChainConnector(EVMChain _chain) { + super(); + this.chain = _chain; + this.chaininfo = EVMUtils.getEVMChainInfo(_chain); + selectRandomNodeURL(); + } + + public EVMBlockChainConnector(EVMChain _chain, boolean _nodeOptimized) { + super(); + this.chain = _chain; + this.chaininfo = EVMUtils.getEVMChainInfo(_chain); + if (_nodeOptimized) { + selectSpeedyNodeURL(); + } else { + selectRandomNodeURL(); + } + } + + public void selectRandomNodeURL() { + // verify and select RPC connection + LOGGER.info("We need to get 1 of these candidates working, gonna go random:"); + int candindex = 1; + for (String nodeURL: this.chaininfo.getNodeURLs()) { + LOGGER.info(" #" + candindex + ": " + nodeURL); + candindex++; + } + boolean selection_complete = false; + int randomAttemptCounter = 0; + while (!selection_complete && (randomAttemptCounter<=10)) { + String candidate = getRandom_nodeURL_candidate(); + Web3j web3j_cand = Web3j.build(new HttpService(candidate)); + long init = System.currentTimeMillis(); + Long latestblocknr = EVMUtils.getLatestBlockNumberFromNodeAsHealthCheck(this.chain, candidate, web3j_cand); + //System.out.println("latestblocknr: " + latestblocknr); + long resp = System.currentTimeMillis() - init; + if ( (null != latestblocknr) && (latestblocknr>0L)) { + LOGGER.info("node URL " + candidate + " looks fine for " + this.chain + ", will use it"); + LOGGER.info("latestblock='" + latestblocknr + "', response_time=" + resp + " ms"); + this.provider_instance = web3j_cand; + this.current_nodeURL = candidate; + selection_complete = true; + } else { + LOGGER.info("Failed attempt using node " + candidate + ", randomAttemptCounter=" + randomAttemptCounter); + } + randomAttemptCounter++; + } + } + + public void selectRandomNodeURL(String _skipthisNodeURL) { + // verify and select RPC connection + LOGGER.info("We need to get 1 of these candidates working, gonna go random without " + _skipthisNodeURL); + int candindex = 1; + for (String nodeURL: this.chaininfo.getNodeURLs()) { + LOGGER.info(" #" + candindex + ": " + nodeURL); + candindex++; + } + boolean morethan1Candidate = true; + if (this.chaininfo.getNodeURLs().size() == 1) morethan1Candidate = false; + boolean selection_complete = false; + int randomAttemptCounter = 0; + while (!selection_complete && (randomAttemptCounter<=10)) { + String candidate = getRandom_nodeURL_candidate(); + if (morethan1Candidate && _skipthisNodeURL.equals(candidate)) { + // lets pick a different node + } else if (!morethan1Candidate && _skipthisNodeURL.equals(candidate)) { + // early exit + if (!morethan1Candidate) randomAttemptCounter = 100; + } else { + Web3j web3j_cand = Web3j.build(new HttpService(candidate)); + long init = System.currentTimeMillis(); + Long latestblocknr = EVMUtils.getLatestBlockNumberFromNodeAsHealthCheck(this.chain, candidate, web3j_cand); + long resp = System.currentTimeMillis() - init; + if ( (null != latestblocknr) && (latestblocknr>0L)) { + LOGGER.info("node URL " + candidate + " looks fine for " + this.chain + ", will use it"); + LOGGER.info("latestblock='" + latestblocknr + "', response_time=" + resp + " ms"); + this.provider_instance = web3j_cand; + this.current_nodeURL = candidate; + selection_complete = true; + } + } + randomAttemptCounter++; + } + } + + public String getRandom_nodeURL_candidate() { + int size = this.chaininfo.getNodeURLs().size(); + if (size == 0) { + LOGGER.error("We have no nodeURL candidates available. We should not be instantiated at at this point .."); + SystemUtils.halt(); + } else if (size == 1) { + return this.chaininfo.getNodeURLs().get(0); + } else { + int selection = NumUtils.randomNumWithinRangeAsInt(1, size); + int index = 1; + for (String nodeURL: this.chaininfo.getNodeURLs()) { + if (selection == index) return nodeURL; + index++; + } + return this.chaininfo.getNodeURLs().get(0); + } + LOGGER.error("We have no nodeURL candidates available. We should not be instantiated at at this point .."); + SystemUtils.halt(); + return null; + } + + public void selectSpeedyNodeURL() { + // verify and select RPC connection + String winner = ""; + if (this.chaininfo.getNodeURLs().size() == 1) { + winner = this.chaininfo.getNodeURLs().get(0); + this.current_nodeURL = winner; + LOGGER.info("We only have one node candidate so lets move forward with " + winner); + } else { + + LOGGER.info("We need to get 1 of these candidates working, gonna optimize:"); + int candindex = 1; + for (String nodeURL: this.chaininfo.getNodeURLs()) { + LOGGER.info(" #" + candindex + ": " + nodeURL); + candindex++; + } + + boolean nondead_winner_found = false; + while (!nondead_winner_found) { + + HashMap candidate_blockstate = new HashMap<>(); + + long maxBlockNR = Long.MIN_VALUE; + long minDiff = Long.MAX_VALUE; + for (String candidate: this.getChaininfo().getNodeURLs()) { + // make sure to disregard dead nodes + if (null == deadnodes.get(candidate)) { + Web3j web3j_cand = Web3j.build(new HttpService(candidate)); + long init = System.currentTimeMillis(); + Long latestblocknr = EVMUtils.getLatestBlockNumberFromNodeAsHealthCheck(this.chain, candidate, web3j_cand); + //System.out.println("version: " + version); + long resp = System.currentTimeMillis() - init; + if ( (null != latestblocknr) && (latestblocknr>0L)) { + this.current_nodeURL = candidate; + if (resp candidate_blockstate.keySet().size()) { + LOGGER.warn("Found dead/lagging node, blockdiff=" + diff + ": " + cand); + deadnodes.put(cand, true); + } + } + + if (null == deadnodes.get(winner)) { + LOGGER.info("node URL " + winner + " seems best option for " + this.chain + ", response_time=" + minDiff + " ms"); + nondead_winner_found = true; + } else { + LOGGER.info("We need to re-run, found dead nodes (" + deadnodes.size() + ") in our list .."); + LOGGER.info("deadnodes: " + deadnodes.keySet()); + if (this.getChaininfo().getNodeURLs().size() == deadnodes.size()) { + LOGGER.error("All RPC node candidates are dead?"); + SystemUtils.halt(); + } + } + + } + + } + + } + this.provider_instance = Web3j.build(new HttpService(winner)); + } + + public EVMChainInfo getChaininfo() { + return chaininfo; + } + + public void setChaininfo(EVMChainInfo chaininfo) { + this.chaininfo = chaininfo; + } + + public String getCurrent_nodeURL() { + return current_nodeURL; + } + + public void setCurrent_nodeURL(String current_nodeURL) { + this.current_nodeURL = current_nodeURL; + } + + public String getCurrent_blockexplorerURL() { + return current_blockexplorerURL; + } + + public void setCurrent_blockexplorerURL(String current_blockexplorerURL) { + this.current_blockexplorerURL = current_blockexplorerURL; + } + + public EVMChain getChain() { + return chain; + } + + public void setChain(EVMChain chain) { + this.chain = chain; + } + + public Web3j getProvider_instance() { + return provider_instance; + } + + public void setProvider_instance(Web3j provider_instance) { + this.provider_instance = provider_instance; + } + + public int getConfirmTimeInSecondsBeforeRetry() { + return confirmTimeInSecondsBeforeRetry; + } + + public void setConfirmTimeInSecondsBeforeRetry(int confirmTimeInSecondsBeforeRetry) { + this.confirmTimeInSecondsBeforeRetry = confirmTimeInSecondsBeforeRetry; + } + + public boolean isHaltOnFailedCall() { + return haltOnFailedCall; + } + + public void setHaltOnFailedCall(boolean haltOnFailedCall) { + this.haltOnFailedCall = haltOnFailedCall; + } + + public HashMap getDeadnodes() { + return deadnodes; + } + + public void setDeadnodes(HashMap deadnodes) { + this.deadnodes = deadnodes; + } + + public int getTxRetryThreshold() { + return txRetryThreshold; + } + + public void setTxRetryThreshold(int txRetryThreshold) { + this.txRetryThreshold = txRetryThreshold; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/connector/EVMBlockChainUltraConnector.java b/src/main/java/crypto/forestfish/objects/evm/connector/EVMBlockChainUltraConnector.java new file mode 100644 index 0000000..619dbee --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/connector/EVMBlockChainUltraConnector.java @@ -0,0 +1,82 @@ +package crypto.forestfish.objects.evm.connector; + +import java.util.HashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import crypto.forestfish.enums.BlockchainType; +import crypto.forestfish.enums.evm.EVMChain; +import crypto.forestfish.objects.evm.model.chain.EVMChainInfo; +import crypto.forestfish.utils.EVMUtils; +import crypto.forestfish.utils.SystemUtils; + +public class EVMBlockChainUltraConnector { + + private static final Logger LOGGER = LoggerFactory.getLogger(EVMBlockChainUltraConnector.class); + + private HashMap connectors = new HashMap<>(); + private BlockchainType chainType; + + public EVMBlockChainUltraConnector(BlockchainType _chainType) { + super(); + + this.chainType = _chainType; + + //Initiate an rpc connection to every public blockchain we known of + for (EVMChain chain: EVMChain.values()) { + EVMChainInfo chainInfo = EVMUtils.getEVMChainInfo(chain); + if (chainInfo == null) { + LOGGER.error("No chainInfo for chain " + chain + "?"); + SystemUtils.halt(); + } + if (BlockchainType.valueOf(chainInfo.getType()) == chainType) { + LOGGER.info("Finding optimal node for public EVM blockchain " + chain); + EVMBlockChainConnector connector = new EVMBlockChainConnector(chain, true); + connectors.put(chain, connector); + } + } + + } + + public EVMBlockChainUltraConnector(BlockchainType _chainType, HashMap _chainlimit) { + super(); + + this.chainType = _chainType; + + if (_chainlimit.keySet().isEmpty()) { + LOGGER.error("Empty chain limitation passed as argument"); + SystemUtils.halt(); + } + + //Initiate an rpc connection to every public blockchain we known of + for (EVMChain chain: EVMChain.values()) { + if (null != _chainlimit.get(chain.toString())) { + EVMChainInfo chainInfo = EVMUtils.getEVMChainInfo(chain); + if (BlockchainType.valueOf(chainInfo.getType()) == chainType) { + LOGGER.info("Adding optimal node for public EVM blockchain " + chain); + EVMBlockChainConnector connector = new EVMBlockChainConnector(chain, true); + connectors.put(chain, connector); + } + } + } + + } + + public HashMap getConnectors() { + return connectors; + } + + public void setConnectors(HashMap connectors) { + this.connectors = connectors; + } + + public BlockchainType getChainType() { + return chainType; + } + + public void setChainType(BlockchainType chainType) { + this.chainType = chainType; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/model/chain/EVMChainIndex.java b/src/main/java/crypto/forestfish/objects/evm/model/chain/EVMChainIndex.java new file mode 100644 index 0000000..126c35d --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/model/chain/EVMChainIndex.java @@ -0,0 +1,28 @@ +package crypto.forestfish.objects.evm.model.chain; + +import java.util.HashMap; + +import crypto.forestfish.enums.evm.EVMChain; + +public class EVMChainIndex { + + private HashMap networks = new HashMap<>(); + + public EVMChainIndex() { + super(); + } + + public EVMChainIndex(HashMap networks) { + super(); + this.networks = networks; + } + + public HashMap getNetworks() { + return networks; + } + + public void setNetworks(HashMap networks) { + this.networks = networks; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/model/chain/EVMChainInfo.java b/src/main/java/crypto/forestfish/objects/evm/model/chain/EVMChainInfo.java new file mode 100644 index 0000000..454eb61 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/model/chain/EVMChainInfo.java @@ -0,0 +1,199 @@ +package crypto.forestfish.objects.evm.model.chain; + +import java.util.ArrayList; + +import crypto.forestfish.objects.evm.model.erc20.ERC20TokenIndex; +import crypto.forestfish.objects.evm.model.nft.EVMNFTIndex; + +public class EVMChainInfo { + + private String shortName; + private String chainName; + private Long chainId; + private String type; + private EVMCurrency nativeCurrency = null; + private String priceMechanism; + private String fallbackGasPriceInWEI; + private String enforcedMinGasPriceInWEI = null; + private String fallbackGasLimitInUnits; + private ArrayList nodeURLs = new ArrayList(); + private ArrayList archivenodeURLs = new ArrayList(); + private ArrayList flashbotnodeURLs = new ArrayList(); + private ArrayList flashbotrelaynodeURLs = new ArrayList(); + private ArrayList blockexplorerURLs = new ArrayList(); + private ArrayList faucets = new ArrayList(); + private ArrayList origins = new ArrayList(); + private ERC20TokenIndex tokenIndex; + private EVMNFTIndex nftindex; + + public EVMChainInfo() { + super(); + } + + public EVMChainInfo(String _shortName, String _chainName, Long _chainId, String _type, EVMCurrency _nativeCurrency, String _priceMechanism, String _fallbackGasPriceInWEI, String _enforcedMinGasPriceInWEI, String _fallbackGasLimitInUnits, ArrayList _nodeURLs, ArrayList _archivenodeURLs, ArrayList _flashbotnodeURLs, ArrayList _flashbotrelaynodeURLs, ArrayList _blockexplorerURLs, ArrayList _faucets, ArrayList _origins, ERC20TokenIndex _tokenIndex, EVMNFTIndex _nftindex) { + super(); + this.shortName = _shortName; + this.chainName = _chainName; + this.chainId = _chainId; + this.type = _type; + this.nativeCurrency = _nativeCurrency; + this.priceMechanism = _priceMechanism; + this.fallbackGasPriceInWEI = _fallbackGasPriceInWEI; + this.enforcedMinGasPriceInWEI = _enforcedMinGasPriceInWEI; + this.fallbackGasLimitInUnits = _fallbackGasLimitInUnits; + this.nodeURLs = _nodeURLs; + this.archivenodeURLs = _archivenodeURLs; + this.flashbotnodeURLs = _flashbotnodeURLs; + this.flashbotrelaynodeURLs = _flashbotrelaynodeURLs; + this.blockexplorerURLs = _blockexplorerURLs; + this.faucets = _faucets; + this.origins = _origins; + this.tokenIndex = _tokenIndex; + this.nftindex = _nftindex; + } + + public String getShortName() { + return shortName; + } + + public void setShortName(String shortName) { + this.shortName = shortName; + } + + public String getChainName() { + return chainName; + } + + public void setChainName(String chainName) { + this.chainName = chainName; + } + + public Long getChainId() { + return chainId; + } + + public void setChainId(Long chainId) { + this.chainId = chainId; + } + + public EVMCurrency getNativeCurrency() { + return nativeCurrency; + } + + public void setNativeCurrency(EVMCurrency nativeCurrency) { + this.nativeCurrency = nativeCurrency; + } + + public ArrayList getNodeURLs() { + return nodeURLs; + } + + public void setNodeURLs(ArrayList nodeURLs) { + this.nodeURLs = nodeURLs; + } + + public ArrayList getBlockexplorerURLs() { + return blockexplorerURLs; + } + + public void setBlockexplorerURLs(ArrayList blockexplorerURLs) { + this.blockexplorerURLs = blockexplorerURLs; + } + + public ArrayList getOrigins() { + return origins; + } + + public void setOrigins(ArrayList origins) { + this.origins = origins; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public ERC20TokenIndex getTokenIndex() { + return tokenIndex; + } + + public void setTokenIndex(ERC20TokenIndex tokenIndex) { + this.tokenIndex = tokenIndex; + } + + public EVMNFTIndex getNftindex() { + return nftindex; + } + + public void setNftindex(EVMNFTIndex nftindex) { + this.nftindex = nftindex; + } + + public String getPriceMechanism() { + return priceMechanism; + } + + public void setPriceMechanism(String priceMechanism) { + this.priceMechanism = priceMechanism; + } + + public String getFallbackGasPriceInWEI() { + return fallbackGasPriceInWEI; + } + + public void setFallbackGasPriceInWEI(String fallbackGasPriceInWEI) { + this.fallbackGasPriceInWEI = fallbackGasPriceInWEI; + } + + public String getFallbackGasLimitInUnits() { + return fallbackGasLimitInUnits; + } + + public void setFallbackGasLimitInUnits(String fallbackGasLimitInUnits) { + this.fallbackGasLimitInUnits = fallbackGasLimitInUnits; + } + + public ArrayList getFaucets() { + return faucets; + } + + public void setFaucets(ArrayList faucets) { + this.faucets = faucets; + } + + public ArrayList getFlashbotnodeURLs() { + return flashbotnodeURLs; + } + + public void setFlashbotnodeURLs(ArrayList flashbotnodeURLs) { + this.flashbotnodeURLs = flashbotnodeURLs; + } + + public ArrayList getFlashbotrelaynodeURLs() { + return flashbotrelaynodeURLs; + } + + public void setFlashbotrelaynodeURLs(ArrayList flashbotrelaynodeURLs) { + this.flashbotrelaynodeURLs = flashbotrelaynodeURLs; + } + + public String getEnforcedMinGasPriceInWEI() { + return enforcedMinGasPriceInWEI; + } + + public void setEnforcedMinGasPriceInWEI(String enforcedMinGasPriceInWEI) { + this.enforcedMinGasPriceInWEI = enforcedMinGasPriceInWEI; + } + + public ArrayList getArchivenodeURLs() { + return archivenodeURLs; + } + + public void setArchivenodeURLs(ArrayList archivenodeURLs) { + this.archivenodeURLs = archivenodeURLs; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/model/chain/EVMCurrency.java b/src/main/java/crypto/forestfish/objects/evm/model/chain/EVMCurrency.java new file mode 100644 index 0000000..4268fa8 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/model/chain/EVMCurrency.java @@ -0,0 +1,43 @@ +package crypto.forestfish.objects.evm.model.chain; + +public class EVMCurrency { + private String name = null; + private String symbol = null; + private Integer decimal = 18; + + public EVMCurrency() { + super(); + } + + public EVMCurrency(String _name, String _symbol, Integer _decimal) { + super(); + this.name = _name; + this.symbol = _symbol; + this.decimal = _decimal; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSymbol() { + return symbol; + } + + public void setSymbol(String symbol) { + this.symbol = symbol; + } + + public Integer getDecimal() { + return decimal; + } + + public void setDecimal(Integer decimal) { + this.decimal = decimal; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/model/erc20/ERC20TokenIndex.java b/src/main/java/crypto/forestfish/objects/evm/model/erc20/ERC20TokenIndex.java new file mode 100644 index 0000000..d950f3d --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/model/erc20/ERC20TokenIndex.java @@ -0,0 +1,26 @@ +package crypto.forestfish.objects.evm.model.erc20; + +import java.util.HashMap; + +public class ERC20TokenIndex { + + private HashMap tokens = new HashMap<>(); + + public ERC20TokenIndex() { + super(); + } + + public ERC20TokenIndex(HashMap tokens) { + super(); + this.tokens = tokens; + } + + public HashMap getTokens() { + return tokens; + } + + public void setTokens(HashMap tokens) { + this.tokens = tokens; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/model/erc20/EVMERC20TokenInfo.java b/src/main/java/crypto/forestfish/objects/evm/model/erc20/EVMERC20TokenInfo.java new file mode 100644 index 0000000..88a177a --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/model/erc20/EVMERC20TokenInfo.java @@ -0,0 +1,86 @@ +package crypto.forestfish.objects.evm.model.erc20; + +import java.util.ArrayList; + +public class EVMERC20TokenInfo { + + private String symbol; + private String contractAddress; + private String name; + private Integer decimals; + private String chain; + private ArrayList origins = new ArrayList(); + private String category; + + public EVMERC20TokenInfo() { + super(); + } + + public EVMERC20TokenInfo(String _symbol, String _contractAddress, String _name, Integer _decimals, String _category, String _chain, ArrayList _origins) { + super(); + this.symbol = _symbol; + this.contractAddress = _contractAddress; + this.name = _name; + this.decimals = _decimals; + this.category = _category; + this.chain = _chain; + this.origins = _origins; + } + + public String getSymbol() { + return symbol; + } + + public void setSymbol(String symbol) { + this.symbol = symbol; + } + + public String getContractAddress() { + return contractAddress; + } + + public void setContractAddress(String contractAddress) { + this.contractAddress = contractAddress; + } + + public ArrayList getOrigins() { + return origins; + } + + public void setOrigins(ArrayList origins) { + this.origins = origins; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getDecimals() { + return decimals; + } + + public void setDecimals(Integer decimals) { + this.decimals = decimals; + } + + public String getChain() { + return chain; + } + + public void setChain(String chain) { + this.chain = chain; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/model/erc721/ERC721ContractInfo.java b/src/main/java/crypto/forestfish/objects/evm/model/erc721/ERC721ContractInfo.java new file mode 100644 index 0000000..be08d65 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/model/erc721/ERC721ContractInfo.java @@ -0,0 +1,72 @@ +package crypto.forestfish.objects.evm.model.erc721; + +public class ERC721ContractInfo { + + private String name; + private String symbol; + private String contractAddress; + private String totalSupply; + private String baseuri; + private String owner; + + public ERC721ContractInfo() { + super(); + } + + public ERC721ContractInfo(String name, String symbol, String contractAddress, String totalSupply, String uri, String id, String metajson) { + super(); + this.name = name; + this.symbol = symbol; + this.contractAddress = contractAddress; + this.totalSupply = totalSupply; + } + + public String getSymbol() { + return symbol; + } + + public void setSymbol(String symbol) { + this.symbol = symbol; + } + + public String getContractAddress() { + return contractAddress; + } + + public void setContractAddress(String contractAddress) { + this.contractAddress = contractAddress; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getTotalSupply() { + return totalSupply; + } + + public void setTotalSupply(String totalSupply) { + this.totalSupply = totalSupply; + } + + public String getBaseuri() { + return baseuri; + } + + public void setBaseuri(String baseuri) { + this.baseuri = baseuri; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/model/erc721/ERC721TokenInfo.java b/src/main/java/crypto/forestfish/objects/evm/model/erc721/ERC721TokenInfo.java new file mode 100644 index 0000000..38b3dfc --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/model/erc721/ERC721TokenInfo.java @@ -0,0 +1,53 @@ +package crypto.forestfish.objects.evm.model.erc721; + +public class ERC721TokenInfo { + + private String uri; + private String id; + private String metajson; + private ERC721ContractInfo contractinfo; + + public ERC721TokenInfo() { + super(); + } + + public ERC721TokenInfo(String uri, String id, String metajson) { + super(); + this.uri = uri; + this.id = id; + this.metajson = metajson; + } + + public String getMetajson() { + return metajson; + } + + public void setMetajson(String metajson) { + this.metajson = metajson; + } + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public ERC721ContractInfo getContractinfo() { + return contractinfo; + } + + public void setContractinfo(ERC721ContractInfo contractinfo) { + this.contractinfo = contractinfo; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/model/nft/EVMERC1155TokenInfo.java b/src/main/java/crypto/forestfish/objects/evm/model/nft/EVMERC1155TokenInfo.java new file mode 100644 index 0000000..08353fd --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/model/nft/EVMERC1155TokenInfo.java @@ -0,0 +1,107 @@ +package crypto.forestfish.objects.evm.model.nft; + +import java.util.ArrayList; + +public class EVMERC1155TokenInfo { + + private String symbol; + private String contractAddress; + private Long mintBlock; + private String description; + private String chain; + private ArrayList origins = new ArrayList(); + private String category; + private ArrayList linked_tokens = new ArrayList(); + + public EVMERC1155TokenInfo() { + super(); + } + + public EVMERC1155TokenInfo(String _symbol, String _contractAddress, Long _mintBlock, String _description, String _category, String _chain, ArrayList _origins) { + super(); + this.symbol = _symbol; + this.contractAddress = _contractAddress; + this.mintBlock = _mintBlock; + this.description = _description; + this.category = _category; + this.chain = _chain; + this.origins = _origins; + } + + public EVMERC1155TokenInfo(String _symbol, String _contractAddress, Long _mintBlock, String _description, String _category, String _chain, ArrayList _origins, ArrayList _linked_tokens) { + super(); + this.symbol = _symbol; + this.contractAddress = _contractAddress; + this.mintBlock = _mintBlock; + this.description = _description; + this.category = _category; + this.chain = _chain; + this.origins = _origins; + this.linked_tokens = _linked_tokens; + } + + public String getSymbol() { + return symbol; + } + + public void setSymbol(String symbol) { + this.symbol = symbol; + } + + public String getContractAddress() { + return contractAddress; + } + + public void setContractAddress(String contractAddress) { + this.contractAddress = contractAddress; + } + + public ArrayList getOrigins() { + return origins; + } + + public void setOrigins(ArrayList origins) { + this.origins = origins; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getChain() { + return chain; + } + + public void setChain(String chain) { + this.chain = chain; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public ArrayList getLinked_tokens() { + return linked_tokens; + } + + public void setLinked_tokens(ArrayList linked_tokens) { + this.linked_tokens = linked_tokens; + } + + public Long getMintBlock() { + return mintBlock; + } + + public void setMintBlock(Long mintBlock) { + this.mintBlock = mintBlock; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/model/nft/EVMERC721TokenInfo.java b/src/main/java/crypto/forestfish/objects/evm/model/nft/EVMERC721TokenInfo.java new file mode 100644 index 0000000..eae3667 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/model/nft/EVMERC721TokenInfo.java @@ -0,0 +1,107 @@ +package crypto.forestfish.objects.evm.model.nft; + +import java.util.ArrayList; + +public class EVMERC721TokenInfo { + + private String symbol; + private String contractAddress; + private Long mintBlock; + private String description; + private String chain; + private ArrayList origins = new ArrayList(); + private String category; + private ArrayList linked_tokens = new ArrayList(); + + public EVMERC721TokenInfo() { + super(); + } + + public EVMERC721TokenInfo(String _symbol, String _contractAddress, Long _mintBlock, String _description, String _category, String _chain, ArrayList _origins) { + super(); + this.symbol = _symbol; + this.contractAddress = _contractAddress; + this.mintBlock = _mintBlock; + this.description = _description; + this.category = _category; + this.chain = _chain; + this.origins = _origins; + } + + public EVMERC721TokenInfo(String _symbol, String _contractAddress, Long _mintBlock, String _description, String _category, String _chain, ArrayList _origins, ArrayList _linked_tokens) { + super(); + this.symbol = _symbol; + this.contractAddress = _contractAddress; + this.mintBlock = _mintBlock; + this.description = _description; + this.category = _category; + this.chain = _chain; + this.origins = _origins; + this.linked_tokens = _linked_tokens; + } + + public String getSymbol() { + return symbol; + } + + public void setSymbol(String symbol) { + this.symbol = symbol; + } + + public String getContractAddress() { + return contractAddress; + } + + public void setContractAddress(String contractAddress) { + this.contractAddress = contractAddress; + } + + public ArrayList getOrigins() { + return origins; + } + + public void setOrigins(ArrayList origins) { + this.origins = origins; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getChain() { + return chain; + } + + public void setChain(String chain) { + this.chain = chain; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public ArrayList getLinked_tokens() { + return linked_tokens; + } + + public void setLinked_tokens(ArrayList linked_tokens) { + this.linked_tokens = linked_tokens; + } + + public Long getMintBlock() { + return mintBlock; + } + + public void setMintBlock(Long mintBlock) { + this.mintBlock = mintBlock; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/model/nft/EVMNFTIndex.java b/src/main/java/crypto/forestfish/objects/evm/model/nft/EVMNFTIndex.java new file mode 100644 index 0000000..36554f3 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/model/nft/EVMNFTIndex.java @@ -0,0 +1,36 @@ +package crypto.forestfish.objects.evm.model.nft; + +import java.util.HashMap; + +public class EVMNFTIndex { + + private HashMap erc721tokens = new HashMap<>(); + private HashMap erc1155tokens = new HashMap<>(); + + public EVMNFTIndex() { + super(); + } + + public EVMNFTIndex(HashMap erc721tokens, HashMap erc1155tokens) { + super(); + this.erc721tokens = erc721tokens; + this.erc1155tokens = erc1155tokens; + } + + public HashMap getErc721tokens() { + return erc721tokens; + } + + public void setErc721tokens(HashMap erc721tokens) { + this.erc721tokens = erc721tokens; + } + + public HashMap getErc1155tokens() { + return erc1155tokens; + } + + public void setErc1155tokens(HashMap erc1155tokens) { + this.erc1155tokens = erc1155tokens; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/model/nft/metadata/ERC1155MetaData.java b/src/main/java/crypto/forestfish/objects/evm/model/nft/metadata/ERC1155MetaData.java new file mode 100644 index 0000000..716a873 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/model/nft/metadata/ERC1155MetaData.java @@ -0,0 +1,159 @@ +package crypto.forestfish.objects.evm.model.nft.metadata; + +import java.util.ArrayList; +import java.util.HashMap; + +public class ERC1155MetaData { + + /** + * https://eips.ethereum.org/EIPS/eip-721 + */ + private String name; + private String description; + private String image; // Supports {id} + private Integer decimals; + + private ArrayList> properties; + // Common properties keys: + // - String file_url + + private HashMap localization; + // Required localization keys: + // - String uri (supports {locale}) + // - String default + // - ArrayList locales + + /** + * https://docs.opensea.io/docs/metadata-standards + */ + //private String name; + //private String description; + //private String image; // Supports {id} + private String background_color; + private String image_data; + private String external_url; // Supports {id} + private String animation_url; + private String youtube_url; + + private ArrayList attributes; + + public ERC1155MetaData() { + super(); + } + + public ERC1155MetaData(String _name, String _description, Integer _decimals, String _background_color, + String _image, String _image_data, + String _external_url, String _animation_url, String _youtube_url, + ArrayList _attributes, ArrayList> _properties, HashMap _localization) { + super(); + this.name = _name; + this.description = _description; + this.decimals = _decimals; + this.background_color = _background_color; + this.image = _image; + this.image_data = _image_data; + this.external_url = _external_url; + this.animation_url = _animation_url; + this.youtube_url = _youtube_url; + this.attributes = _attributes; + this.properties = _properties; + this.localization = _localization; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } + + public ArrayList> getProperties() { + return properties; + } + + public void setProperties(ArrayList> properties) { + this.properties = properties; + } + + public String getBackground_color() { + return background_color; + } + + public void setBackground_color(String background_color) { + this.background_color = background_color; + } + + public String getImage_data() { + return image_data; + } + + public void setImage_data(String image_data) { + this.image_data = image_data; + } + + public String getExternal_url() { + return external_url; + } + + public void setExternal_url(String external_url) { + this.external_url = external_url; + } + + public String getAnimation_url() { + return animation_url; + } + + public void setAnimation_url(String animation_url) { + this.animation_url = animation_url; + } + + public String getYoutube_url() { + return youtube_url; + } + + public void setYoutube_url(String youtube_url) { + this.youtube_url = youtube_url; + } + + public HashMap getLocalization() { + return localization; + } + + public void setLocalization(HashMap localization) { + this.localization = localization; + } + + public Integer getDecimals() { + return decimals; + } + + public void setDecimals(Integer decimals) { + this.decimals = decimals; + } + + public ArrayList getAttributes() { + return attributes; + } + + public void setAttributes(ArrayList attributes) { + this.attributes = attributes; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/model/nft/metadata/ERC721MetaData.java b/src/main/java/crypto/forestfish/objects/evm/model/nft/metadata/ERC721MetaData.java new file mode 100644 index 0000000..db864c8 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/model/nft/metadata/ERC721MetaData.java @@ -0,0 +1,120 @@ +package crypto.forestfish.objects.evm.model.nft.metadata; + +import java.util.ArrayList; + +public class ERC721MetaData { + + /** + * https://eips.ethereum.org/EIPS/eip-721 + */ + private String name; + private String description; + private String image; // Supports {id} + + /** + * https://docs.opensea.io/docs/metadata-standards + */ + //private String name; + //private String description; + //private String image; // Supports {id} + private String background_color; + private String image_data; // Only use this if you're not including the image parameter + private String external_url; // Supports {id} + private String animation_url; + private String youtube_url; + + private ArrayList attributes; + + public ERC721MetaData() { + super(); + } + + public ERC721MetaData(String _name, String _description, String _background_color, + String _image, String _image_data, + String _external_url, String _animation_url, String youtube_url, + ArrayList _attributes) { + super(); + this.name = _name; + this.description = _description; + this.background_color = _background_color; + this.image = _image; + this.image_data = _image_data; + this.external_url = _external_url; + this.animation_url = _animation_url; + this.youtube_url = youtube_url; + this.attributes = _attributes; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } + + public String getBackground_color() { + return background_color; + } + + public void setBackground_color(String background_color) { + this.background_color = background_color; + } + + public String getImage_data() { + return image_data; + } + + public void setImage_data(String image_data) { + this.image_data = image_data; + } + + public String getExternal_url() { + return external_url; + } + + public void setExternal_url(String external_url) { + this.external_url = external_url; + } + + public String getAnimation_url() { + return animation_url; + } + + public void setAnimation_url(String animation_url) { + this.animation_url = animation_url; + } + + public String getYoutube_url() { + return youtube_url; + } + + public void setYoutube_url(String youtube_url) { + this.youtube_url = youtube_url; + } + + public ArrayList getAttributes() { + return attributes; + } + + public void setAttributes(ArrayList attributes) { + this.attributes = attributes; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/model/nft/metadata/OpenSeaTrait.java b/src/main/java/crypto/forestfish/objects/evm/model/nft/metadata/OpenSeaTrait.java new file mode 100644 index 0000000..8bf1d3c --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/model/nft/metadata/OpenSeaTrait.java @@ -0,0 +1,34 @@ +package crypto.forestfish.objects.evm.model.nft.metadata; + +public class OpenSeaTrait { + + private String trait_type; + private Object value; + + public OpenSeaTrait() { + super(); + } + + public OpenSeaTrait(String trait_type, Object value) { + super(); + this.trait_type = trait_type; + this.value = value; + } + + public String getTrait_type() { + return trait_type; + } + + public void setTrait_type(String trait_type) { + this.trait_type = trait_type; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/model/solidity/ABIFunctionEntry.java b/src/main/java/crypto/forestfish/objects/evm/model/solidity/ABIFunctionEntry.java new file mode 100644 index 0000000..c4310ba --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/model/solidity/ABIFunctionEntry.java @@ -0,0 +1,57 @@ +package crypto.forestfish.objects.evm.model.solidity; + +import java.util.ArrayList; + +public class ABIFunctionEntry { + + private String name; + private String type; + private String stateMutability; + private ArrayList inputs; + private ArrayList outputs; + + public ABIFunctionEntry() { + super(); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getStateMutability() { + return stateMutability; + } + + public void setStateMutability(String stateMutability) { + this.stateMutability = stateMutability; + } + + public ArrayList getInputs() { + return inputs; + } + + public void setInputs(ArrayList inputs) { + this.inputs = inputs; + } + + public ArrayList getOutputs() { + return outputs; + } + + public void setOutputs(ArrayList outputs) { + this.outputs = outputs; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/model/solidity/ABIIOEntry.java b/src/main/java/crypto/forestfish/objects/evm/model/solidity/ABIIOEntry.java new file mode 100644 index 0000000..74d6960 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/model/solidity/ABIIOEntry.java @@ -0,0 +1,51 @@ +package crypto.forestfish.objects.evm.model.solidity; + +import crypto.forestfish.utils.StringsUtils; + +public class ABIIOEntry { + + private String internalType; + private String name; + private String type; + + public ABIIOEntry() { + super(); + } + + public ABIIOEntry(String internalType, String name, String type) { + super(); + this.internalType = internalType; + this.name = name; + this.type = type; + } + + public String getInternalType() { + return internalType; + } + + public void setInternalType(String internalType) { + this.internalType = internalType; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + @Override + public String toString() { + return StringsUtils.cutAndPadStringToN("name=" + this.name, 20) + StringsUtils.cutAndPadStringToN(" type=" + this.type, 20) + StringsUtils.cutAndPadStringToN(" internalType=" + this.internalType, 20); + } + +} diff --git a/src/main/java/crypto/forestfish/objects/evm/moralis/MoralisERC20ContractMetaInfo.java b/src/main/java/crypto/forestfish/objects/evm/moralis/MoralisERC20ContractMetaInfo.java new file mode 100644 index 0000000..b903c96 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/moralis/MoralisERC20ContractMetaInfo.java @@ -0,0 +1,87 @@ +package crypto.forestfish.objects.evm.moralis; + +public class MoralisERC20ContractMetaInfo { + + private String address; + private String name; + private String symbol; + private String decimals; + + private String logo; + private String logo_hash; + private String thumbnail; + private String block_number; + private Integer validated; + private String created_at; + + public MoralisERC20ContractMetaInfo() { + super(); + } + + public String getAddress() { + return address; + } + public void setAddress(String address) { + this.address = address; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public String getSymbol() { + return symbol; + } + public void setSymbol(String symbol) { + this.symbol = symbol; + } + public String getDecimals() { + return decimals; + } + public void setDecimals(String decimals) { + this.decimals = decimals; + } + public String getLogo() { + return logo; + } + public void setLogo(String logo) { + this.logo = logo; + } + public String getLogo_hash() { + return logo_hash; + } + public void setLogo_hash(String logo_hash) { + this.logo_hash = logo_hash; + } + public String getThumbnail() { + return thumbnail; + } + public void setThumbnail(String thumbnail) { + this.thumbnail = thumbnail; + } + public String getBlock_number() { + return block_number; + } + public void setBlock_number(String block_number) { + this.block_number = block_number; + } + public Integer getValidated() { + return validated; + } + public void setValidated(Integer validated) { + this.validated = validated; + } + + public String getCreated_at() { + return created_at; + } + public void setCreated_at(String created_at) { + this.created_at = created_at; + } + + @Override + public String toString() { + return "name: " + this.getName() + " symbol: " + this.getSymbol() + " address: " + this.getAddress() + " decimals: " + this.getDecimals() + " created_at: " + this.getCreated_at() + " validated: " + this.getValidated(); + } +} diff --git a/src/main/java/crypto/forestfish/objects/evm/moralis/MoralisERC20ContractPriceInfo.java b/src/main/java/crypto/forestfish/objects/evm/moralis/MoralisERC20ContractPriceInfo.java new file mode 100644 index 0000000..569bd1c --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/moralis/MoralisERC20ContractPriceInfo.java @@ -0,0 +1,50 @@ +package crypto.forestfish.objects.evm.moralis; + +public class MoralisERC20ContractPriceInfo { + + private MoralisNativePrice nativePrice; + private String usdPrice; + private String exchangeAddress; + private String exchangeName; + + public MoralisERC20ContractPriceInfo() { + super(); + } + + public MoralisNativePrice getNativePrice() { + return nativePrice; + } + + public void setNativePrice(MoralisNativePrice nativePrice) { + this.nativePrice = nativePrice; + } + + public String getUsdPrice() { + return usdPrice; + } + + public void setUsdPrice(String usdPrice) { + this.usdPrice = usdPrice; + } + + public String getExchangeAddress() { + return exchangeAddress; + } + + public void setExchangeAddress(String exchangeAddress) { + this.exchangeAddress = exchangeAddress; + } + + public String getExchangeName() { + return exchangeName; + } + + public void setExchangeName(String exchangeName) { + this.exchangeName = exchangeName; + } + + @Override + public String toString() { + return "usdPrice: " + this.getUsdPrice() + " exchangeName: " + this.getExchangeName() + " exchangeName: " + this.getExchangeName() + " nativePrice: " + this.getNativePrice().toString(); + } +} diff --git a/src/main/java/crypto/forestfish/objects/evm/moralis/MoralisNativePrice.java b/src/main/java/crypto/forestfish/objects/evm/moralis/MoralisNativePrice.java new file mode 100644 index 0000000..1b2f6eb --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/evm/moralis/MoralisNativePrice.java @@ -0,0 +1,50 @@ +package crypto.forestfish.objects.evm.moralis; + +public class MoralisNativePrice { + + private String value; + private Integer decimals; + private String name; + private String symbol; + + public MoralisNativePrice() { + super(); + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public Integer getDecimals() { + return decimals; + } + + public void setDecimals(Integer decimals) { + this.decimals = decimals; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSymbol() { + return symbol; + } + + public void setSymbol(String symbol) { + this.symbol = symbol; + } + + @Override + public String toString() { + return "nativeName: " + this.getName() + " nativeSymbol: " + this.getSymbol() + " nativeDecimals: " + this.getDecimals() + " nativeValue: " + this.getValue(); + } +} diff --git a/src/main/java/crypto/forestfish/objects/ipfs/IPFSNode.java b/src/main/java/crypto/forestfish/objects/ipfs/IPFSNode.java new file mode 100644 index 0000000..6844a95 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/ipfs/IPFSNode.java @@ -0,0 +1,35 @@ +package crypto.forestfish.objects.ipfs; + +public class IPFSNode { + + private String api_address = ""; // typically port 5001 + private String gateway_address = ""; // typically port 8080 + + public IPFSNode(String api_address) { + super(); + this.api_address = api_address; + } + + public IPFSNode(String api_address, String gateway_address) { + super(); + this.api_address = api_address; + this.gateway_address = gateway_address; + } + + public String getApi_address() { + return api_address; + } + + public void setApi_address(String api_address) { + this.api_address = api_address; + } + + public String getGateway_address() { + return gateway_address; + } + + public void setGateway_address(String gateway_address) { + this.gateway_address = gateway_address; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/ipfs/connector/IPFSConnector.java b/src/main/java/crypto/forestfish/objects/ipfs/connector/IPFSConnector.java new file mode 100644 index 0000000..1dcdedc --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/ipfs/connector/IPFSConnector.java @@ -0,0 +1,120 @@ +package crypto.forestfish.objects.ipfs.connector; + +import java.util.HashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import crypto.forestfish.objects.embedded.ipfs.IPFSDetails; +import crypto.forestfish.utils.HttpRequestUtils; +import crypto.forestfish.utils.SystemUtils; + +public class IPFSConnector { + + private static final Logger LOGGER = LoggerFactory.getLogger(IPFSConnector.class); + + private HashMap active_gatewayURLs; + + public IPFSConnector() { + super(); + LOGGER.debug("Creating a new IPFSConnector"); + + // Initial scan for active IPFS gateway nodes + this.updateActiveGatewayURLs(); + } + + public void updateActiveGatewayURLs() { + LOGGER.info("Updating list of active IPFS gateway URLs .."); + HashMap active_gatewayURLs_new = new HashMap<>(); + String url = "ipfs://" + IPFSDetails.network.getGateway_checker_cid(); + + // Walk through all gateways + for (String gatewayURL: IPFSDetails.network.getGatewayURLs()) { + + String content_url = url.replace("ipfs://", gatewayURL); + try { + String content = HttpRequestUtils.getBodyUsingGETUrlRequestOpportunistic(content_url); + if ("".equals(content)) { + LOGGER.debug("Unable to get gateway checked CID content from " + gatewayURL); + } else { + if (content.contains("Hello from IPFS Gateway Checker")) { + active_gatewayURLs_new.put(gatewayURL, true); + LOGGER.debug("Verified gateway checked CID content access from " + gatewayURL); + } else { + LOGGER.debug("Unable to get gateway checked CID content from " + gatewayURL); + } + } + } catch (Exception e) { + LOGGER.debug("Unable to get gateway checked CID content from " + gatewayURL); + } + } + this.active_gatewayURLs = active_gatewayURLs_new; + LOGGER.info("Nr of active IPFS gateways: " + this.getNrActiveGatewayURLs()); + } + + public Integer getNrActiveGatewayURLs() { + return this.active_gatewayURLs.size(); + } + + public HashMap getActive_gatewayURLs() { + return active_gatewayURLs; + } + + public void setActive_gatewayURLs(HashMap active_gatewayURLs) { + this.active_gatewayURLs = active_gatewayURLs; + } + + public String getStringContent(final String content_url) { + LOGGER.debug("getStringContent() called for " + content_url); + + if (false || + content_url.startsWith("https://") || + content_url.startsWith("ipfs://") || + false) { + // all good + } else { + LOGGER.warn("Unsupported URL schema for content_url: " + content_url); + return ""; + } + + if (this.active_gatewayURLs.isEmpty()) { + LOGGER.error("Number of active IPFS URLs is 0."); + SystemUtils.halt(); + } + + for (String gatewayURL: this.active_gatewayURLs.keySet()) { + String fetch_url = content_url; + if (content_url.startsWith("ipfs://")) fetch_url = fetch_url.replace("ipfs://", gatewayURL); + LOGGER.info("Attempting to fetch " + content_url); + String content = HttpRequestUtils.getBodyUsingGETUrlRequestOpportunistic(fetch_url); + if (!"".equals(content)) { + // Exit on first successful download + return content; + } + } + return ""; + } + + public byte[] getBinaryContent(String _content_url) { + if (false || + _content_url.startsWith("https://") || + _content_url.startsWith("ipfs://") || + false) { + // all good + } else { + LOGGER.warn("Unsupported URL schema for content_url: " + _content_url); + return null; + } + if (_content_url.endsWith("#arc3")) _content_url = _content_url.replace("#arc3", "arc3"); + + for (String gatewayURL: this.active_gatewayURLs.keySet()) { + String fetch_url = _content_url; + if (_content_url.startsWith("ipfs://")) fetch_url = fetch_url.replace("ipfs://", gatewayURL); + LOGGER.info("Attempting to fetch " + _content_url + " using " + gatewayURL); + + byte[] bytes = HttpRequestUtils.downloadImage(fetch_url); + if (null != bytes) return bytes; + } + return null; + } +} diff --git a/src/main/java/crypto/forestfish/objects/ipfs/model/IPFSNetwork.java b/src/main/java/crypto/forestfish/objects/ipfs/model/IPFSNetwork.java new file mode 100644 index 0000000..dabfdfe --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/ipfs/model/IPFSNetwork.java @@ -0,0 +1,47 @@ +package crypto.forestfish.objects.ipfs.model; + +import java.util.ArrayList; + +public class IPFSNetwork { + + private String name; + private ArrayList gatewayURLs = new ArrayList(); + private String gateway_checker_cid; + + public IPFSNetwork() { + super(); + } + + public IPFSNetwork(String _name, ArrayList _gatewayURLs, String _gateway_checker_cid) { + super(); + this.name = _name; + this.gatewayURLs = _gatewayURLs; + this.gateway_checker_cid = _gateway_checker_cid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ArrayList getGatewayURLs() { + return gatewayURLs; + } + + public void setGatewayURLs(ArrayList gatewayURLs) { + this.gatewayURLs = gatewayURLs; + } + + public String getGateway_checker_cid() { + return gateway_checker_cid; + } + + public void setGateway_checker_cid(String gateway_checker_cid) { + this.gateway_checker_cid = gateway_checker_cid; + } + + +} diff --git a/src/main/java/crypto/forestfish/objects/jwt/JWK.java b/src/main/java/crypto/forestfish/objects/jwt/JWK.java new file mode 100644 index 0000000..e4385f1 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/jwt/JWK.java @@ -0,0 +1,64 @@ +package crypto.forestfish.objects.jwt; + +public class JWK { + + private String kid; + private Long nbf; + private String use; + private String kty; + private String e; + private String n; + + public JWK() { + super(); + } + + public String getKid() { + return kid; + } + + public void setKid(String kid) { + this.kid = kid; + } + + public Long getNbf() { + return nbf; + } + + public void setNbf(Long nbf) { + this.nbf = nbf; + } + + public String getUse() { + return use; + } + + public void setUse(String use) { + this.use = use; + } + + public String getKty() { + return kty; + } + + public void setKty(String kty) { + this.kty = kty; + } + + public String getE() { + return e; + } + + public void setE(String e) { + this.e = e; + } + + public String getN() { + return n; + } + + public void setN(String n) { + this.n = n; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/jwt/JWKS.java b/src/main/java/crypto/forestfish/objects/jwt/JWKS.java new file mode 100644 index 0000000..4bd3186 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/jwt/JWKS.java @@ -0,0 +1,21 @@ +package crypto.forestfish.objects.jwt; + +import java.util.ArrayList; + +public class JWKS { + + private ArrayList keys = new ArrayList(); + + public JWKS() { + super(); + } + + public ArrayList getKeys() { + return keys; + } + + public void setKeys(ArrayList keys) { + this.keys = keys; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/jwt/JWTSignedDecodeResult.java b/src/main/java/crypto/forestfish/objects/jwt/JWTSignedDecodeResult.java new file mode 100644 index 0000000..8344bc5 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/jwt/JWTSignedDecodeResult.java @@ -0,0 +1,93 @@ +package crypto.forestfish.objects.jwt; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JWTSignedDecodeResult { + + private static final Logger LOGGER = LoggerFactory.getLogger(JWTSignedDecodeResult.class); + + private boolean invalid_jwt = false; + private boolean signature_valid = false; + private boolean expired = false; + private RegisteredClaims registered_claims; + private PublicClaims public_claims; + private PrivateClaims private_claims; + private TokenType token_type = TokenType.UNKNOWN; + + public JWTSignedDecodeResult() { + super(); + } + + public JWTSignedDecodeResult(boolean _invalid_jwt, boolean _signature_valid, boolean _expired, RegisteredClaims _registered_claims, PublicClaims _public_claims, PrivateClaims _private_claims, String _token_type) { + super(); + this.invalid_jwt = _invalid_jwt; + this.signature_valid = _signature_valid; + this.expired = _expired; + this.registered_claims = _registered_claims; + this.public_claims = _public_claims; + this.private_claims = _private_claims; + try { + this.token_type = TokenType.valueOf(_token_type); + } catch (Exception e) { + LOGGER.warn("Unable to set JWT token type to " + _token_type); + } + } + + public boolean isSignature_valid() { + return signature_valid; + } + + public void setSignature_valid(boolean signature_valid) { + this.signature_valid = signature_valid; + } + + public RegisteredClaims getRegistered_claims() { + return registered_claims; + } + + public void setRegistered_claims(RegisteredClaims registered_claims) { + this.registered_claims = registered_claims; + } + + public PublicClaims getPublic_claims() { + return public_claims; + } + + public void setPublic_claims(PublicClaims public_claims) { + this.public_claims = public_claims; + } + + public PrivateClaims getPrivate_claims() { + return private_claims; + } + + public void setPrivate_claims(PrivateClaims private_claims) { + this.private_claims = private_claims; + } + + public boolean isInvalid_jwt() { + return invalid_jwt; + } + + public void setInvalid_jwt(boolean invalid_jwt) { + this.invalid_jwt = invalid_jwt; + } + + public boolean isExpired() { + return expired; + } + + public void setExpired(boolean expired) { + this.expired = expired; + } + + public TokenType getToken_type() { + return token_type; + } + + public void setToken_type(TokenType token_type) { + this.token_type = token_type; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/jwt/JWTUnsignedDecodeResult.java b/src/main/java/crypto/forestfish/objects/jwt/JWTUnsignedDecodeResult.java new file mode 100644 index 0000000..b10f3f3 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/jwt/JWTUnsignedDecodeResult.java @@ -0,0 +1,64 @@ +package crypto.forestfish.objects.jwt; + +public class JWTUnsignedDecodeResult { + + private boolean invalid_jwt = false; + private String typ; + private String alg; + private String iss; + private String payloadJSON; + + public JWTUnsignedDecodeResult() { + super(); + } + + public JWTUnsignedDecodeResult(boolean invalid_jwt, String typ, String alg, String iss, String payloadJSON) { + super(); + this.invalid_jwt = invalid_jwt; + this.typ = typ; + this.alg = alg; + this.iss = iss; + this.payloadJSON = payloadJSON; + } + + public String getTyp() { + return typ; + } + + public void setTyp(String typ) { + this.typ = typ; + } + + public String getAlg() { + return alg; + } + + public void setAlg(String alg) { + this.alg = alg; + } + + public String getPayloadJSON() { + return payloadJSON; + } + + public void setPayloadJSON(String payloadJSON) { + this.payloadJSON = payloadJSON; + } + + public boolean isInvalid_jwt() { + return invalid_jwt; + } + + public void setInvalid_jwt(boolean invalid_jwt) { + this.invalid_jwt = invalid_jwt; + } + + public String getIss() { + return iss; + } + + public void setIss(String iss) { + this.iss = iss; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/jwt/PrivateClaims.java b/src/main/java/crypto/forestfish/objects/jwt/PrivateClaims.java new file mode 100644 index 0000000..c4ebf90 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/jwt/PrivateClaims.java @@ -0,0 +1,110 @@ +package crypto.forestfish.objects.jwt; + +import java.util.ArrayList; +import java.util.HashMap; + +public class PrivateClaims { + + private String evm_wallet_address = null; + private String token_type = null; + private String role = null; + + // Azure + private String oid = null; + private String tfp = null; + private String azp = null; + private String ver = null; + private ArrayList emails = null; + private HashMap erc20_ownership = null; + private HashMap nft_ownership = null; + + public PrivateClaims() { + super(); + } + + public String getEvm_wallet_address() { + return evm_wallet_address; + } + + public void setEvm_wallet_address(String evm_wallet_address) { + this.evm_wallet_address = evm_wallet_address; + } + + public String getOid() { + return oid; + } + + public void setOid(String oid) { + this.oid = oid; + } + + public String getTfp() { + return tfp; + } + + public void setTfp(String tfp) { + this.tfp = tfp; + } + + public String getAzp() { + return azp; + } + + public void setAzp(String azp) { + this.azp = azp; + } + + public String getVer() { + return ver; + } + + public void setVer(String ver) { + this.ver = ver; + } + + public ArrayList getEmails() { + return emails; + } + + public void setEmails(ArrayList emails) { + this.emails = emails; + } + + @Override + public String toString() { + return "emails: " + this.emails + " evm_wallet_address: " + this.evm_wallet_address + " oid: " + this.oid + " tfp: " + this.tfp + " azp: " + this.azp + " erc20_ownership: " + this.erc20_ownership + " nft_ownership: " + this.nft_ownership; + } + + public HashMap getErc20_ownership() { + return erc20_ownership; + } + + public void setErc20_ownership(HashMap erc20_ownership) { + this.erc20_ownership = erc20_ownership; + } + + public HashMap getNft_ownership() { + return nft_ownership; + } + + public void setNft_ownership(HashMap nft_ownership) { + this.nft_ownership = nft_ownership; + } + + public String getToken_type() { + return token_type; + } + + public void setToken_type(String token_type) { + this.token_type = token_type; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/jwt/PublicClaims.java b/src/main/java/crypto/forestfish/objects/jwt/PublicClaims.java new file mode 100644 index 0000000..6871e43 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/jwt/PublicClaims.java @@ -0,0 +1,224 @@ +package crypto.forestfish.objects.jwt; + +public class PublicClaims { + + // https://www.iana.org/assignments/jwt/jwt.xhtml + + // OpenID + private String name = null; + private String given_name = null; + private String family_name = null; + private String middle_name = null; + private String nickname = null; + private String preferred_username = null; + private String profile = null; + private String picture = null; + private String website = null; + private String email = null; + private Boolean email_verified = null; + private String gender = null; + private String birthdate = null; + private String zoneinfo = null; + private String locale = null; + private String phone_number = null; + private String phone_number_verified = null; + private String address = null; + private Integer updated_at = null; + private String azp = null; + private String nonce = null; + private Integer auth_time = null; + private String at_hash = null; + private String c_hash = null; + private String acr = null; + private String amr = null; + private String sub_jwk = null; + + // RFC7800 + private String jwk = null; // key used to issue/sign the token + private String jku = null; // JSON Web Key URL, JSON file jwks (set of keys) + + public PublicClaims() { + super(); + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public String getGiven_name() { + return given_name; + } + public void setGiven_name(String given_name) { + this.given_name = given_name; + } + public String getFamily_name() { + return family_name; + } + public void setFamily_name(String family_name) { + this.family_name = family_name; + } + public String getMiddle_name() { + return middle_name; + } + public void setMiddle_name(String middle_name) { + this.middle_name = middle_name; + } + public String getNickname() { + return nickname; + } + public void setNickname(String nickname) { + this.nickname = nickname; + } + public String getPreferred_username() { + return preferred_username; + } + public void setPreferred_username(String preferred_username) { + this.preferred_username = preferred_username; + } + public String getProfile() { + return profile; + } + public void setProfile(String profile) { + this.profile = profile; + } + public String getPicture() { + return picture; + } + public void setPicture(String picture) { + this.picture = picture; + } + public String getWebsite() { + return website; + } + public void setWebsite(String website) { + this.website = website; + } + public String getEmail() { + return email; + } + public void setEmail(String email) { + this.email = email; + } + public Boolean getEmail_verified() { + return email_verified; + } + public void setEmail_verified(Boolean email_verified) { + this.email_verified = email_verified; + } + public String getGender() { + return gender; + } + public void setGender(String gender) { + this.gender = gender; + } + public String getBirthdate() { + return birthdate; + } + public void setBirthdate(String birthdate) { + this.birthdate = birthdate; + } + public String getZoneinfo() { + return zoneinfo; + } + public void setZoneinfo(String zoneinfo) { + this.zoneinfo = zoneinfo; + } + public String getLocale() { + return locale; + } + public void setLocale(String locale) { + this.locale = locale; + } + public String getPhone_number() { + return phone_number; + } + public void setPhone_number(String phone_number) { + this.phone_number = phone_number; + } + public String getPhone_number_verified() { + return phone_number_verified; + } + public void setPhone_number_verified(String phone_number_verified) { + this.phone_number_verified = phone_number_verified; + } + public String getAddress() { + return address; + } + public void setAddress(String address) { + this.address = address; + } + public Integer getUpdated_at() { + return updated_at; + } + public void setUpdated_at(Integer updated_at) { + this.updated_at = updated_at; + } + public String getAzp() { + return azp; + } + public void setAzp(String azp) { + this.azp = azp; + } + public String getNonce() { + return nonce; + } + public void setNonce(String nonce) { + this.nonce = nonce; + } + public Integer getAuth_time() { + return auth_time; + } + public void setAuth_time(Integer auth_time) { + this.auth_time = auth_time; + } + public String getAt_hash() { + return at_hash; + } + public void setAt_hash(String at_hash) { + this.at_hash = at_hash; + } + public String getC_hash() { + return c_hash; + } + public void setC_hash(String c_hash) { + this.c_hash = c_hash; + } + public String getAcr() { + return acr; + } + public void setAcr(String acr) { + this.acr = acr; + } + public String getAmr() { + return amr; + } + public void setAmr(String amr) { + this.amr = amr; + } + public String getSub_jwk() { + return sub_jwk; + } + public void setSub_jwk(String sub_jwk) { + this.sub_jwk = sub_jwk; + } + + public String getJwk() { + return jwk; + } + public void setJwk(String jwk) { + this.jwk = jwk; + } + public String getJku() { + return jku; + } + public void setJku(String jku) { + this.jku = jku; + } + + @Override + public String toString() { + return "name: " + this.name + " given_name: " + this.given_name + " family_name: " + this.family_name + " middle_name: " + this.middle_name; + } +} diff --git a/src/main/java/crypto/forestfish/objects/jwt/RegisteredClaims.java b/src/main/java/crypto/forestfish/objects/jwt/RegisteredClaims.java new file mode 100644 index 0000000..7e5dea0 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/jwt/RegisteredClaims.java @@ -0,0 +1,78 @@ +package crypto.forestfish.objects.jwt; + +public class RegisteredClaims { + + // RFC 7519 + private String iss = ""; // who issued the token + private String sub = ""; // to whom the token was issued + private String aud = ""; // audience of the token + private String jti = ""; // unique identifier of the token + + private Integer iat = -1; // issued at + private Integer exp = -1; // expiration + private Integer nbf = -1; // not before + + public RegisteredClaims() { + super(); + } + + public RegisteredClaims(String iss, String sub, String aud, Integer iat, Integer exp, Integer nbf, String jti) { + super(); + this.iss = iss; + this.sub = sub; + this.aud = aud; + this.iat = iat; + this.exp = exp; + this.nbf = nbf; + this.jti = jti; + } + + public Integer getNbf() { + return nbf; + } + public void setNbf(Integer nbf) { + this.nbf = nbf; + } + public String getIss() { + return iss; + } + public void setIss(String iss) { + this.iss = iss; + } + public String getSub() { + return sub; + } + public void setSub(String sub) { + this.sub = sub; + } + public Integer getIat() { + return iat; + } + public void setIat(Integer iat) { + this.iat = iat; + } + public Integer getExp() { + return exp; + } + public void setExp(Integer exp) { + this.exp = exp; + } + public String getJti() { + return jti; + } + public void setJti(String jti) { + this.jti = jti; + } + public String getAud() { + return aud; + } + public void setAud(String aud) { + this.aud = aud; + } + + @Override + public String toString() { + return "iss: " + this.iss + " sub: " + this.sub + " aud: " + this.aud + " iat: " + this.iat + " exp: " + this.exp + " nbf: " + this.nbf + " jti: " + this.jti; + } + +} diff --git a/src/main/java/crypto/forestfish/objects/jwt/TokenType.java b/src/main/java/crypto/forestfish/objects/jwt/TokenType.java new file mode 100644 index 0000000..7577cf7 --- /dev/null +++ b/src/main/java/crypto/forestfish/objects/jwt/TokenType.java @@ -0,0 +1,7 @@ +package crypto.forestfish.objects.jwt; + +public enum TokenType { + AUTHN, + AUTHZ, + UNKNOWN +} \ No newline at end of file diff --git a/src/main/java/crypto/forestfish/utils/AVMUtils.java b/src/main/java/crypto/forestfish/utils/AVMUtils.java new file mode 100644 index 0000000..00f3882 --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/AVMUtils.java @@ -0,0 +1,3825 @@ +package crypto.forestfish.utils; + +import java.io.File; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.RoundingMode; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HexFormat; +import java.util.List; +import java.util.regex.Pattern; + +import org.bouncycastle.crypto.digests.SHA512tDigest; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.algorand.algosdk.account.Account; +import com.algorand.algosdk.crypto.Address; +import com.algorand.algosdk.transaction.SignedTransaction; +import com.algorand.algosdk.transaction.Transaction; +import com.algorand.algosdk.util.Encoder; +import com.algorand.algosdk.v2.client.common.Response; +import com.algorand.algosdk.v2.client.model.ApplicationLocalState; +import com.algorand.algosdk.v2.client.model.Asset; +import com.algorand.algosdk.v2.client.model.AssetHolding; +import com.algorand.algosdk.v2.client.model.Enums.TxType; +import com.algorand.algosdk.v2.client.model.HealthCheck; +import com.algorand.algosdk.v2.client.model.NodeStatusResponse; +import com.algorand.algosdk.v2.client.model.PendingTransactionResponse; +import com.algorand.algosdk.v2.client.model.PostTransactionsResponse; +import com.algorand.algosdk.v2.client.model.TransactionParametersResponse; +import com.algorand.algosdk.v2.client.model.TransactionsResponse; +import com.algorand.algosdk.v2.client.Utils; + +import crypto.forestfish.enums.BlockchainType; +import crypto.forestfish.enums.ExceptionType; +import crypto.forestfish.enums.avm.AVMChain; +import crypto.forestfish.enums.avm.AVMNFTStandard; +import crypto.forestfish.enums.avm.Unit; +import crypto.forestfish.objects.avm.AVMASAMutables; +import crypto.forestfish.objects.avm.AVMAccountASABalance; +import crypto.forestfish.objects.avm.AVMAccountBalance; +import crypto.forestfish.objects.avm.AVMAccountTxSummary; +import crypto.forestfish.objects.avm.AVMChainPortfolio; +import crypto.forestfish.objects.avm.AVMChainPortfolioDiff; +import crypto.forestfish.objects.avm.AVMCreateAssetResult; +import crypto.forestfish.objects.avm.AVMIndexerException; +import crypto.forestfish.objects.avm.AVMIndexerExceptionActionState; +import crypto.forestfish.objects.avm.AVMNativeValue; +import crypto.forestfish.objects.avm.AVMNftAccountBalance; +import crypto.forestfish.objects.avm.AVMPortfolio; +import crypto.forestfish.objects.avm.AVMPortfolioDiff; +import crypto.forestfish.objects.avm.AVMPortfolioDiffResult; +import crypto.forestfish.objects.avm.AVMPortfolioSimple; +import crypto.forestfish.objects.avm.AVMProviderException; +import crypto.forestfish.objects.avm.AVMProviderExceptionActionState; +import crypto.forestfish.objects.avm.AlgoIndexerNode; +import crypto.forestfish.objects.avm.AlgoLocalWallet; +import crypto.forestfish.objects.avm.AlgoRelayNode; +import crypto.forestfish.objects.avm.connector.AVMBlockChainConnector; +import crypto.forestfish.objects.avm.connector.AVMBlockChainUltraConnector; +import crypto.forestfish.objects.avm.model.asa.ASAContentOnchainReply; +import crypto.forestfish.objects.avm.model.asa.AVMASAInfo; +import crypto.forestfish.objects.avm.model.chain.AVMChainIndex; +import crypto.forestfish.objects.avm.model.chain.AVMChainInfo; +import crypto.forestfish.objects.avm.model.chain.AVMCurrency; +import crypto.forestfish.objects.avm.model.nft.ARC19Asset; +import crypto.forestfish.objects.avm.model.nft.ARC3Asset; +import crypto.forestfish.objects.avm.model.nft.ARC3Info; +import crypto.forestfish.objects.avm.model.nft.ARC69Asset; +import crypto.forestfish.objects.avm.model.nft.ARC69Info; +import crypto.forestfish.objects.avm.model.nft.ASAVerificationStatus; +import crypto.forestfish.objects.avm.model.nft.metadata.ARC3MetaData; +import crypto.forestfish.objects.avm.model.nft.metadata.ARC69ARC19MetaData; +import crypto.forestfish.objects.avm.model.nft.metadata.MetaDataEntry; +import crypto.forestfish.objects.embedded.avm.BlockchainDetailsAVM; +import crypto.forestfish.objects.ipfs.connector.IPFSConnector; +import io.ipfs.cid.Cid; +import io.ipfs.cid.Cid.Codec; +import io.ipfs.multihash.Multihash; + +public class AVMUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(AVMUtils.class); + + private static final Pattern ALGO_ADDRESS_PATTERN = Pattern.compile("[A-Z0-9]{58}$"); + + public static final Long txFee_microAlgo = 1000L; + public static final Long accountMinBalanceBase_microAlgo = 100000L; // Account holding ALGO, no asas etc.. + + public static AVMAccountBalance getAccountNativeBalance(AVMBlockChainConnector _connector, Address _address) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + Response respAcct = _connector.getProvider_instance().AccountInformation(_address).execute(); + if (!respAcct.isSuccessful()) { + LOGGER.error("respAcct.message(): " + respAcct.message()); + SystemUtils.halt(); + } + com.algorand.algosdk.v2.client.model.Account accountInfo = respAcct.body(); + long balance_microAlgo = accountInfo.amount; + Double balance_ALGO = Double.parseDouble("" + balance_microAlgo) / 1000000d; + boolean isEmpty = false; + if (balance_microAlgo == 0L) isEmpty = true; + return new AVMAccountBalance(balance_microAlgo, balance_ALGO, _connector.getChaininfo().getNativeCurrency(), isEmpty); + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static boolean isAccountOptinForASA(AVMBlockChainConnector _connector, Address _address, long assetID) { + boolean optedin = false; + List asset_holdings = getASAOwnershipInfoForAccount(_connector, _address); + for (AssetHolding assetHolding: asset_holdings) { + if (assetHolding.assetId.equals(assetID)) optedin = true; + } + return optedin; + } + + public static boolean isAccountOptinForASA(AVMBlockChainConnector _connector, Address _address, AVMASAInfo asaInfo) { + return isAccountOptinForASA(_connector, _address, asaInfo.getId()); + } + + public static BigInteger getAccountBalanceForASA(AVMBlockChainConnector _connector, Address _address, Long _assetID) { + List asset_holdings = getASAOwnershipInfoForAccount(_connector, _address); + for (AssetHolding assetHolding: asset_holdings) { + if (assetHolding.assetId.equals(_assetID)) { + return assetHolding.amount; + } + } + return new BigInteger("0"); + } + + public static AVMAccountASABalance getAccountBalanceForASA(AVMBlockChainConnector _connector, Address _address, AVMASAInfo asaInfo) { + List asset_holdings = getASAOwnershipInfoForAccount(_connector, _address); + for (AssetHolding assetHolding: asset_holdings) { + if (assetHolding.assetId.equals(asaInfo.getId())) { + return new AVMAccountASABalance(assetHolding.amount, asaInfo); + } + } + return new AVMAccountASABalance(new BigInteger("0"), asaInfo); + } + + public static String getASARawJSONResponse(AVMBlockChainConnector _connector, Long _assetID) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + Response respAss = _connector.getProvider_instance().GetAssetByID(_assetID).execute(); + if (!respAss.isSuccessful()) { + if (respAss.message().contains("asset does not exist")) { + LOGGER.error("respAss.message(): " + respAss.message()); + return null; + } else { + LOGGER.error("respAss.message(): " + respAss.message()); + SystemUtils.halt(); + } + } + Asset asset = respAss.body(); + return asset.toString(); + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static Boolean checkIfASAExists(AVMBlockChainConnector _connector, Long _assetID) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + Response respAss = _connector.getProvider_instance().GetAssetByID(_assetID).execute(); + if (!respAss.isSuccessful()) { + if (respAss.message().contains("asset does not exist")) { + return false; + } else { + LOGGER.error("respAss.message(): " + respAss.message()); + SystemUtils.halt(); + } + } + return true; + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static ArrayList getASAConfigTransactionNotes(AVMBlockChainConnector _connector, Long _assetID) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + ArrayList result = new ArrayList(); + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + // Transactions are returned oldest to newest. Max 10000 + Response respCall = _connector.getIndexer_instance() + .lookupAssetTransactions(_assetID) + .txType(TxType.ACFG) + .limit(Long.MAX_VALUE) + .execute(); + if (!respCall.isSuccessful()) { + LOGGER.error("getASAConfigTransactionNotes() respCall.message(): " + respCall.message()); + SystemUtils.halt(); + } + + TransactionsResponse txs = respCall.body(); + if (txs.transactions.size() > 0); { + for (com.algorand.algosdk.v2.client.model.Transaction tx: txs.transactions) { + boolean assetConfigTx = false; + if (null != tx.assetConfigTransaction) { + assetConfigTx = true; + } + if (null != tx.note()) { + String txnote = new String(tx.note, StandardCharsets.UTF_8); + LOGGER.debug(" * txid: " + tx.id + ",confirmedround=" + tx.confirmedRound + ": " + tx.sender + " txtype=" + tx.txType + " txnote: " + txnote + ", assetconfig:" + assetConfigTx); + txnote = StringsUtils.decodeBase64String(tx.note()); + + MetaDataEntry entry = new MetaDataEntry(txnote); + entry.setTx_id(tx.id); + entry.setTx_confirmedRound(tx.confirmedRound); + entry.setTx_roundTime(tx.roundTime); + result.add(entry); + } + } + } + + return result; + + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return result; + } + + public static String getASALatestConfigTransactionNote(AVMBlockChainConnector _connector, Long _assetID) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + // Transactions are returned oldest to newest. Max 10000 + Response respCall = _connector.getIndexer_instance() + .lookupAssetTransactions(_assetID) + .txType(TxType.ACFG) + .limit(Long.MAX_VALUE) + .execute(); + if (!respCall.isSuccessful()) { + LOGGER.error("getASALatestConfigTransactionNote() respCall.message(): " + respCall.message()); + SystemUtils.halt(); + } + + String latesttxnote = ""; + TransactionsResponse txs = respCall.body(); + if (txs.transactions.size() > 0); { + for (com.algorand.algosdk.v2.client.model.Transaction tx: txs.transactions) { + boolean assetConfigTx = false; + if (null != tx.assetConfigTransaction) { + assetConfigTx = true; + } + if (null != tx.note()) { + String txnote = new String(tx.note, StandardCharsets.UTF_8); + LOGGER.debug(" * txid: " + tx.id + ",confirmedround=" + tx.confirmedRound + ": " + tx.sender + " txtype=" + tx.txType + " txnote: " + txnote + ", assetconfig:" + assetConfigTx); + latesttxnote = StringsUtils.decodeBase64String(tx.note()); + } + } + } + + return latesttxnote; + + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static AVMAccountTxSummary getTransactionSummaryForAccount(AVMBlockChainConnector _connector, String _address) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + + HashMap txtype_counts = new HashMap<>(); + long txcount = 0L; + + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + // Transactions are returned oldest to newest. Max 10000 + Response respCall = _connector.getIndexer_instance() + .lookupAccountTransactions(createAddressFromSTR(_address)) + .limit(Long.MAX_VALUE) + .execute(); + if (!respCall.isSuccessful()) { + LOGGER.debug(_connector.getChain() + " getTransactionSummaryForAccount() respCall.message(): " + respCall.message()); + + // indexer exceptions (readonly) + AVMIndexerException avmE = analyzeIndexerException(_connector.getChain(), _connector.getIndexerNode(), new Exception(respCall.message())); + AVMIndexerExceptionActionState avmEAS = actAndGetStateAVMIndexerException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } else { + + TransactionsResponse txs = respCall.body(); + if (txs.transactions.size() > 0); { + for (com.algorand.algosdk.v2.client.model.Transaction tx: txs.transactions) { + Long currentCount = txtype_counts.get(tx.txType.toString()); + if (null == currentCount) currentCount = 0L; + currentCount++; + txcount++; + txtype_counts.put(tx.txType.toString(), currentCount); + } + } + + return new AVMAccountTxSummary(txtype_counts, txcount); + + } + + } catch (Exception ex) { + // index exceptions (readonly) + AVMIndexerException avmE = analyzeIndexerException(_connector.getChain(), _connector.getIndexerNode(), ex); + AVMIndexerExceptionActionState avmEAS = actAndGetStateAVMIndexerException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static AVMNFTStandard identifyARCStandard(AVMBlockChainConnector _connector, Long assetID) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + Response respAss = _connector.getProvider_instance().GetAssetByID(assetID).execute(); + if (!respAss.isSuccessful()) { + LOGGER.error("respAss.message(): " + respAss.message()); + SystemUtils.halt(); + } + Asset asset = respAss.body(); + ASAContentOnchainReply reply = JSONUtils.createPOJOFromJSON(asset.toString(), ASAContentOnchainReply.class); + + AVMNFTStandard standard = identifyARCStandardFromASAOnChainReply(_connector, reply); + return standard; + + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static ASAContentOnchainReply getASAJSON(String assetJSON) { + ASAContentOnchainReply reply = JSONUtils.createPOJOFromJSON(assetJSON, ASAContentOnchainReply.class); + return reply; + } + + public static AVMNFTStandard identifyARCStandardFromASAAssetID(AVMBlockChainConnector _connector, Long _assetID) { + String assetJSON = AVMUtils.getASARawJSONResponse(_connector, _assetID); + ASAContentOnchainReply reply = JSONUtils.createPOJOFromJSON(assetJSON, ASAContentOnchainReply.class); + return identifyARCStandardFromASAOnChainReply(_connector, reply); + } + + public static AVMNFTStandard identifyARCStandardFromASAJSON(AVMBlockChainConnector _connector, String _assetJSON) { + ASAContentOnchainReply reply = JSONUtils.createPOJOFromJSON(_assetJSON, ASAContentOnchainReply.class); + return identifyARCStandardFromASAOnChainReply(_connector, reply); + } + + public static AVMNFTStandard identifyARCStandardFromASAOnChainReply(AVMBlockChainConnector _connector, ASAContentOnchainReply _reply) { + + /** + * ARC3 + */ + if (_reply.getParams().getName().equals("arc3")) return AVMNFTStandard.ARC3; + if (_reply.getParams().getName().endsWith("@arc3")) return AVMNFTStandard.ARC3; + if ((null != _reply.getParams().getUrl()) && (_reply.getParams().getUrl().endsWith("#arc3"))) return AVMNFTStandard.ARC3; + + /** + * ARC69 + */ + if (true && + (null != _reply.getParams().getUnit_name()) && + (null != _reply.getParams().getName()) && + (null != _reply.getParams().getTotal()) && + (null != _reply.getParams().getDecimals()) && + (null != _reply.getParams().getUrl()) && + true) { + + // Grab the latest tx note and check if it qualifies as ARC69 metadata + // we dont want to do this for non arcs (=timeouts) so require + // - total supply below 100k or media type specifier (#p, #v ..) + // - url must be possible mediadata link + if (false || + (_reply.getParams().getTotal().compareTo(new BigInteger("100000")) < 0) || + _reply.getParams().getUrl().contains("#i") || // image + _reply.getParams().getUrl().contains("#a") || // audio + _reply.getParams().getUrl().contains("#v") || // video + _reply.getParams().getUrl().contains("#h") || // html + false) { + if (false || + _reply.getParams().getUrl().startsWith("http://") || + _reply.getParams().getUrl().startsWith("https://") || + _reply.getParams().getUrl().startsWith("ipfs://") || + false) { + + // We really need to check the URL JSON metadata "standard" key here to make sure it states "arc69" + LOGGER.debug("Using indexer to fetch latest tx note for asa id " + _reply.getIndex() + ", ASA URL is " + _reply.getParams().getUrl() + " total: " + _reply.getParams().getTotal()); + + String latesttxnote = AVMUtils.getASALatestConfigTransactionNote(_connector, _reply.getIndex()); + latesttxnote = StringsUtils.cleanJSON(latesttxnote); + if (null == latesttxnote) return AVMNFTStandard.UNKNOWN; + if (true && + latesttxnote.contains("{") && + latesttxnote.contains("}") && + true) { + latesttxnote = StringsUtils.cleanJSON(latesttxnote); + ARC69ARC19MetaData arcmetadata = JSONUtils.createPOJOFromJSON(latesttxnote, ARC69ARC19MetaData.class); + if (null == arcmetadata) return AVMNFTStandard.UNKNOWN; + if (true && + (null != arcmetadata.getStandard()) && + "arc69".equals(arcmetadata.getStandard()) && + true) { + return AVMNFTStandard.ARC69; + } + } + } + } + } + + /* + * ARC19 + */ + if ((null != _reply.getParams().getUrl()) && (_reply.getParams().getUrl().contains("template-ipfs"))) return AVMNFTStandard.ARC19; + + return AVMNFTStandard.UNKNOWN; + } + + public static ARC3Asset getARC3Info(AVMBlockChainConnector _connector, Long _assetID) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + Response respAss = _connector.getProvider_instance().GetAssetByID(_assetID).execute(); + if (!respAss.isSuccessful()) { + LOGGER.error("respAss.message(): " + respAss.message()); + SystemUtils.halt(); + } + Asset asset = respAss.body(); + return createARC3Asset(asset.toString()); + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static ARC3Asset createARC3Asset(String assetString) { + try { + ASAContentOnchainReply reply = JSONUtils.createPOJOFromJSON(assetString.toString(), ASAContentOnchainReply.class); + if (null != reply) { + Address manager_addr = null; + if (null != reply.getParams().getManager()) manager_addr = new Address(reply.getParams().getManager()); + + Address reserve_addr = null; + if (null != reply.getParams().getReserve()) reserve_addr = new Address(reply.getParams().getReserve()); + + Address freeze_addr = null; + if (null != reply.getParams().getFreeze()) freeze_addr = new Address(reply.getParams().getFreeze()); + + Address clawback_addr = null; + if (null != reply.getParams().getClawback()) clawback_addr = new Address(reply.getParams().getClawback()); + + ARC3Asset asset3 = new ARC3Asset(reply.getIndex(), reply.getParams().getUnit_name(), reply.getParams().getName(), reply.getParams().getUrl(), + reply.getParams().getTotal(), reply.getParams().getDecimals(), reply.getParams().getDefault_frozen(),reply.getParams().getMetadata_hash(), + manager_addr, + reserve_addr, + freeze_addr, + clawback_addr); + return asset3; + } else { + LOGGER.error("Not a valid ARC3 reply .. ABORT!"); + SystemUtils.halt(); + } + } catch (Exception e) { + LOGGER.warn("Exception: " + e.getMessage()); + return null; + } + return null; + } + + public static ARC69Asset getARC69Info(AVMBlockChainConnector _connector, Long _assetID) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + Response respAss = _connector.getProvider_instance().GetAssetByID(_assetID).execute(); + if (!respAss.isSuccessful()) { + LOGGER.error("respAss.message(): " + respAss.message()); + SystemUtils.halt(); + } + Asset asset = respAss.body(); + return createARC69Asset(asset.toString()); + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static ARC69Asset createARC69Asset(String assetString) { + try { + ASAContentOnchainReply reply = JSONUtils.createPOJOFromJSON(assetString, ASAContentOnchainReply.class); + if (null != reply) { + + Address manager_addr = null; + if (null != reply.getParams().getManager()) manager_addr = new Address(reply.getParams().getManager()); + + Address reserve_addr = null; + if (null != reply.getParams().getReserve()) reserve_addr = new Address(reply.getParams().getReserve()); + + Address freeze_addr = null; + if (null != reply.getParams().getFreeze()) freeze_addr = new Address(reply.getParams().getFreeze()); + + Address clawback_addr = null; + if (null != reply.getParams().getClawback()) clawback_addr = new Address(reply.getParams().getClawback()); + + ARC69Asset asset69 = new ARC69Asset(reply.getIndex(), reply.getParams().getUnit_name(), reply.getParams().getName(), reply.getParams().getUrl(), + reply.getParams().getTotal(), reply.getParams().getDecimals(), reply.getParams().getDefault_frozen(), + manager_addr, + reserve_addr, + freeze_addr, + clawback_addr); + return asset69; + } else { + LOGGER.error("Not a valid ARC69 reply .. ABORT!"); + SystemUtils.halt(); + } + } catch (Exception e) { + LOGGER.warn("Exception: " + e.getMessage()); + return null; + } + return null; + } + + public static ARC19Asset getARC19Info(AVMBlockChainConnector _connector, Long _assetID) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + Response respAss = _connector.getProvider_instance().GetAssetByID(_assetID).execute(); + if (!respAss.isSuccessful()) { + LOGGER.error("respAss.message(): " + respAss.message()); + SystemUtils.halt(); + } + Asset asset = respAss.body(); + return createARC19Asset(asset.toString()); + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static ARC19Asset createARC19Asset(String assetString) { + try { + ASAContentOnchainReply reply = JSONUtils.createPOJOFromJSON(assetString, ASAContentOnchainReply.class); + if (null != reply) { + + Address manager_addr = null; + if (null != reply.getParams().getManager()) manager_addr = new Address(reply.getParams().getManager()); + + Address reserve_addr = null; + if (null != reply.getParams().getReserve()) reserve_addr = new Address(reply.getParams().getReserve()); + + Address freeze_addr = null; + if (null != reply.getParams().getFreeze()) freeze_addr = new Address(reply.getParams().getFreeze()); + + Address clawback_addr = null; + if (null != reply.getParams().getClawback()) clawback_addr = new Address(reply.getParams().getClawback()); + + ARC19Asset asset69 = new ARC19Asset(reply.getIndex(), reply.getParams().getUnit_name(), reply.getParams().getName(), reply.getParams().getUrl(), + reply.getParams().getTotal(), reply.getParams().getDecimals(), reply.getParams().getDefault_frozen(), + manager_addr, + reserve_addr, + freeze_addr, + clawback_addr); + return asset69; + } else { + LOGGER.error("Not a valid ARC19 reply .. ABORT!"); + SystemUtils.halt(); + } + } catch (Exception e) { + LOGGER.warn("Exception: " + e.getMessage()); + return null; + } + return null; + } + + public static String getChainGenesis(AVMBlockChainConnector _connector) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + Response resp = _connector.getProvider_instance().GetGenesis().execute(); + if (!resp.isSuccessful()) { + LOGGER.error("resp.message(): " + resp.message()); + SystemUtils.halt(); + } + String genesis = resp.body(); + return genesis; + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static Long getLastRound(AVMBlockChainConnector _connector) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + Response resp = _connector.getProvider_instance().GetStatus().execute(); + if (!resp.isSuccessful()) { + LOGGER.debug(_connector.getRelayNode().getUrl() + " resp.message(): " + resp.message().replace("\n", "")); + + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), new Exception(resp.message())); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } else { + NodeStatusResponse status = resp.body(); + return status.lastRound; + } + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static Long getIndexerHealthCheck(AVMBlockChainConnector _connector) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + Response resp = _connector.getIndexer_instance().makeHealthCheck().execute(); + if (!resp.isSuccessful()) { + LOGGER.error("resp.message(): " + resp.message()); + SystemUtils.halt(); + } + HealthCheck status = resp.body(); + return status.round; + } catch (Exception ex) { + // tx exceptions (readonly) + AVMIndexerException avmE = analyzeIndexerException(_connector.getChain(), _connector.getIndexerNode(), ex); + AVMIndexerExceptionActionState avmEAS = actAndGetStateAVMIndexerException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static List getASAOwnershipInfoForAccount(AVMBlockChainConnector _connector, Address _address) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + Response respAcct = _connector.getProvider_instance().AccountInformation(_address).execute(); + if (!respAcct.isSuccessful()) { + LOGGER.error("respAcct.message(): " + respAcct.message()); + SystemUtils.halt(); + } + com.algorand.algosdk.v2.client.model.Account accountInfo = respAcct.body(); + return accountInfo.assets; + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static List getLocalStateInfoForAccount(AVMBlockChainConnector _connector, Address _address) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + Response respAcct = _connector.getProvider_instance().AccountInformation(_address).execute(); + if (!respAcct.isSuccessful()) { + LOGGER.error("respAcct.message(): " + respAcct.message()); + SystemUtils.halt(); + } + com.algorand.algosdk.v2.client.model.Account accountInfo = respAcct.body(); + return accountInfo.appsLocalState; + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static Long getTotalAppsOptedInForAccount(AVMBlockChainConnector _connector, Address _address) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + Response respAcct = _connector.getProvider_instance().AccountInformation(_address).execute(); + if (!respAcct.isSuccessful()) { + LOGGER.error("respAcct.message(): " + respAcct.message()); + SystemUtils.halt(); + } + com.algorand.algosdk.v2.client.model.Account accountInfo = respAcct.body(); + return accountInfo.totalAppsOptedIn; + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static Long getTotalAssetsOptedInForAccount(AVMBlockChainConnector _connector, Address _address) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + Response respAcct = _connector.getProvider_instance().AccountInformation(_address).execute(); + if (!respAcct.isSuccessful()) { + LOGGER.error("respAcct.message(): " + respAcct.message()); + SystemUtils.halt(); + } + com.algorand.algosdk.v2.client.model.Account accountInfo = respAcct.body(); + return accountInfo.totalAssetsOptedIn; + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static Boolean holdsAssets(AVMBlockChainConnector _connector, Address _address) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + Response respAcct = _connector.getProvider_instance().AccountInformation(_address).execute(); + if (!respAcct.isSuccessful()) { + LOGGER.error("respAcct.message(): " + respAcct.message()); + SystemUtils.halt(); + } + com.algorand.algosdk.v2.client.model.Account accountInfo = respAcct.body(); + List asas_owned = accountInfo.assets; + List localstates_owned = accountInfo.appsLocalState; + Long total_apps_optedin = accountInfo.totalAppsOptedIn; + Long total_assets_optedin = accountInfo.totalAssetsOptedIn; + Long total_created_apps = accountInfo.totalCreatedApps; + + /* + System.out.println("asas_owned.size() : " + asas_owned.size()); + System.out.println("localstates_owned.size() : " + localstates_owned.size()); + System.out.println("total_apps_optedin : " + total_apps_optedin); + System.out.println("total_assets_optedin : " + total_assets_optedin); + System.out.println("total_created_apps : " + total_created_apps); + */ + + if (false || + (asas_owned.size()>0) || + (localstates_owned.size()>0) || + (total_apps_optedin > 0) || + (total_created_apps > 0) || + (total_assets_optedin > 0) || + false) { + return true; + } else { + return false; + } + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return true; + } + + public static Long getTotalCreatedAppsForAccount(AVMBlockChainConnector _connector, Address _address) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + Response respAcct = _connector.getProvider_instance().AccountInformation(_address).execute(); + if (!respAcct.isSuccessful()) { + LOGGER.error("respAcct.message(): " + respAcct.message()); + SystemUtils.halt(); + } + com.algorand.algosdk.v2.client.model.Account accountInfo = respAcct.body(); + return accountInfo.totalCreatedApps; + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static Boolean isAccountRekeyed(AVMBlockChainConnector _connector, Address _address) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + Response respAcct = _connector.getProvider_instance().AccountInformation(_address).execute(); + if (!respAcct.isSuccessful()) { + LOGGER.error("respAcct.message(): " + respAcct.message()); + SystemUtils.halt(); + } + com.algorand.algosdk.v2.client.model.Account accountInfo = respAcct.body(); + if (null == accountInfo.authAddr) { + return false; + } else { + return true; + } + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static Boolean getRekeyAddressForAccount(AVMBlockChainConnector _connector, Address _address) { + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + Response respAcct = _connector.getProvider_instance().AccountInformation(_address).execute(); + if (!respAcct.isSuccessful()) { + LOGGER.error("respAcct.message(): " + respAcct.message()); + SystemUtils.halt(); + } + com.algorand.algosdk.v2.client.model.Account accountInfo = respAcct.body(); + if (null == accountInfo.authAddr) { + return false; + } else { + return true; + } + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static Long calculateMinimumBalanceForASAOwnedByAccount(AVMBlockChainConnector _connector, Address _address) { + Long minBalance = 0L; + + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + + // Get accountinfo + Response respAcct = _connector.getProvider_instance().AccountInformation(_address).execute(); + if (!respAcct.isSuccessful()) { + LOGGER.error("respAcct.message(): " + respAcct.message()); + SystemUtils.halt(); + } + com.algorand.algosdk.v2.client.model.Account accountInfo = respAcct.body(); + + // ALGO account base, 0.1 ALGO + if (accountInfo.amount > 0L) { + minBalance = minBalance + 100000L; + } + + // Each ASA asset opt-in, 0.1 ALGO + minBalance = minBalance + accountInfo.assets.size() * 100000L; + + // App opt-in + /** + * https://developer.algorand.org/docs/get-details/dapps/smart-contracts/apps/ + * - 100,000 microAlgo base fee of opt-in + * - 25,000 + 3,500 = 28,500 for each Uint in the Local State schema + * - 25,000 + 25,000 = 50,000 for each byte-slice in the Local State schema + * + * 100,000 + (25,000+3,500)*schema.NumUint + (25,000+25,000)*schema.NumByteSlice + */ + minBalance = minBalance + accountInfo.appsLocalState.size() * 100000L; + + // App creation + /** + * https://developer.algorand.org/docs/get-details/dapps/smart-contracts/apps/ + * - 100,000 microAlgo base fee for each page requested. + * - 25,000 + 3,500 = 28,500 for each Uint in the Global State schema + * - 25,000 + 25,000 = 50,000 for each byte-slice in the Global State schema + * + * 100,000*(1+ExtraProgramPages) + (25,000+3,500)*schema.NumUint + (25,000+25,000)*schema.NumByteSlice + */ + + // TODO + /* + List localstateinfo = accountInfo.appsLocalState; + for (ApplicationLocalState applocalstate: localstateinfo) { + } + */ + + return minBalance; + + } catch (Exception ex) { + // tx exceptions (readonly) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, false); + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + LOGGER.error("Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static AVMChainInfo getAVMChainInfo(AVMChain _chain) { + AVMChainIndex idx = BlockchainDetailsAVM.generateAVMChainIndex(); + return idx.getNetworks().get(_chain); + } + + public static String sendTXTransferASA(AVMBlockChainConnector _connector, AlgoLocalWallet _fromWallet, Address _target_address, AVMASAInfo _asaInfo, BigInteger _assetAmount, boolean _haltOnUnconfirmedTX) { + return sendTXTransferASA(_connector, _fromWallet, _target_address, _asaInfo.getId(), _assetAmount, _haltOnUnconfirmedTX); + } + + public static String sendTXTransferASA(AVMBlockChainConnector _connector, AlgoLocalWallet _fromWallet, Address _target_address, Long _assetid, BigInteger _assetAmount, boolean _haltOnUnconfirmedTX) { + String hash = null; + boolean debug = false; + + boolean confirmedTransaction = false; + int txAttemptCount = 0; + int requestCount = 0; + + while (!confirmedTransaction && (txAttemptCount<5) && (requestCount<15)) { + requestCount++; + + try { + + // Construct the transaction + Response < TransactionParametersResponse > resp = _connector.getProvider_instance().TransactionParams().execute(); + if (!resp.isSuccessful()) { + throw new Exception(resp.message()); + } + TransactionParametersResponse params = resp.body(); + if (params == null) { + throw new Exception("Params retrieval error"); + } + JSONObject jsonObj = new JSONObject(params.toString()); + if (debug) System.out.println("Algorand suggested parameters: " + jsonObj.toString(2)); + + Transaction txn = Transaction.AssetTransferTransactionBuilder() + .sender(_fromWallet.fetchAccount().getAddress()) + .assetReceiver(_target_address) + .assetAmount(_assetAmount) + .assetIndex(_assetid) + .suggestedParams(params) + .build(); + + // Sign the transaction + SignedTransaction signedTxn = _fromWallet.fetchAccount().signTransaction(txn); + if (debug) System.out.println("Signed transaction with txid: " + signedTxn.transactionID); + + // Submit the transaction to the network + byte[] encodedTxBytes = Encoder.encodeToMsgPack(signedTxn); + Response < PostTransactionsResponse > rawtxresponse = _connector.getProvider_instance().RawTransaction().rawtxn(encodedTxBytes).execute(); + if (!rawtxresponse.isSuccessful()) { + throw new Exception(rawtxresponse.message()); + } + String id = rawtxresponse.body().txId; + + // Wait for transaction confirmation + PendingTransactionResponse pTrx = Utils.waitForConfirmation(_connector.getProvider_instance(), id, 4); + if (debug) System.out.println("Transaction " + id + " confirmed in round " + pTrx.confirmedRound); + hash = id; + confirmedTransaction = true; + + // Read the transaction + if (debug) { + JSONObject jsonObj2 = new JSONObject(pTrx.toString()); + System.out.println("Transaction information (with notes): " + jsonObj2.toString(2)); + if (null != pTrx.txn.tx.note) System.out.println("Decoded note: " + new String(pTrx.txn.tx.note)); + System.out.println("Amount: " + new String(pTrx.txn.tx.amount.toString())); + System.out.println("Fee: " + new String(pTrx.txn.tx.fee.toString())); + } + } catch (Exception ex) { + // tx exceptions (readwrite) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, _haltOnUnconfirmedTX); + if (avmE.isNodeInteraction()) txAttemptCount++; + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + + return hash; + } + + public static String sendTXOptInToAsset(AVMBlockChainConnector _connector, AlgoLocalWallet _algoWallet, AVMASAInfo _asaInfo, boolean _haltOnUnconfirmedTX) { + return sendTXOptInToAsset(_connector, _algoWallet, _asaInfo.getId(), _haltOnUnconfirmedTX); + } + + public static String sendTXOptInToAsset(AVMBlockChainConnector _connector, AlgoLocalWallet _algoWallet, Long assetID, boolean _haltOnUnconfirmedTX) { + String hash = null; + boolean debug = false; + + boolean confirmedTransaction = false; + int txAttemptCount = 0; + int requestCount = 0; + + while (!confirmedTransaction && (txAttemptCount<5) && (requestCount<15)) { + requestCount++; + + try { + + // Construct the transaction + Response < TransactionParametersResponse > resp = _connector.getProvider_instance().TransactionParams().execute(); + if (!resp.isSuccessful()) { + throw new Exception(resp.message()); + } + TransactionParametersResponse params = resp.body(); + if (params == null) { + throw new Exception("Params retrieval error"); + } + JSONObject jsonObj = new JSONObject(params.toString()); + if (debug) System.out.println("Algorand suggested parameters: " + jsonObj.toString(2)); + + Transaction txn = Transaction.AssetAcceptTransactionBuilder() + .acceptingAccount(_algoWallet.fetchAccount().getAddress()) + .assetIndex(assetID) + .suggestedParams(params) + .build(); + + // Sign the transaction + SignedTransaction signedTxn = _algoWallet.fetchAccount().signTransaction(txn); + if (debug) System.out.println("Signed transaction with txid: " + signedTxn.transactionID); + + // Submit the transaction to the network + byte[] encodedTxBytes = Encoder.encodeToMsgPack(signedTxn); + Response < PostTransactionsResponse > rawtxresponse = _connector.getProvider_instance().RawTransaction().rawtxn(encodedTxBytes).execute(); + if (!rawtxresponse.isSuccessful()) { + throw new Exception(rawtxresponse.message()); + } + String id = rawtxresponse.body().txId; + + // Wait for transaction confirmation + PendingTransactionResponse pTrx = Utils.waitForConfirmation(_connector.getProvider_instance(), id, 4); + if (debug) System.out.println("Transaction " + id + " confirmed in round " + pTrx.confirmedRound); + hash = id; + confirmedTransaction = true; + + // Read the transaction + if (debug) { + JSONObject jsonObj2 = new JSONObject(pTrx.toString()); + System.out.println("Transaction information (with notes): " + jsonObj2.toString(2)); + if (null != pTrx.txn.tx.note) System.out.println("Decoded note: " + new String(pTrx.txn.tx.note)); + System.out.println("Amount: " + new String(pTrx.txn.tx.amount.toString())); + System.out.println("Fee: " + new String(pTrx.txn.tx.fee.toString())); + } + } catch (Exception ex) { + // tx exceptions (readwrite) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, _haltOnUnconfirmedTX); + if (avmE.isNodeInteraction()) txAttemptCount++; + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + + return hash; + } + + public static String sendTXOptOutToAsset(AVMBlockChainConnector _connector, AlgoLocalWallet _algoWallet, String _receiver_address, Long assetID, boolean _haltOnUnconfirmedTX, BigInteger _asaAmount) { + String hash = null; + boolean debug = false; + + boolean confirmedTransaction = false; + int txAttemptCount = 0; + int requestCount = 0; + + while (!confirmedTransaction && (txAttemptCount<5) && (requestCount<15)) { + requestCount++; + + try { + + // Construct the transaction + Response < TransactionParametersResponse > resp = _connector.getProvider_instance().TransactionParams().execute(); + if (!resp.isSuccessful()) { + throw new Exception(resp.message()); + } + TransactionParametersResponse params = resp.body(); + if (params == null) { + throw new Exception("Params retrieval error"); + } + JSONObject jsonObj = new JSONObject(params.toString()); + if (debug) System.out.println("Algorand suggested parameters: " + jsonObj.toString(2)); + + Transaction txn = Transaction.AssetTransferTransactionBuilder() + .sender(_algoWallet.getAddress()) + .assetReceiver(_receiver_address) + .assetCloseTo(_receiver_address) + .assetIndex(assetID) + .assetAmount(_asaAmount) + .suggestedParams(params) + .build(); + + // Sign the transaction + SignedTransaction signedTxn = _algoWallet.fetchAccount().signTransaction(txn); + if (debug) System.out.println("Signed transaction with txid: " + signedTxn.transactionID); + + // Submit the transaction to the network + byte[] encodedTxBytes = Encoder.encodeToMsgPack(signedTxn); + Response < PostTransactionsResponse > rawtxresponse = _connector.getProvider_instance().RawTransaction().rawtxn(encodedTxBytes).execute(); + if (!rawtxresponse.isSuccessful()) { + throw new Exception(rawtxresponse.message()); + } + String id = rawtxresponse.body().txId; + + // Wait for transaction confirmation + PendingTransactionResponse pTrx = Utils.waitForConfirmation(_connector.getProvider_instance(), id, 4); + if (debug) System.out.println("Transaction " + id + " confirmed in round " + pTrx.confirmedRound); + hash = id; + confirmedTransaction = true; + + // Read the transaction + if (debug) { + JSONObject jsonObj2 = new JSONObject(pTrx.toString()); + System.out.println("Transaction information (with notes): " + jsonObj2.toString(2)); + if (null != pTrx.txn.tx.note) System.out.println("Decoded note: " + new String(pTrx.txn.tx.note)); + System.out.println("Amount: " + new String(pTrx.txn.tx.amount.toString())); + System.out.println("Fee: " + new String(pTrx.txn.tx.fee.toString())); + } + } catch (Exception ex) { + + // Method specific error messages + if (ex.getMessage().contains("cannot close asset ID in allocating account")) { + LOGGER.error("You just attempted to opt-out of an asset you are the creator of. Not possible. Rethink your life choices."); + SystemUtils.halt(); + } + + // tx exceptions (readwrite) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, _haltOnUnconfirmedTX); + if (avmE.isNodeInteraction()) txAttemptCount++; + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + + return hash; + } + + public static String sendTXWithNativeCurrency(AVMBlockChainConnector _connector, AlgoLocalWallet _algoWallet, Address _target_address, AVMNativeValue _nativevalue) { + String txhash = sendTXWithNativeCurrency(_connector, _algoWallet, _target_address, _nativevalue, true); + return txhash; + } + + public static String sendTXWithNativeCurrency(AVMBlockChainConnector _connector, AlgoLocalWallet _algoWallet, Address _target_address, AVMNativeValue _nativevalue, boolean _haltOnUnconfirmedTX) { + String hash = null; + boolean debug = false; + + boolean tx_submitted = false; + String txid = null; + + // Sanitycheck + if (!AVMUtils.isValidAlgorandAddress(_target_address.toString())) { + LOGGER.info("Target address is not valid: " + _target_address.toString()); + SystemUtils.halt(); + } + + long amountInMicroAlgo = 0L; + if (_nativevalue.getUnit() == Unit.microAlgo) amountInMicroAlgo = _nativevalue.getVal().longValue(); + if (_nativevalue.getUnit() == Unit.ALGO) amountInMicroAlgo = _nativevalue.getVal().longValue()*1000000L; + + boolean confirmedTransaction = false; + int txAttemptCount = 0; + int requestCount = 0; + + while (!confirmedTransaction && (txAttemptCount<5) && (requestCount<15)) { + requestCount++; + + try { + + // Make sure we dont resubmit tx if we get timeouts and txid confirmed + if (!tx_submitted) { + // Construct the transaction + String note = ""; + Response < TransactionParametersResponse > resp = _connector.getProvider_instance().TransactionParams().execute(); + if (!resp.isSuccessful()) { + throw new Exception(resp.message()); + } + TransactionParametersResponse params = resp.body(); + if (params == null) { + throw new Exception("Params retrieval error"); + } + JSONObject jsonObj = new JSONObject(params.toString()); + if (debug) System.out.println("Algorand suggested parameters: " + jsonObj.toString(2)); + Transaction txn = Transaction.PaymentTransactionBuilder() + .sender(_algoWallet.fetchAccount().getAddress().toString()) + .note(note.getBytes()) + .amount(amountInMicroAlgo) + .receiver(_target_address) + .suggestedParams(params) + .build(); + + // Sign the transaction + SignedTransaction signedTxn = _algoWallet.fetchAccount().signTransaction(txn); + if (debug) System.out.println("Signed transaction with txid: " + signedTxn.transactionID); + + // Submit the transaction to the network + byte[] encodedTxBytes = Encoder.encodeToMsgPack(signedTxn); + Response < PostTransactionsResponse > rawtxresponse = _connector.getProvider_instance().RawTransaction().rawtxn(encodedTxBytes).execute(); + if (!rawtxresponse.isSuccessful()) { + throw new Exception(rawtxresponse.message()); + } + txid = rawtxresponse.body().txId; + LOGGER.debug("Confirmed TX submit txid with " + txid); + tx_submitted = true; + } + + // Wait for transaction confirmation + PendingTransactionResponse pTrx = Utils.waitForConfirmation(_connector.getProvider_instance(), txid, 4); + if (debug) System.out.println("Transaction " + txid + " confirmed in round " + pTrx.confirmedRound); + hash = txid; + confirmedTransaction = true; + + // Read the transaction + if (debug) { + JSONObject jsonObj2 = new JSONObject(pTrx.toString()); + System.out.println("Transaction information (with notes): " + jsonObj2.toString(2)); + if (null != pTrx.txn.tx.note) System.out.println("Decoded note: " + new String(pTrx.txn.tx.note)); + System.out.println("Amount: " + new String(pTrx.txn.tx.amount.toString())); + System.out.println("Fee: " + new String(pTrx.txn.tx.fee.toString())); + } + } catch (Exception ex) { + // tx exceptions (readwrite) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, _haltOnUnconfirmedTX); + if (avmE.isNodeInteraction()) txAttemptCount++; + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + + return hash; + } + + public static AVMCreateAssetResult createARC69ASA(AVMBlockChainConnector _connector, AlgoLocalWallet _algoWallet, ARC69Asset _arc69params, String _metadatajson) { + return createARC69ASA(_connector, _algoWallet, _arc69params, _metadatajson, false); + } + + public static AVMCreateAssetResult createARC69ASA(AVMBlockChainConnector _connector, AlgoLocalWallet _algoWallet, ARC69Asset _arc69params, String _metadatajson, boolean _haltOnUnconfirmedTX) { + boolean debug = false; + + String txhash = null; + Long assetID = null; + boolean confirmedTransaction = false; + + int txAttemptCount = 0; + int requestCount = 0; + + while (!confirmedTransaction && (txAttemptCount<5) && (requestCount<15)) { + requestCount++; + + try { + + // Construct the transaction + Response < TransactionParametersResponse > resp = _connector.getProvider_instance().TransactionParams().execute(); + if (!resp.isSuccessful()) { + throw new Exception(resp.message()); + } + TransactionParametersResponse params = resp.body(); + if (params == null) { + throw new Exception("Params retrieval error"); + } + JSONObject jsonObj = new JSONObject(params.toString()); + if (debug) System.out.println("Algorand suggested parameters: " + jsonObj.toString(2)); + + Transaction txn = Transaction.AssetCreateTransactionBuilder() + .sender(_algoWallet.getAddress().toString()) + .assetTotal(_arc69params.getTotalNrUnits()) + .assetDecimals(_arc69params.getDecimals()) + .assetUnitName(_arc69params.getUnitName()) + .assetName(_arc69params.getAssetName()) + .url(_arc69params.getAssetURL()) + .noteUTF8(_metadatajson) + .manager(_arc69params.getManager()) + .reserve(_arc69params.getReserve()) + .freeze(_arc69params.getFreeze()) + .defaultFrozen(_arc69params.isDefaultFrozen()) + .clawback(_arc69params.getClawback()) + .suggestedParams(params) + .build(); + + // Sign the transaction + SignedTransaction signedTxn = _algoWallet.fetchAccount().signTransaction(txn); + if (debug) System.out.println("Signed transaction with txid: " + signedTxn.transactionID); + + // Submit the transaction to the network + byte[] encodedTxBytes = Encoder.encodeToMsgPack(signedTxn); + Response < PostTransactionsResponse > rawtxresponse = _connector.getProvider_instance().RawTransaction().rawtxn(encodedTxBytes).execute(); + if (!rawtxresponse.isSuccessful()) { + throw new Exception(rawtxresponse.message()); + } + String id = rawtxresponse.body().txId; + + // Wait for transaction confirmation + PendingTransactionResponse pTrx = Utils.waitForConfirmation(_connector.getProvider_instance(), id, 4); + if (debug) System.out.println("Transaction " + id + " confirmed in round " + pTrx.confirmedRound); + + txhash = id; + confirmedTransaction = true; + assetID = pTrx.assetIndex; + + // Read the transaction + if (debug) { + JSONObject jsonObj2 = new JSONObject(pTrx.toString()); + System.out.println("Transaction information (with notes): " + jsonObj2.toString(2)); + if (null != pTrx.txn.tx.note) System.out.println("Decoded note: " + new String(pTrx.txn.tx.note)); + System.out.println("Amount: " + new String(pTrx.txn.tx.amount.toString())); + System.out.println("Fee: " + new String(pTrx.txn.tx.fee.toString())); + } + } catch (Exception ex) { + // tx exceptions (readwrite) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, _haltOnUnconfirmedTX); + if (avmE.isNodeInteraction()) txAttemptCount++; + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + + return new AVMCreateAssetResult(txhash, assetID, confirmedTransaction); + } + + public static AVMCreateAssetResult createARC3ASA(AVMBlockChainConnector _connector, AlgoLocalWallet _algoWallet, ARC3Asset _arc3params) { + return createARC3ASA(_connector, _algoWallet, _arc3params, false); + } + + public static AVMCreateAssetResult createARC3ASA(AVMBlockChainConnector _connector, AlgoLocalWallet _algoWallet, ARC3Asset _arc3params, boolean _haltOnUnconfirmedTX) { + boolean debug = false; + + String txhash = null; + Long assetID = null; + boolean confirmedTransaction = false; + + int txAttemptCount = 0; + int requestCount = 0; + + while (!confirmedTransaction && (txAttemptCount<5) && (requestCount<15)) { + requestCount++; + + try { + + // Construct the transaction + Response < TransactionParametersResponse > resp = _connector.getProvider_instance().TransactionParams().execute(); + if (!resp.isSuccessful()) { + throw new Exception(resp.message()); + } + TransactionParametersResponse params = resp.body(); + if (params == null) { + throw new Exception("Params retrieval error"); + } + JSONObject jsonObj = new JSONObject(params.toString()); + if (debug) System.out.println("Algorand suggested parameters: " + jsonObj.toString(2)); + + Transaction txn = Transaction.AssetCreateTransactionBuilder() + .sender(_algoWallet.getAddress().toString()) + .assetTotal(_arc3params.getTotalNrUnits()) + .assetDecimals(_arc3params.getDecimals()) + .assetUnitName(_arc3params.getUnitName()) + .assetName(_arc3params.getAssetName()) + .url(_arc3params.getAssetURL()) + .metadataHash(_arc3params.getAssetMetadataHash()) + .manager(_arc3params.getManager()) + .reserve(_arc3params.getReserve()) + .freeze(_arc3params.getFreeze()) + .defaultFrozen(_arc3params.isDefaultFrozen()) + .clawback(_arc3params.getClawback()) + .suggestedParams(params) + .build(); + + // Sign the transaction + SignedTransaction signedTxn = _algoWallet.fetchAccount().signTransaction(txn); + if (debug) System.out.println("Signed transaction with txid: " + signedTxn.transactionID); + + // Submit the transaction to the network + byte[] encodedTxBytes = Encoder.encodeToMsgPack(signedTxn); + Response < PostTransactionsResponse > rawtxresponse = _connector.getProvider_instance().RawTransaction().rawtxn(encodedTxBytes).execute(); + if (!rawtxresponse.isSuccessful()) { + throw new Exception(rawtxresponse.message()); + } + String id = rawtxresponse.body().txId; + + // Wait for transaction confirmation + PendingTransactionResponse pTrx = Utils.waitForConfirmation(_connector.getProvider_instance(), id, 4); + if (debug) System.out.println("Transaction " + id + " confirmed in round " + pTrx.confirmedRound); + + txhash = id; + confirmedTransaction = true; + assetID = pTrx.assetIndex; + + // Read the transaction + if (debug) { + JSONObject jsonObj2 = new JSONObject(pTrx.toString()); + System.out.println("Transaction information (with notes): " + jsonObj2.toString(2)); + if (null != pTrx.txn.tx.note) System.out.println("Decoded note: " + new String(pTrx.txn.tx.note)); + System.out.println("Amount: " + new String(pTrx.txn.tx.amount.toString())); + System.out.println("Fee: " + new String(pTrx.txn.tx.fee.toString())); + } + } catch (Exception ex) { + // tx exceptions (readwrite) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, _haltOnUnconfirmedTX); + if (avmE.isNodeInteraction()) txAttemptCount++; + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + + return new AVMCreateAssetResult(txhash, assetID, confirmedTransaction); + } + + public static String reconfigureARC69ASAWithNote(AVMBlockChainConnector _connector, AlgoLocalWallet _algoWallet, Long assetID, AVMASAMutables _mutables, boolean _haltOnUnconfirmedTX, String _note) { + boolean debug = false; + + String txhash = null; + boolean confirmedTransaction = false; + int txAttemptCount = 0; + int requestCount = 0; + + while (!confirmedTransaction && (txAttemptCount<5) && (requestCount<15)) { + requestCount++; + + try { + + // Construct the transaction + Response < TransactionParametersResponse > resp = _connector.getProvider_instance().TransactionParams().execute(); + if (!resp.isSuccessful()) { + throw new Exception(resp.message()); + } + TransactionParametersResponse params = resp.body(); + if (params == null) { + throw new Exception("Params retrieval error"); + } + JSONObject jsonObj = new JSONObject(params.toString()); + if (debug) System.out.println("Algorand suggested parameters: " + jsonObj.toString(2)); + + Transaction txn = Transaction.AssetConfigureTransactionBuilder() + .strictEmptyAddressChecking(false) + .assetIndex(assetID) + .noteUTF8(_note) + .sender(_algoWallet.getAddress().toString()) + .manager(_mutables.getManager()) + .reserve(_mutables.getReserve()) + .freeze(_mutables.getFreeze()) + .clawback(_mutables.getClawback()) + .suggestedParams(params) + .build(); + + // Sign the transaction + SignedTransaction signedTxn = _algoWallet.fetchAccount().signTransaction(txn); + if (debug) System.out.println("Signed transaction with txid: " + signedTxn.transactionID); + + // Submit the transaction to the network + byte[] encodedTxBytes = Encoder.encodeToMsgPack(signedTxn); + Response < PostTransactionsResponse > rawtxresponse = _connector.getProvider_instance().RawTransaction().rawtxn(encodedTxBytes).execute(); + if (!rawtxresponse.isSuccessful()) { + throw new Exception(rawtxresponse.message()); + } + String id = rawtxresponse.body().txId; + + // Wait for transaction confirmation + PendingTransactionResponse pTrx = Utils.waitForConfirmation(_connector.getProvider_instance(), id, 4); + if (debug) System.out.println("Transaction " + id + " confirmed in round " + pTrx.confirmedRound); + txhash = id; + confirmedTransaction = true; + + // Read the transaction + if (debug) { + JSONObject jsonObj2 = new JSONObject(pTrx.toString()); + System.out.println("Transaction information (with notes): " + jsonObj2.toString(2)); + if (null != pTrx.txn.tx.note) System.out.println("Decoded note: " + new String(pTrx.txn.tx.note)); + System.out.println("Amount: " + new String(pTrx.txn.tx.amount.toString())); + System.out.println("Fee: " + new String(pTrx.txn.tx.fee.toString())); + } + } catch (Exception ex) { + // tx exceptions (readwrite) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, _haltOnUnconfirmedTX); + if (avmE.isNodeInteraction()) txAttemptCount++; + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + + return txhash; + } + + public static String reconfigureARCASA(AVMBlockChainConnector _connector, AlgoLocalWallet _algoWallet, Long assetID, AVMASAMutables _mutables, boolean _haltOnUnconfirmedTX) { + boolean debug = false; + + String txhash = null; + boolean confirmedTransaction = false; + int txAttemptCount = 0; + int requestCount = 0; + + while (!confirmedTransaction && (txAttemptCount<5) && (requestCount<15)) { + requestCount++; + + try { + + // Construct the transaction + Response < TransactionParametersResponse > resp = _connector.getProvider_instance().TransactionParams().execute(); + if (!resp.isSuccessful()) { + throw new Exception(resp.message()); + } + TransactionParametersResponse params = resp.body(); + if (params == null) { + throw new Exception("Params retrieval error"); + } + JSONObject jsonObj = new JSONObject(params.toString()); + if (debug) System.out.println("Algorand suggested parameters: " + jsonObj.toString(2)); + + Transaction txn = Transaction.AssetConfigureTransactionBuilder() + .strictEmptyAddressChecking(false) + .assetIndex(assetID) + .sender(_algoWallet.getAddress().toString()) + .manager(_mutables.getManager()) + .reserve(_mutables.getReserve()) + .freeze(_mutables.getFreeze()) + .clawback(_mutables.getClawback()) + .suggestedParams(params) + .build(); + + // Sign the transaction + SignedTransaction signedTxn = _algoWallet.fetchAccount().signTransaction(txn); + if (debug) System.out.println("Signed transaction with txid: " + signedTxn.transactionID); + + // Submit the transaction to the network + byte[] encodedTxBytes = Encoder.encodeToMsgPack(signedTxn); + Response < PostTransactionsResponse > rawtxresponse = _connector.getProvider_instance().RawTransaction().rawtxn(encodedTxBytes).execute(); + if (!rawtxresponse.isSuccessful()) { + throw new Exception(rawtxresponse.message()); + } + String id = rawtxresponse.body().txId; + + // Wait for transaction confirmation + PendingTransactionResponse pTrx = Utils.waitForConfirmation(_connector.getProvider_instance(), id, 4); + if (debug) System.out.println("Transaction " + id + " confirmed in round " + pTrx.confirmedRound); + txhash = id; + confirmedTransaction = true; + + // Read the transaction + if (debug) { + JSONObject jsonObj2 = new JSONObject(pTrx.toString()); + System.out.println("Transaction information (with notes): " + jsonObj2.toString(2)); + if (null != pTrx.txn.tx.note) System.out.println("Decoded note: " + new String(pTrx.txn.tx.note)); + System.out.println("Amount: " + new String(pTrx.txn.tx.amount.toString())); + System.out.println("Fee: " + new String(pTrx.txn.tx.fee.toString())); + } + } catch (Exception ex) { + // tx exceptions (readwrite) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, _haltOnUnconfirmedTX); + if (avmE.isNodeInteraction()) txAttemptCount++; + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + + return txhash; + } + + public static boolean makeASAImmutable(AVMBlockChainConnector _connector, AlgoLocalWallet _algoWallet, Long _assetID, boolean _haltOnUnconfirmedTX) { + boolean confirmed_step1 = clearallASAddressesExceptManager(_connector, _algoWallet, _assetID, _haltOnUnconfirmedTX); + boolean confirmed_step2 = clearallASAddressesExceptReserve(_connector, _algoWallet, _assetID, _haltOnUnconfirmedTX); + return (confirmed_step1 && confirmed_step2); + } + + public static boolean makeASAImmutableLeavingReserve(AVMBlockChainConnector _connector, AlgoLocalWallet _algoWallet, Long _assetID, boolean _haltOnUnconfirmedTX, Address _reserve) { + boolean confirmed_step1 = clearallASAddressesExceptManagerAndReserve(_connector, _algoWallet, _assetID, _haltOnUnconfirmedTX, _reserve); + boolean confirmed_step2 = clearallASAddressesExceptReserve(_connector, _algoWallet, _assetID, _haltOnUnconfirmedTX); + return (confirmed_step1 && confirmed_step2); + } + + public static boolean clearallASAddressesExceptReserve(AVMBlockChainConnector _connector, AlgoLocalWallet _algoWallet, Long _assetID, boolean _haltOnUnconfirmedTX) { + boolean debug = false; + + String txhash = null; + boolean confirmedTransaction = false; + int txAttemptCount = 0; + int requestCount = 0; + + while (!confirmedTransaction && (txAttemptCount<5) && (requestCount<15)) { + requestCount++; + + try { + + // Construct the transaction + Response < TransactionParametersResponse > resp = _connector.getProvider_instance().TransactionParams().execute(); + if (!resp.isSuccessful()) { + throw new Exception(resp.message()); + } + TransactionParametersResponse params = resp.body(); + if (params == null) { + throw new Exception("Params retrieval error"); + } + JSONObject jsonObj = new JSONObject(params.toString()); + if (debug) System.out.println("Algorand suggested parameters: " + jsonObj.toString(2)); + + Transaction txn = Transaction.AssetConfigureTransactionBuilder() + .strictEmptyAddressChecking(false) + .assetIndex(_assetID) + .sender(_algoWallet.getAddress().toString()) + .reserve(new Address(_algoWallet.getAddress().toString())) + .suggestedParams(params) + .build(); + + // Sign the transaction + SignedTransaction signedTxn = _algoWallet.fetchAccount().signTransaction(txn); + if (debug) System.out.println("Signed transaction with txid: " + signedTxn.transactionID); + + // Submit the transaction to the network + byte[] encodedTxBytes = Encoder.encodeToMsgPack(signedTxn); + Response < PostTransactionsResponse > rawtxresponse = _connector.getProvider_instance().RawTransaction().rawtxn(encodedTxBytes).execute(); + if (!rawtxresponse.isSuccessful()) { + throw new Exception(rawtxresponse.message()); + } + String id = rawtxresponse.body().txId; + + // Wait for transaction confirmation + PendingTransactionResponse pTrx = Utils.waitForConfirmation(_connector.getProvider_instance(), id, 4); + txhash = id; + if (debug) System.out.println("Transaction " + txhash + " confirmed in round " + pTrx.confirmedRound); + confirmedTransaction = true; + + // Read the transaction + if (debug) { + JSONObject jsonObj2 = new JSONObject(pTrx.toString()); + System.out.println("Transaction information (with notes): " + jsonObj2.toString(2)); + if (null != pTrx.txn.tx.note) System.out.println("Decoded note: " + new String(pTrx.txn.tx.note)); + System.out.println("Amount: " + new String(pTrx.txn.tx.amount.toString())); + System.out.println("Fee: " + new String(pTrx.txn.tx.fee.toString())); + } + } catch (Exception ex) { + // tx exceptions (readwrite) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, _haltOnUnconfirmedTX); + if (avmE.isNodeInteraction()) txAttemptCount++; + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + + return confirmedTransaction; + } + + public static Boolean setLocalAVMNetworkSettings() { + boolean success = false; + + return success; + } + + + public static Boolean clearallASAddressesExceptManager(AVMBlockChainConnector _connector, AlgoLocalWallet _algoWallet, Long _assetID, boolean _haltOnUnconfirmedTX) { + boolean debug = false; + + String txhash = null; + boolean confirmedTransaction = false; + int txAttemptCount = 0; + int requestCount = 0; + + while (!confirmedTransaction && (txAttemptCount<5) && (requestCount<15)) { + requestCount++; + + try { + + // Construct the transaction + Response < TransactionParametersResponse > resp = _connector.getProvider_instance().TransactionParams().execute(); + if (!resp.isSuccessful()) { + throw new Exception(resp.message()); + } + TransactionParametersResponse params = resp.body(); + if (params == null) { + throw new Exception("Params retrieval error"); + } + JSONObject jsonObj = new JSONObject(params.toString()); + if (debug) System.out.println("Algorand suggested parameters: " + jsonObj.toString(2)); + + Transaction txn = Transaction.AssetConfigureTransactionBuilder() + .strictEmptyAddressChecking(false) + .assetIndex(_assetID) + .sender(_algoWallet.getAddress().toString()) + .manager(new Address(_algoWallet.getAddress().toString())) + .suggestedParams(params) + .build(); + + // Sign the transaction + SignedTransaction signedTxn = _algoWallet.fetchAccount().signTransaction(txn); + if (debug) System.out.println("Signed transaction with txid: " + signedTxn.transactionID); + + // Submit the transaction to the network + byte[] encodedTxBytes = Encoder.encodeToMsgPack(signedTxn); + Response < PostTransactionsResponse > rawtxresponse = _connector.getProvider_instance().RawTransaction().rawtxn(encodedTxBytes).execute(); + if (!rawtxresponse.isSuccessful()) { + throw new Exception(rawtxresponse.message()); + } + String id = rawtxresponse.body().txId; + + // Wait for transaction confirmation + PendingTransactionResponse pTrx = Utils.waitForConfirmation(_connector.getProvider_instance(), id, 4); + txhash = id; + if (debug) System.out.println("Transaction " + txhash + " confirmed in round " + pTrx.confirmedRound); + confirmedTransaction = true; + + // Read the transaction + if (debug) { + JSONObject jsonObj2 = new JSONObject(pTrx.toString()); + System.out.println("Transaction information (with notes): " + jsonObj2.toString(2)); + if (null != pTrx.txn.tx.note) System.out.println("Decoded note: " + new String(pTrx.txn.tx.note)); + System.out.println("Amount: " + new String(pTrx.txn.tx.amount.toString())); + System.out.println("Fee: " + new String(pTrx.txn.tx.fee.toString())); + } + } catch (Exception ex) { + // tx exceptions (readwrite) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, _haltOnUnconfirmedTX); + if (avmE.isNodeInteraction()) txAttemptCount++; + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + + return confirmedTransaction; + } + + + public static Boolean clearallASAddressesExceptManagerAndReserve(AVMBlockChainConnector _connector, AlgoLocalWallet _algoWallet, Long _assetID, boolean _haltOnUnconfirmedTX, Address _reserve) { + boolean debug = false; + + String txhash = null; + boolean confirmedTransaction = false; + int txAttemptCount = 0; + int requestCount = 0; + + while (!confirmedTransaction && (txAttemptCount<5) && (requestCount<15)) { + requestCount++; + + try { + + // Construct the transaction + Response < TransactionParametersResponse > resp = _connector.getProvider_instance().TransactionParams().execute(); + if (!resp.isSuccessful()) { + throw new Exception(resp.message()); + } + TransactionParametersResponse params = resp.body(); + if (params == null) { + throw new Exception("Params retrieval error"); + } + JSONObject jsonObj = new JSONObject(params.toString()); + if (debug) System.out.println("Algorand suggested parameters: " + jsonObj.toString(2)); + + Transaction txn = Transaction.AssetConfigureTransactionBuilder() + .strictEmptyAddressChecking(false) + .assetIndex(_assetID) + .sender(_algoWallet.getAddress().toString()) + .manager(new Address(_algoWallet.getAddress().toString())) + .reserve(_reserve) + .suggestedParams(params) + .build(); + + // Sign the transaction + SignedTransaction signedTxn = _algoWallet.fetchAccount().signTransaction(txn); + if (debug) System.out.println("Signed transaction with txid: " + signedTxn.transactionID); + + // Submit the transaction to the network + byte[] encodedTxBytes = Encoder.encodeToMsgPack(signedTxn); + Response < PostTransactionsResponse > rawtxresponse = _connector.getProvider_instance().RawTransaction().rawtxn(encodedTxBytes).execute(); + if (!rawtxresponse.isSuccessful()) { + throw new Exception(rawtxresponse.message()); + } + String id = rawtxresponse.body().txId; + + // Wait for transaction confirmation + PendingTransactionResponse pTrx = Utils.waitForConfirmation(_connector.getProvider_instance(), id, 4); + txhash = id; + if (debug) System.out.println("Transaction " + txhash + " confirmed in round " + pTrx.confirmedRound); + confirmedTransaction = true; + + // Read the transaction + if (debug) { + JSONObject jsonObj2 = new JSONObject(pTrx.toString()); + System.out.println("Transaction information (with notes): " + jsonObj2.toString(2)); + if (null != pTrx.txn.tx.note) System.out.println("Decoded note: " + new String(pTrx.txn.tx.note)); + System.out.println("Amount: " + new String(pTrx.txn.tx.amount.toString())); + System.out.println("Fee: " + new String(pTrx.txn.tx.fee.toString())); + } + } catch (Exception ex) { + // tx exceptions (readwrite) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, _haltOnUnconfirmedTX); + if (avmE.isNodeInteraction()) txAttemptCount++; + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + + return confirmedTransaction; + } + + + public static String destroyASA(AVMBlockChainConnector _connector, AlgoLocalWallet _algoWallet, Long assetID, boolean _haltOnUnconfirmedTX) { + boolean debug = false; + + String txhash = null; + boolean confirmedTransaction = false; + int txAttemptCount = 0; + int requestCount = 0; + + while (!confirmedTransaction && (txAttemptCount<5) && (requestCount<15)) { + requestCount++; + + try { + + // Construct the transaction + Response < TransactionParametersResponse > resp = _connector.getProvider_instance().TransactionParams().execute(); + if (!resp.isSuccessful()) { + throw new Exception(resp.message()); + } + TransactionParametersResponse params = resp.body(); + if (params == null) { + throw new Exception("Params retrieval error"); + } + JSONObject jsonObj = new JSONObject(params.toString()); + if (debug) System.out.println("Algorand suggested parameters: " + jsonObj.toString(2)); + + Transaction txn = Transaction.AssetConfigureTransactionBuilder() + .strictEmptyAddressChecking(false) + .assetIndex(assetID) + .sender(_algoWallet.getAddress().toString()) + // no manager/reserve/freeze/clawback = destroy + .suggestedParams(params) + .build(); + + // Sign the transaction + SignedTransaction signedTxn = _algoWallet.fetchAccount().signTransaction(txn); + if (debug) System.out.println("Signed transaction with txid: " + signedTxn.transactionID); + + // Submit the transaction to the network + byte[] encodedTxBytes = Encoder.encodeToMsgPack(signedTxn); + Response < PostTransactionsResponse > rawtxresponse = _connector.getProvider_instance().RawTransaction().rawtxn(encodedTxBytes).execute(); + if (!rawtxresponse.isSuccessful()) { + throw new Exception(rawtxresponse.message()); + } + String id = rawtxresponse.body().txId; + + // Wait for transaction confirmation + PendingTransactionResponse pTrx = Utils.waitForConfirmation(_connector.getProvider_instance(), id, 4); + if (debug) System.out.println("Transaction " + id + " confirmed in round " + pTrx.confirmedRound); + txhash = id; + confirmedTransaction = true; + + // Read the transaction + if (debug) { + JSONObject jsonObj2 = new JSONObject(pTrx.toString()); + System.out.println("Transaction information (with notes): " + jsonObj2.toString(2)); + if (null != pTrx.txn.tx.note) System.out.println("Decoded note: " + new String(pTrx.txn.tx.note)); + System.out.println("Amount: " + new String(pTrx.txn.tx.amount.toString())); + System.out.println("Fee: " + new String(pTrx.txn.tx.fee.toString())); + } + } catch (Exception ex) { + // tx exceptions (readwrite) + AVMProviderException avmE = analyzeProviderException(_connector.getChain(), _connector.getRelayNode(), ex); + AVMProviderExceptionActionState avmEAS = actAndGetStateAVMProviderException(avmE, _connector, _haltOnUnconfirmedTX); + if (avmE.isNodeInteraction()) txAttemptCount++; + if (avmEAS.isNewAVMBlockChainConnector()) _connector = avmEAS.getConnector(); + } + } + + return txhash; + } + + public static void avmpingpong(AVMChain _chain, AlgoLocalWallet _algoWallet1, AlgoLocalWallet _algoWallet2, AVMNativeValue _avmNativeValue, int _nrIterations) { + LOGGER.info("evmpingpong init()"); + LOGGER.info(" - chain: " + _chain.toString()); + + boolean haltOnUnconfirmedTX = true; + AVMBlockChainConnector connector = new AVMBlockChainConnector(_chain, false); + + AVMChainInfo chainInfo = AVMUtils.getAVMChainInfo(_chain); + LOGGER.info("- genesis_id: " + chainInfo.getGenesisID()); + + AVMAccountBalance algoWalletBalance1PRE = AVMUtils.getAccountNativeBalance(connector, _algoWallet1.fetchAccount().getAddress()); + System.out.println(String.format("PRE %s balance: %f ALGO", _algoWallet1.fetchAccount().getAddress().toString(), algoWalletBalance1PRE.getBalanceInALGO())); + AVMAccountBalance algoWalletBalance2PRE = AVMUtils.getAccountNativeBalance(connector, _algoWallet2.fetchAccount().getAddress()); + System.out.println(String.format("PRE %s balance: %f ALGO", _algoWallet2.fetchAccount().getAddress().toString(), algoWalletBalance2PRE.getBalanceInALGO())); + + /** + * Sanity checks + */ + if (_avmNativeValue.getUnit() != Unit.ALGO) { + LOGGER.error("Please use ALGO as native currency"); + SystemUtils.halt(); + } + if (true && + (algoWalletBalance1PRE.getBalanceInALGO()>(_avmNativeValue.getVal().doubleValue()*2.0d)) && + (algoWalletBalance2PRE.getBalanceInALGO()>(_avmNativeValue.getVal().doubleValue()*2.0d)) && + true) { + // all good + } else { + LOGGER.error("Both accounts playing pingpong needs to have a balance above " + _avmNativeValue.getVal().doubleValue()*2.0d + " ALGO"); + SystemUtils.halt(); + } + + for (int i=1; i<=_nrIterations; i++) { + + /** + * ping() + * - Send funds from wallet001 --> wallet002 + */ + String txhash1 = sendTXWithNativeCurrency(connector, _algoWallet1, _algoWallet2.fetchAccount().getAddress(), _avmNativeValue, haltOnUnconfirmedTX); + LOGGER.info("PING TX completed with tx hash: " + txhash1); + + /** + * pong() + * - Send funds from wallet002 --> wallet001 + */ + String txhash2 = sendTXWithNativeCurrency(connector, _algoWallet2, _algoWallet1.fetchAccount().getAddress(), _avmNativeValue, haltOnUnconfirmedTX); + LOGGER.info("PONG TX completed with tx hash: " + txhash2); + + } + + AVMAccountBalance algoWalletBalance1POST = AVMUtils.getAccountNativeBalance(connector, _algoWallet1.fetchAccount().getAddress()); + System.out.println(String.format("POST %s balance: %f ALGO", _algoWallet1.fetchAccount().getAddress().toString(), algoWalletBalance1POST.getBalanceInALGO())); + AVMAccountBalance algoWalletBalance2POST = AVMUtils.getAccountNativeBalance(connector, _algoWallet2.fetchAccount().getAddress()); + System.out.println(String.format("POST %s balance: %f ALGO", _algoWallet2.fetchAccount().getAddress().toString(), algoWalletBalance2POST.getBalanceInALGO())); + + } + + + public static AVMProviderException analyzeProviderException(AVMChain _chain, AlgoRelayNode _relayNode, Exception _ex) { + boolean nodeInteraction = false; + boolean sleepBeforeRetry = false; + int sleepTimeInSecondsRecommended = 5; + ExceptionType exceptionType = ExceptionType.UNKNOWN; + boolean switchNode = false; + boolean timeout = false; + + if (false || + _ex.getMessage().contains("timeout") || + _ex.getMessage().contains("timed out") || + false) { + // java.net.SocketTimeoutException: connect timed out + // java.net.SocketTimeoutException: Read timed out + LOGGER.info("Got a timeout .. will retry .. ex: " + _ex.getMessage()); + nodeInteraction = false; + sleepBeforeRetry = true; + sleepTimeInSecondsRecommended = 5; + exceptionType = ExceptionType.RECOVERABLE; + timeout = true; + } else if (false || + _ex.getMessage().contains(URLUtils.extractURLHostnameFromURL(_relayNode.getUrl())) || + false) { + // hostname echoed back + // mainnet-algorand.api.purestake.io + LOGGER.info("Got hostname echoed back .. will retry .. ex: " + _ex.getMessage()); + nodeInteraction = false; + sleepBeforeRetry = true; + sleepTimeInSecondsRecommended = 5; + exceptionType = ExceptionType.RECOVERABLE; + timeout = true; + } else if (false || + (_ex.getMessage().contains("Failed to connect")) || + (_ex.getMessage().contains("Connection reset")) || + (_ex.getMessage().contains("closed")) || + (_ex.getMessage().contains("Remote host terminated the handshake")) || + false) { + // java.net.ConnectException: Failed to connect to + // java.net.SocketException: Connection reset + // javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake + LOGGER.warn("Got a connection reset from nodeURL " + _relayNode.getUrl() + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (false || + _ex.getMessage().contains("UnknownHostException") || + _ex.getMessage().contains("No such host is known") || + false) { + LOGGER.info("Unable to resolve host using nodeURL " + _relayNode.getUrl() + ".. will not retry and switch provider, move on to next node"); + exceptionType = ExceptionType.IGNORE; + sleepBeforeRetry = true; + sleepTimeInSecondsRecommended = 1; + switchNode = true; + } else if (_ex.getMessage().contains(" overspend ")) { + LOGGER.warn("Got an overspend warning from nodeURL " + _relayNode.getUrl() + ".. did you account for the Account Minimum Balance?"); + exceptionType = ExceptionType.FATAL; + } else if (_ex.getMessage().contains("404;")) { + LOGGER.warn("Got a 404 non JSON response from nodeURL " + _relayNode.getUrl() + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("Invalid API Token")) { + LOGGER.warn("Got an invalid API key error from relay node " + _relayNode.getUrl() + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("Invalid response received: 429")) { + if (false || + _ex.getMessage().contains("daily request count exceeded") || + _ex.getMessage().contains("You have sent too many requests in a given amount of time") || + false) { + LOGGER.info("Node limit reached for nodeURL " + _relayNode.getUrl() + ", we should probably cool down: " + _ex.getMessage()); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else { + LOGGER.error("Generic 429 error from nodeURL " + _relayNode.getUrl() + ": " + _ex.getMessage() + ", update analyzeProviderException() .. "); + LOGGER.info("429 error noted for nodeURL " + _relayNode.getUrl() + ": " + _ex.getMessage() + ", lets try again"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } + } else { + exceptionType = ExceptionType.UNKNOWN; + LOGGER.error("Unknown error from relay node " + _relayNode.getUrl() + ": " + _ex.getMessage() + ", update analyzeProviderException()"); + LOGGER.error("Unknown response noted while communicating with relay node " + _relayNode.getUrl()); + SystemUtils.halt(); + } + + return new AVMProviderException(exceptionType, nodeInteraction, sleepBeforeRetry, sleepTimeInSecondsRecommended, switchNode, timeout); + } + + + public static AVMIndexerException analyzeIndexerException(AVMChain _chain, AlgoIndexerNode _indexerNode, Exception _ex) { + boolean nodeInteraction = false; + boolean sleepBeforeRetry = false; + int sleepTimeInSecondsRecommended = 5; + ExceptionType exceptionType = ExceptionType.UNKNOWN; + boolean switchNode = false; + boolean timeout = false; + + if (false || + _ex.getMessage().contains("timeout") || + _ex.getMessage().contains("timed out") || + false) { + // java.net.SocketTimeoutException: connect timed out + // java.net.SocketTimeoutException: Read timed out + LOGGER.info("Got a timeout .. will retry .. ex: " + _ex.getMessage()); + nodeInteraction = false; + sleepBeforeRetry = true; + sleepTimeInSecondsRecommended = 5; + exceptionType = ExceptionType.RECOVERABLE; + timeout = true; + } else if (false || + _ex.getMessage().contains(URLUtils.extractURLHostnameFromURL(_indexerNode.getUrl())) || + false) { + // hostname echoed back + // mainnet-algorand.api.purestake.io + LOGGER.info("Got hostname echoed back .. will retry .. ex: " + _ex.getMessage()); + nodeInteraction = false; + sleepBeforeRetry = true; + sleepTimeInSecondsRecommended = 5; + exceptionType = ExceptionType.RECOVERABLE; + timeout = true; + } else if (false || + (_ex.getMessage().contains("Failed to connect")) || + (_ex.getMessage().contains("Connection reset")) || + (_ex.getMessage().contains("closed")) || + (_ex.getMessage().contains("Remote host terminated the handshake")) || + false) { + // java.net.ConnectException: Failed to connect to + // java.net.SocketException: Connection reset + // javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake + LOGGER.warn("Got a connection reset from nodeURL " + _indexerNode.getUrl() + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (false || + _ex.getMessage().contains("UnknownHostException") || + _ex.getMessage().contains("No such host is known") || + false) { + LOGGER.info("Unable to resolve host using nodeURL " + _indexerNode.getUrl() + ".. will not retry and switch provider, move on to next node"); + exceptionType = ExceptionType.IGNORE; + sleepBeforeRetry = true; + sleepTimeInSecondsRecommended = 1; + switchNode = true; + } else if (_ex.getMessage().contains(" overspend ")) { + LOGGER.warn("Got an overspend warning from nodeURL " + _indexerNode.getUrl() + ".. did you account for the Account Minimum Balance?"); + exceptionType = ExceptionType.FATAL; + } else if (_ex.getMessage().contains("404;")) { + LOGGER.warn("Got a 404 non JSON response from nodeURL " + _indexerNode.getUrl() + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("invalid value on parameter")) { + // https://node.testnet.algoexplorerapi.io: {"message":"invalid value on parameter 'limit'"} + LOGGER.warn("Got an invalid value on parameter response from indexer node " + _indexerNode.getUrl() + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("Invalid response received: 429")) { + if (false || + _ex.getMessage().contains("daily request count exceeded") || + _ex.getMessage().contains("You have sent too many requests in a given amount of time") || + false) { + LOGGER.info("Node limit reached for nodeURL " + _indexerNode.getUrl() + ", we should probably cool down: " + _ex.getMessage()); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else { + LOGGER.error("Generic 429 error from nodeURL " + _indexerNode.getUrl() + ": " + _ex.getMessage() + ", update analyzeIndexerException() .. "); + LOGGER.info("429 error noted for nodeURL " + _indexerNode.getUrl() + ": " + _ex.getMessage() + ", lets try again"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } + } else { + exceptionType = ExceptionType.UNKNOWN; + LOGGER.error("Unknown error from indexer node " + _indexerNode.getUrl() + ": " + _ex.getMessage() + ", update analyzeIndexerException()"); + LOGGER.error("Unknown response noted while communicating with indexer node " + _indexerNode.getUrl()); + SystemUtils.halt(); + } + + return new AVMIndexerException(exceptionType, nodeInteraction, sleepBeforeRetry, sleepTimeInSecondsRecommended, switchNode, timeout); + } + + + public static AVMProviderExceptionActionState actAndGetStateAVMProviderException(AVMProviderException _avmE, AVMBlockChainConnector _connector, boolean _haltOnUnconfirmedTX) { + + boolean newEVMBlockChainConnector = false; + AVMBlockChainConnector connector = _connector; + + if (_avmE.isSleepBeforeRetry()) { + SystemUtils.sleepInSeconds(_avmE.getSleepTimeInSecondsRecommended()); + } else { + SystemUtils.sleepInSeconds(1); // Always sleep for 1 sec + } + if (_avmE.getExceptionType() == ExceptionType.FATAL) { + LOGGER.info("ExceptionType is FATAL, exiting .."); + SystemUtils.halt(); + } + if (_avmE.isSwitchNode()) { + newEVMBlockChainConnector = true; + //connector.selectRandomNodeURL(_connector.getNode_url()); + } + if ( true && + (_avmE.getExceptionType() != ExceptionType.RECOVERABLE) && + _haltOnUnconfirmedTX && + true) { + LOGGER.info("haltOnUnconfirmedTX is set to true, and we have an unrecoverable exception"); + SystemUtils.halt(); + } + + return new AVMProviderExceptionActionState(newEVMBlockChainConnector, connector); + } + + + public static AVMIndexerExceptionActionState actAndGetStateAVMIndexerException(AVMIndexerException _avmE, AVMBlockChainConnector _connector, boolean _haltOnUnconfirmedTX) { + + boolean newAVMIndexerConnector = false; + AVMBlockChainConnector connector = _connector; + + if (_avmE.isSleepBeforeRetry()) { + SystemUtils.sleepInSeconds(_avmE.getSleepTimeInSecondsRecommended()); + } else { + SystemUtils.sleepInSeconds(1); // Always sleep for 1 sec + } + if (_avmE.getExceptionType() == ExceptionType.FATAL) { + LOGGER.info("ExceptionType is FATAL, exiting .."); + SystemUtils.halt(); + } + if (_avmE.isSwitchNode()) { + newAVMIndexerConnector = true; + AlgoIndexerNode new_indexernode = connector.selectRandomIndexerNode(_connector.getIndexerNode().getUrl()); + connector.setIndexerNode(new_indexernode); + connector.reinitializeConnector(); + } + if ( true && + (_avmE.getExceptionType() != ExceptionType.RECOVERABLE) && + _haltOnUnconfirmedTX && + true) { + LOGGER.info("haltOnUnconfirmedTX is set to true, and we have an unrecoverable exception"); + SystemUtils.halt(); + } + + return new AVMIndexerExceptionActionState(newAVMIndexerConnector, connector); + } + + public static String extractCIDFromARC19URLAndReserveAddress(String assetURL, String reserve_address) { + + String derived_cid = ""; + + if (assetURL.startsWith("template-ipfs://{") && assetURL.contains("}")) { + + assetURL = assetURL.replace("template-ipfs://{",""); + assetURL = assetURL.replace("}",""); + + String[] parts = assetURL.split(":"); + if (parts.length == 5) { + + String template = parts[0]; + String version = parts[1]; + String multicodec = parts[2]; + String fieldname = parts[3]; + String hashtype = parts[4]; + + if (template.equals("ipfscid")) { + if (false || + "0".equals(version) || + "1".equals(version) || + false) { + if (false || + "raw".equals(multicodec) || + "dag-pb".equals(multicodec) || + false) { + if ("reserve".equals(fieldname)) { + if ("sha2-256".equals(hashtype)) { + // weeeee nesting is fun! + if ("raw".equals(multicodec) && "1".equals(version)) { + derived_cid = AVMUtils.arc19DecodeAlgorandAddressToCIDv1(reserve_address); + return derived_cid; + } else if ("dag-pb".equals(multicodec) && "0".equals(version)) { + derived_cid = AVMUtils.arc19DecodeAlgorandAddressToCIDv0(reserve_address); + return derived_cid; + } else { + LOGGER.error("Currently unsupported ARC19 version/multicode combo. version=" + version + " multicodec=" + multicodec); + SystemUtils.halt(); + } + } else { + LOGGER.warn("Invalid ARC19 (unsupported fieldname) assetURL: " + assetURL); + } + } else { + LOGGER.warn("Invalid ARC19 (unsupported fieldname) assetURL: " + assetURL); + } + } else { + LOGGER.warn("Invalid ARC19 (unsupported multicode) assetURL: " + assetURL); + } + } else { + LOGGER.warn("Invalid ARC19 (unsupported version) assetURL: " + assetURL); + } + } else { + LOGGER.warn("Invalid ARC19 (content must start with ipfscid) assetURL: " + assetURL); + } + } else { + LOGGER.warn("Invalid ARC19 (invalid content) assetURL: " + assetURL); + } + } else { + LOGGER.warn("Invalid ARC19 (invalid prefix) assetURL: " + assetURL); + } + + return derived_cid; + } + + public static String arc19EncodeCIDv0ToAlgorandAddress(String cid_str) { + System.out.println("CID: " + cid_str); + + String derived_reserve_addr = ""; + + // Parse the CID + Cid cid_version0 = Cid.decode(cid_str); + LOGGER.info("codec : " + cid_version0.codec); + LOGGER.info("version : " + cid_version0.version); + LOGGER.info("hashCode : " + cid_version0.hashCode()); + LOGGER.info("hashlen : " + cid_version0.getHash().length); + LOGGER.info(""); + + LOGGER.info("base58 : " + cid_version0.toBase58()); + LOGGER.info("hex : " + cid_version0.toHex()); + LOGGER.info("string : " + cid_version0.toString()); + LOGGER.info(""); + + try { + // parse the multihash, https://multiformats.io/multihash/ + Multihash mh_version0 = Multihash.decode(cid_version0.toString()); + LOGGER.debug("mh hex : " + mh_version0.toHex()); + + // Early exit + if (mh_version0.toHex().length() != 68) return ""; + + String hash_func_type = mh_version0.toHex().substring(0, 2); + LOGGER.info("mh hash_func_type : " + hash_func_type); // 0x12 = sha2-256 + + String digest_length = mh_version0.toHex().substring(2, 4); + int digest_length_int = Integer.parseInt(digest_length, 16); // 0x20 = 32 bytes + LOGGER.info("mh digest_length : " + digest_length + " [" + digest_length_int + "]"); + + String digest_value = mh_version0.toHex().substring(4, 68); + LOGGER.info("mh digest_value : " + digest_value); + + // Convert digest value to byte array + byte[] byteValue = HexFormat.of().parseHex(digest_value); + LOGGER.debug("byteValue len : " + byteValue.length); + + // Derive Algorand address + derived_reserve_addr = new Address(byteValue).toString(); + + } catch (Exception e1) { + e1.printStackTrace(); + } + + return derived_reserve_addr; + } + + public static String arc19DecodeAlgorandAddressToCIDv0(String reserve_addr) { + try { + byte[] addr_bytes = new Address(reserve_addr).getBytes(); + Multihash m2 = new Multihash(Multihash.Type.sha2_256, addr_bytes); + return m2.toBase58(); + } catch (Exception e) { + LOGGER.warn("Exception: " + e.getMessage()); + } + return null; + } + + public static String arc19DecodeAlgorandAddressToCIDv1(String reserve_addr) { + try { + byte[] addr_bytes = new Address(reserve_addr).getBytes(); + + // Return base32 value + Cid c2 = new Cid(1L, Codec.Raw, Multihash.Type.sha2_256, addr_bytes); + return c2.toString(); + } catch (Exception e) { + LOGGER.warn("Exception: " + e.getMessage()); + } + return null; + } + + public static String encodeCIDv1ToARC19AlgorandAddress(String cid_str) { + String derived_reserve_addr = ""; + + // Parse the CID + Cid cid_version1 = Cid.decode(cid_str); + //Cid cid_version1 = new Cid(1L, Codec.Raw, Multihash.Type.sha2_256, cid_str.getBytes()); + LOGGER.info("codec : " + cid_version1.codec); + LOGGER.info("version : " + cid_version1.version); + LOGGER.info("hashCode : " + cid_version1.hashCode()); + LOGGER.info("hashlen : " + cid_version1.getHash().length); + LOGGER.info(""); + + LOGGER.info("base58 : " + cid_version1.toBase58()); + LOGGER.info("hex : " + cid_version1.toHex()); + LOGGER.info("string : " + cid_version1.toString()); + LOGGER.info(""); + + try { + // parse the multihash, https://multiformats.io/multihash/ + + //Multihash mh_version0 = Multihash.decode(cid_version1.toString()); + //LOGGER.debug("mh hex : " + mh_version0.toHex()); + + // Early exit + if (cid_version1.toHex().length() != 72) { + System.out.println("cid_version1.toHex().length(): " + cid_version1.toHex().length()); + return ""; + } + + // https://github.com/multiformats/multicodec/blob/master/table.csv + String hash_func_type = cid_version1.toHex().substring(0, 2); + LOGGER.info("mh hash_func_type : " + hash_func_type); // 0x01 = cidv1 + + String multi_codec = cid_version1.toHex().substring(2, 4); + LOGGER.info("mh multi_codec : " + multi_codec); // 0x70 = dag-pb, 0x55 = raw + + String multihash = cid_version1.toHex().substring(4, 6); + LOGGER.info("mh multihash : " + multihash); // 0x12 = multihash sha2-256 + + String digest_length = cid_version1.toHex().substring(6, 8); + int digest_length_int = Integer.parseInt(digest_length, 16); // 0x20 = 32 bytes + LOGGER.info("mh digest_length : " + digest_length + " [" + digest_length_int + "]"); + + String digest_value = cid_version1.toHex().substring(8, 72); + LOGGER.info("mh digest_value : " + digest_value); + + // Convert digest value to byte array + byte[] byteValue = HexFormat.of().parseHex(digest_value); + LOGGER.info("byteValue len : " + byteValue.length); + + // Derive Algorand address + derived_reserve_addr = new Address(byteValue).toString(); + + } catch (Exception e1) { + e1.printStackTrace(); + } + + return derived_reserve_addr; + } + + public static ASAVerificationStatus verifyARC3Asset(IPFSConnector ipfs_connector, ARC3Asset _arcasset, ARC3MetaData _arc3metadata, String _metajson) { + boolean verified = true; + ArrayList verified_properties = new ArrayList(); + ArrayList major_issues = new ArrayList(); + ArrayList warnings = new ArrayList(); + int score = 10; + + // NFT mutability + if (false || + (null == _arcasset.getManager()) || + ((null != _arcasset.getManager()) && ("".equals(_arcasset.getManager().toString()))) || + false) { + verified_properties.add("ASA is immutable since manager address is blank or set to \"\""); + } else { + warnings.add("Manager address is set, NFT is mutable (not yours)"); + score = score - 1; + } + + // NFT Clawback + if (false || + (null == _arcasset.getClawback()) || + ((null != _arcasset.getClawback()) && ("".equals(_arcasset.getClawback().toString()))) || + false) { + verified_properties.add("ASA cannot currently be withdrawn since clawback address is blank or set to \"\""); + } else { + warnings.add("Clawback address is set, ASA can be withdrawn (not yours)"); + } + + // NFT Freeze + if (false || + (null == _arcasset.getFreeze()) || + ((null != _arcasset.getFreeze()) && ("".equals(_arcasset.getFreeze().toString()))) || + false) { + verified_properties.add("ASA cannot currently be frozen since freeze address is blank or set to \"\""); + } else { + warnings.add("Freeze address is set, ASA can be frozen (restricted)"); + } + + // Asset name constraints + if (true && + _arcasset.getAssetURL().endsWith("#arc3") && + !_arcasset.getAssetName().equals("arc3") && + !_arcasset.getAssetName().contains("@arc3") && + true) { + verified_properties.add("asset URL endswith #arc3 and name is not fixed to arc3 or contains @arc3"); + } + + // URL constraints + if (_arcasset.getAssetURL().startsWith("ipfs://")) { + verified_properties.add("asset URL uses IPFS"); + } else if (_arcasset.getAssetURL().startsWith("https://")) { + warnings.add("Asset URL uses https:// instead of IPFS"); + } else { + verified = false; + major_issues.add("ARC3 ASA does not use ipfs:// or https://"); + } + + /** + * Metadata content + */ + if (_metajson.contains("{") && _metajson.contains("}")) { + byte[] sha256 = CryptUtils.calculateSHA256(_metajson); + String sha256_base64 = StringsUtils.encodeBytesToBase64(sha256); + + // asset metadata hash + if (null != _arcasset.getAssetMetadataHashSTR()) { + if (!_arcasset.getAssetMetadataHashSTR().equals(sha256_base64)) { + warnings.add("Metadata hash (" + _arc3metadata.getName() + ") does not match the calculated value (" + sha256_base64 + ")"); + } else { + verified_properties.add("Calculated metadata hash matches the ASA specified hash (" + _arcasset.getAssetMetadataHashSTR() + ")"); + } + } else { + verified = false; + major_issues.add("No metadata hash value specified in the ASA"); + } + + // Metadata 'name' should be related to ASA unit-name + if ((null != _arcasset.getUnitName() && (null != _arc3metadata.getName()))) { + double similarity = StringsUtils.lcsSimilarity(_arcasset.getUnitName(),_arc3metadata.getName()); + LOGGER.debug("similarity: " + similarity); + if (_arcasset.getUnitName().equals(_arc3metadata.getName())) { + verified_properties.add("Metadata name identical to the ASA specified unit name (" + _arcasset.getUnitName() + ")"); + } else if (false || + ((null != _arc3metadata.getName()) && _arcasset.getUnitName().contains(_arc3metadata.getName())) || + ((null != _arc3metadata.getName()) &&_arc3metadata.getName().contains(_arcasset.getUnitName())) || + (similarity >= 0.2d) || // hey, be nice, unitName is restricted to 8 chars + false) { + verified_properties.add("Metadata name (" + _arc3metadata.getName() + ") related the ASA specified unit name (" + _arcasset.getUnitName() + ")"); + } else { + if (null == _arc3metadata.getName()) { + warnings.add("Missing metadata name does not match the ASA specified unitname (" + _arcasset.getUnitName() + ")"); + } else { + warnings.add("Metadata name (" + _arc3metadata.getName() + ") does not look similar the ASA specified unitname (" + _arcasset.getUnitName() + ")"); + } + } + } else { + if (null == _arc3metadata.getName()) { + warnings.add("No unit name value specified in the ARC3 ASA metadata"); + } else { + warnings.add("No unit name value specified in the ARC3 ASA"); + } + score = score - 1; + } + + // image (metadata) + if ((null != _arc3metadata.getImage()) && (null != _arc3metadata.getImage_integrity())) { + + // download the image and calculate base64 of sha256 + byte[] image_bytes = ipfs_connector.getBinaryContent(_arc3metadata.getImage()); + byte[] image_sha256 = CryptUtils.calculateSHA256FromByteArray(image_bytes); + String image_sha256_base64 = StringsUtils.encodeBytesToBase64(image_sha256); + + // verify image_integrity + if (_arc3metadata.getImage_integrity().equals("sha256-" + image_sha256_base64)) { + verified_properties.add("Calculated image_integrity hash matches the metadata specified hash (" + image_sha256_base64 + ")"); + } else { + verified = false; + major_issues.add("Calculated image_integrity hash (" + image_sha256_base64 + ") does not match the metadata specified hash (" + _arc3metadata.getImage_integrity().replace("sha256-", "") + ")"); + } + } + + // animation_url (metadata) + if ((null != _arc3metadata.getAnimation_url()) && (null != _arc3metadata.getAnimation_url_integrity())) { + + // download the animation media and calculate base64 of sha256 + byte[] animation_bytes = ipfs_connector.getBinaryContent(_arc3metadata.getAnimation_url()); + byte[] animation_sha256 = CryptUtils.calculateSHA256FromByteArray(animation_bytes); + String animation_sha256_base64 = StringsUtils.encodeBytesToBase64(animation_sha256); + + // animation_url_integrity + if (_arc3metadata.getAnimation_url_integrity().equals("sha256-" + animation_sha256_base64)) { + verified_properties.add("Calculated animation_url_integrity hash matches the metadata specified hash (" + animation_sha256_base64 + ")"); + } else { + verified = false; + major_issues.add("Calculated animation_url_integrity hash (" + animation_sha256_base64 + ") does not match the metadata specified hash (" + _arc3metadata.getAnimation_url_integrity().replace("sha256-", "") + ")"); + } + + } + + // external_url (metadata) + if ((null != _arc3metadata.getExternal_url()) && (null != _arc3metadata.getExternal_url_integrity())) { + + // download the external_url media and calculate base64 of sha256 + byte[] external_bytes = ipfs_connector.getBinaryContent(_arc3metadata.getExternal_url()); + byte[] external_sha256 = CryptUtils.calculateSHA256FromByteArray(external_bytes); + String external_sha256_base64 = StringsUtils.encodeBytesToBase64(external_sha256); + + // animation_url_integrity + if (_arc3metadata.getExternal_url_integrity().equals("sha256-" + external_sha256_base64)) { + verified_properties.add("Calculated external_url_integrity hash matches the metadata specified hash (" + external_sha256_base64 + ")"); + } else { + verified = false; + major_issues.add("Calculated external_url_integrity hash (" + external_sha256_base64 + ") does not match the metadata specified hash (" + _arc3metadata.getExternal_url_integrity().replace("sha256-", "") + ")"); + } + + } + + } else { + verified = false; + major_issues.add("Metadata does not seem to be valid JSON"); + } + + if (!warnings.isEmpty()) score = score - warnings.size(); + if (!verified) score = 0; + if (score < 0) score = 0; + + return new ASAVerificationStatus(verified, verified_properties, major_issues, warnings, score); + } + + public static ASAVerificationStatus verifyARC19Asset(IPFSConnector ipfs_connector, ARC19Asset _arcasset, ARC69ARC19MetaData _arc19metadata, String _metajson) { + boolean verified = true; + ArrayList verified_properties = new ArrayList(); + ArrayList major_issues = new ArrayList(); + ArrayList warnings = new ArrayList(); + int score = 10; + + // NFT mutability + if (false || + (null == _arcasset.getManager()) || + ((null != _arcasset.getManager()) && ("".equals(_arcasset.getManager().toString()))) || + false) { + verified_properties.add("ASA is immutable since manager address is blank or set to \"\""); + } else { + warnings.add("Manager address is set, NFT is mutable (not yours)"); + score = score - 1; + } + + // NFT Clawback + if (false || + (null == _arcasset.getClawback()) || + ((null != _arcasset.getClawback()) && ("".equals(_arcasset.getClawback().toString()))) || + false) { + verified_properties.add("ASA cannot currently be withdrawn since clawback address is blank or set to \"\""); + } else { + warnings.add("Clawback address is set, ASA can be withdrawn (not yours)"); + } + + // NFT Freeze + if (false || + (null == _arcasset.getFreeze()) || + ((null != _arcasset.getFreeze()) && ("".equals(_arcasset.getFreeze().toString()))) || + false) { + verified_properties.add("ASA cannot currently be frozen since freeze address is blank or set to \"\""); + } else { + warnings.add("Freeze address is set, ASA can be frozen (restricted)"); + } + + // URL constraints + if (_arcasset.getAssetURL().startsWith("template-ipfs://")) { + + String assetURL = _arcasset.getAssetURL(); + assetURL = assetURL.replace("template-ipfs://{",""); + assetURL = assetURL.replace("}",""); + + String[] parts = assetURL.split(":"); + if (parts.length != 5) { + verified = false; + major_issues.add("ARC19 ASA url has an invalid nr of parameters in the ipfs template schema: " + parts.length); + score = score - 5; + } else { + String template = parts[0]; + String version = parts[1]; + String multicodec = parts[2]; + String fieldname = parts[3]; + String hashtype = parts[4]; + + // template + if (template.equals("ipfscid")) { + verified_properties.add("ARC19 ASA url template is 'ipfscid'"); + } else { + verified = false; + major_issues.add("ARC19 ASA url template needs to be 'ipfscid'"); + } + + // version + if (false || + "0".equals(version) || + "1".equals(version) || + false) { + verified_properties.add("ARC19 ASA url specifies IPFS CID version '0' or '1'"); + } else { + verified = false; + major_issues.add("ARC19 ASA url does not specify a valid IPFS CID version: " + version); + } + + // multicodec + if (false || + "raw".equals(multicodec) || + "dag-pb".equals(multicodec) || + false) { + verified_properties.add("ARC19 ASA url specifies valid multicodec"); + } else { + verified = false; + major_issues.add("ARC19 ASA url does not specify a valid multicodec: " + multicodec); + } + + // fieldname + if ("reserve".equals(fieldname)) { + verified_properties.add("ARC19 ASA url fieldname is 'reserve'"); + } else { + verified = false; + major_issues.add("ARC19 ASA url fieldname is not 'reserve', fieldname set to " + fieldname); + } + + // hashtype + if ("sha2-256".equals(hashtype)) { + verified_properties.add("ARC19 ASA url hashtype is 'sha2-256'"); + } else { + verified = false; + major_issues.add("ARC19 ASA url hashtype is not 'sha2-256', fieldname set to " + fieldname); + } + + } + + } else { + verified = false; + major_issues.add("ARC19 ASA url does not begin with template schema"); + } + + /** + * Metadata content + */ + if (_metajson.contains("{") && _metajson.contains("}")) { + + // Metadata 'name' should be related to ASA unit-name + if ((null != _arcasset.getUnitName() && (null != _arc19metadata.getName()))) { + + double similarity = StringsUtils.lcsSimilarity(_arcasset.getUnitName(),_arc19metadata.getName()); + if (_arcasset.getUnitName().equals(_arc19metadata.getName())) { + verified_properties.add("Metadata name identical to the ASA specified unit name (" + _arcasset.getUnitName() + ")"); + } else if (false || + ((null != _arc19metadata.getName()) && _arcasset.getUnitName().contains(_arc19metadata.getName())) || + ((null != _arc19metadata.getName()) &&_arc19metadata.getName().contains(_arcasset.getUnitName())) || + (similarity >= 0.2d) || // hey, be nice, unitName is restricted to 8 chars + false) { + verified_properties.add("Metadata name (" + _arc19metadata.getName() + ") related the ASA specified unit name (" + _arcasset.getUnitName() + ")"); + } else { + if (null == _arc19metadata.getName()) { + warnings.add("Missing metadata name does not match the ASA specified unitname (" + _arcasset.getUnitName() + ")"); + } else { + warnings.add("Metadata name (" + _arc19metadata.getName() + ") does not match the ASA specified unitname (" + _arcasset.getUnitName() + ")"); + } + } + } else { + if (null == _arc19metadata.getName()) { + warnings.add("No unit name value specified in the ARC19 ASA metadata"); + } else { + warnings.add("No unit name value specified in the ARC19 ASA"); + } + score = score - 1; + } + + } else { + verified = false; + major_issues.add("Metadata does not seem to be valid JSON"); + } + + if (!warnings.isEmpty()) score = score - warnings.size(); + if (!verified) score = 0; + if (score < 0) score = 0; + + return new ASAVerificationStatus(verified, verified_properties, major_issues, warnings, score); + } + + public static ASAVerificationStatus verifyARC69Asset(ARC69Asset _arcasset, ARC69ARC19MetaData _arc69metadata, String _metajson) { + boolean verified = true; + ArrayList verified_properties = new ArrayList(); + ArrayList major_issues = new ArrayList(); + ArrayList warnings = new ArrayList(); + int score = 10; + + // NFT mutability + if (false || + (null == _arcasset.getManager()) || + ((null != _arcasset.getManager()) && ("".equals(_arcasset.getManager().toString()))) || + false) { + verified_properties.add("ASA is immutable since manager address is blank or set to \"\""); + } else { + warnings.add("Manager address is set, NFT is mutable (not yours)"); + score = score - 1; + } + + // NFT Clawback + if (false || + (null == _arcasset.getClawback()) || + ((null != _arcasset.getClawback()) && ("".equals(_arcasset.getClawback().toString()))) || + false) { + verified_properties.add("ASA cannot currently be withdrawn since clawback address is blank or set to \"\""); + } else { + warnings.add("Clawback address is set, ASA can be withdrawn (not yours)"); + } + + // NFT Freeze + if (false || + (null == _arcasset.getFreeze()) || + ((null != _arcasset.getFreeze()) && ("".equals(_arcasset.getFreeze().toString()))) || + false) { + verified_properties.add("ASA cannot currently be frozen since freeze address is blank or set to \"\""); + } else { + warnings.add("Freeze address is set, ASA can be frozen (restricted)"); + } + + // URL constraints on schema + if (_arcasset.getAssetURL().startsWith("ipfs://")) { + verified_properties.add("ARC69 ASA media URL uses IPFS"); + } else if (_arcasset.getAssetURL().startsWith("https://")) { + warnings.add("ARC69 ASA media URL uses https:// instead of IPFS"); + } else if (_arcasset.getAssetURL().startsWith("template-ipfs:")) { + warnings.add("ARC69 ASA media URL is using ARC19 style URL. Kinda neat but fails a SHOULD requirement."); + } else { + verified = false; + major_issues.add("ARC69 ASA does not use ipfs:// or https:// for media URL"); + } + + // URL contstraints on media type + if (false || + _arcasset.getAssetURL().endsWith("#v") || + _arcasset.getAssetURL().endsWith("#i") || + _arcasset.getAssetURL().endsWith("#a") || + _arcasset.getAssetURL().endsWith("#p") || + _arcasset.getAssetURL().endsWith("#h") || + false) { + verified_properties.add("ARC69 ASA media URL specifies media type using # fragment identifier"); + } else { + warnings.add("ARC69 ASA media URL does not specify media type using # fragment identifier"); + } + + /** + * Metadata content + */ + if (_metajson.contains("{") && _metajson.contains("}")) { + + // Metadata 'name' should be related to ASA unit-name + if ((null != _arcasset.getUnitName() && (null != _arc69metadata.getName()))) { + + double similarity = StringsUtils.lcsSimilarity(_arcasset.getUnitName(),_arc69metadata.getName()); + if (_arcasset.getUnitName().equals(_arc69metadata.getName())) { + verified_properties.add("Metadata name identical to the ASA specified unit name (" + _arcasset.getUnitName() + ")"); + } else if (false || + ((null != _arc69metadata.getName()) && _arcasset.getUnitName().contains(_arc69metadata.getName())) || + ((null != _arc69metadata.getName()) &&_arc69metadata.getName().contains(_arcasset.getUnitName())) || + (similarity >= 0.2d) || // hey, be nice, unitName is restricted to 8 chars + false) { + verified_properties.add("Metadata name (" + _arc69metadata.getName() + ") related the ASA specified unit name (" + _arcasset.getUnitName() + ")"); + } else { + if (null == _arc69metadata.getName()) { + warnings.add("Missing metadata name does not match the ASA specified unitname (" + _arcasset.getUnitName() + ")"); + } else { + warnings.add("Metadata name (" + _arc69metadata.getName() + ") does not match the ASA specified unitname (" + _arcasset.getUnitName() + ")"); + } + } + } else { + if (null == _arc69metadata.getName()) { + warnings.add("No unit name value specified in the ARC69 ASA metadata"); + } else { + warnings.add("No unit name value specified in the ARC69 ASA"); + } + score = score - 1; + } + + } else { + verified = false; + major_issues.add("Metadata does not seem to be valid JSON"); + } + + if (!warnings.isEmpty()) score = score - warnings.size(); + if (!verified) score = 0; + if (score < 0) score = 0; + + return new ASAVerificationStatus(verified, verified_properties, major_issues, warnings, score); + } + + public static AlgoLocalWallet getWalletWithName(final String _walletName) { + File walletDirectory = new File(".avm/wallets/" + _walletName); + if (!walletDirectory.exists()) return null; + if (walletDirectory.listFiles().length == 0) return null; + try { + File f = walletDirectory.listFiles()[0]; + String json = FilesUtils.readAllFromFileWithPath(f.getAbsolutePath()); + AlgoLocalWallet wallet = JSONUtils.createPOJOFromJSON(json, AlgoLocalWallet.class); + LOGGER.debug("Just restored ALGO wallet with name " + _walletName + " from " + f.getAbsolutePath()); + return wallet; + } catch (Exception e) { + LOGGER.warn("e: " + e.getMessage()); + SystemUtils.halt(); + } + return null; + } + + public static boolean createWalletWithName(final String _walletName, final String _mnemonic) { + File walletDirectory = new File(".avm/wallets/" + _walletName); + if (walletDirectory.exists()) { + LOGGER.info("Wallet with name " + _walletName + " already exists"); + return true; + } + if ((null != walletDirectory.listFiles()) && walletDirectory.listFiles().length == 0) { + LOGGER.error("Wallet folder with name " + _walletName + " already exists but is empty"); + return false; + } + + try { + Account generatedAccount = new Account(_mnemonic); + AlgoLocalWallet wallet = new AlgoLocalWallet(); + wallet.setWalletName(_walletName); + wallet.setMnemonic(_mnemonic); + wallet.setAddress(generatedAccount.getAddress().toString()); + LOGGER.info("Generated wallet from mnemonic with name " + _walletName + " with address " + wallet.getAddress()); + String json = JSONUtils.createJSONFromPOJO(wallet); + String outfilePath = ".avm/wallets/" + _walletName + "/algowallet.json"; + walletDirectory.mkdirs(); + FilesUtils.writeToFileUNIX(json, outfilePath); + return true; + } catch (Exception e) { + LOGGER.warn("e: " + e.getMessage()); + } + return false; + } + + public static boolean createNewRandomWalletWithName(final String _walletName) { + String mnemonic = createNewRandomAccount().toMnemonic(); + return createWalletWithName(_walletName, mnemonic); + } + + public static Account createNewRandomAccount() { + Account acc = null; + try { + acc = new Account(); + } catch (Exception e) { + LOGGER.error("Account creation error " + e.getMessage()); + SystemUtils.halt(); + } + return acc; + } + + public static boolean isValidAlgorandAddressSimple(String _address) { + return ALGO_ADDRESS_PATTERN.matcher(_address).matches(); + } + + + private static final char[] ALGORAND_BASE32_MAP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".toCharArray(); + private static final int[] DECODE_MAP = new int[128]; + + static { + for (int i = 0; i < DECODE_MAP.length; i++) { + DECODE_MAP[i] = -1; + } + for (int i = 0; i < ALGORAND_BASE32_MAP.length; i++) { + DECODE_MAP[ALGORAND_BASE32_MAP[i]] = i; + } + } + + public static boolean isValidAlgorandAddress(String _address) { + try { + new Address(_address); + return true; + } catch (Exception e) { + return false; + } + } + + public static AVMNFTStandard identifyARCStandardFromMetadata(String metadata_json) { + + ArrayList keys = JSONUtils.getKeyNamesOfJSON(metadata_json); + for (String keyname: keys) { + if (keyname.contains("integrity")) return AVMNFTStandard.ARC3; + if (keyname.equals("standard")) { + if (metadata_json.contains("arc69")) return AVMNFTStandard.ARC69; + } + } + + return AVMNFTStandard.UNKNOWN; + } + + public static Address createAddressFromSTR(final String _addr) { + try { + Address algorand_address = new Address(_addr); + return algorand_address; + } catch (Exception e) { + LOGGER.error("String is not a valid Algorand address: " + _addr); + SystemUtils.halt(); + } + return null; + } + + public static String printASAAssetOwnership(BigInteger _amount, ASAContentOnchainReply _reply, AVMNFTStandard _arcstandard) { + StringBuffer sb = new StringBuffer(); + sb.append(StringsUtils.cutAndPadStringToN("amount=" + _amount + "/" + NumUtils.prettyprintTotal(_reply.getParams().getTotal()), 30)); + if (null != _reply.getParams().getUnit_name()) { + if (_arcstandard == AVMNFTStandard.UNKNOWN) { + sb.append(StringsUtils.cutAndPadStringToN(" unit-name=" + _reply.getParams().getUnit_name(), 25) + StringsUtils.cutAndPadStringToN(" ", 19)); + } else { + sb.append(StringsUtils.cutAndPadStringToN(" unit-name=" + _reply.getParams().getUnit_name(), 25) + StringsUtils.cutAndPadStringToN(" standard=" + _arcstandard, 19)); + } + + } else { + if (_arcstandard == AVMNFTStandard.UNKNOWN) { + sb.append(StringsUtils.cutAndPadStringToN(" unit-name=MISSING", 25) + StringsUtils.cutAndPadStringToN(" ", 19)); + } else { + sb.append(StringsUtils.cutAndPadStringToN(" unit-name=MISSING", 25) + StringsUtils.cutAndPadStringToN(" standard=" + _arcstandard, 19)); + } + } + if (null != _reply.getParams().getUrl()) { + if (_reply.getParams().getUrl().length() > 65) { + sb.append(StringsUtils.cutAndPadStringToN(" url=" + StringsUtils.cutStringFromLeft(_reply.getParams().getUrl(),60) + "..", 70)); + } else { + sb.append(StringsUtils.cutAndPadStringToN(" url=" + _reply.getParams().getUrl(), 70)); + } + + } else { + sb.append(StringsUtils.cutAndPadStringToN(" url=MISSING", 70)); + } + sb.append(" assetid=" + _reply.getIndex()); + return sb.toString(); + } + + public static String printASAAssetOptins(ASAContentOnchainReply _reply) { + StringBuffer sb = new StringBuffer(); + if (null != _reply.getParams().getUnit_name()) { + sb.append(StringsUtils.cutAndPadStringToN(" unit-name=" + _reply.getParams().getUnit_name(), 30)); + } else { + sb.append(StringsUtils.cutAndPadStringToN(" unit-name=MISSING", 30)); + } + if (null != _reply.getParams().getUrl()) { + if (_reply.getParams().getUrl().length() > 65) { + sb.append(StringsUtils.cutAndPadStringToN(" url=" + StringsUtils.cutStringFromLeft(_reply.getParams().getUrl(),60) + "..", 70)); + } else { + sb.append(StringsUtils.cutAndPadStringToN(" url=" + _reply.getParams().getUrl(), 70)); + } + + } else { + sb.append(StringsUtils.cutAndPadStringToN(" url=MISSING", 70)); + } + sb.append(" index=" + _reply.getIndex()); + return sb.toString().replaceFirst(" ", ""); + } + + public static AVMPortfolio getAVMPortfolioForAccount(AVMBlockChainUltraConnector _ultra_connector, String _account_addr) { + return getAVMPortfolioForAccount(_ultra_connector, _account_addr, true, null, null, false); + } + + public static AVMPortfolio getAVMPortfolioForAccount(AVMBlockChainUltraConnector _ultra_connector, String _account_addr, boolean debug) { + return getAVMPortfolioForAccount(_ultra_connector, _account_addr, true, null, null, debug); + } + + public static AVMPortfolio getAVMPortfolioForAccount(AVMBlockChainUltraConnector _ultra_connector, String _account_addr, boolean _checkfornfts, HashMap _token_restriction, HashMap _nft_restriction, boolean _debug) { + LOGGER.debug("getAVMPortfolioForAccount()"); + + HashMap chainportfolio = new HashMap<>(); + + for (AVMChain chain: AVMChain.values()) { + //if (_debug) System.out.println("chain: " + chain); + + /** + * Verify RPC node connectivity + */ + AVMBlockChainConnector connector_temp = _ultra_connector.getConnectors().get(chain); + if (null == connector_temp) { + LOGGER.debug("We dont have a valid connector for chain " + chain); + } else { + Long latestBlockNr = AVMUtils.getLastRound(connector_temp); + if (null == latestBlockNr) { + LOGGER.warn("Seems we cant get a good connection to the chain " + chain); + LOGGER.info("Skipping and will move on .."); + } else { + if (_debug) LOGGER.info("We have a valid connector for chain " + chain +", latestBlockNr=" + latestBlockNr); + + HashMap tokens = new HashMap<>(); + HashMap nfttokens = new HashMap<>(); + AVMAccountBalance native_balance = null; + + AVMChainInfo chainInfo = AVMUtils.getAVMChainInfo(chain); + if (BlockchainType.valueOf(chainInfo.getType()) == _ultra_connector.getChainType()) { + AVMBlockChainConnector connector = _ultra_connector.getConnectors().get(chain); + + if (null != connector) { + + /** + * Check native balance (required for ASAs) + */ + native_balance = AVMUtils.getAccountNativeBalance(connector, createAddressFromSTR(_account_addr)); + if ((null != native_balance) && (!native_balance.isEmpty())) { + + // DEBUG + if (_debug) { + System.out.println(" - algoWalletBalance (uAlgo) : " + native_balance.getBalanceInMicroAlgo()); + System.out.println(" - algoWalletBalance (Algo) : " + native_balance.getBalanceInALGO()); + } + + Long txCount = 0L; + Long calculatedMinimumBalance = 0L; + Long total_apps_optedin = 0L; + Long total_created_apps = 0L; + boolean accounts_holds_assets = false; + + if (null != connector.getIndexer_instance()) { + txCount = AVMUtils.getTransactionSummaryForAccount(connector, _account_addr).getTxcount(); + + /** + * ASA balances, opt-ins, .. + */ + // Check if account holds assets + accounts_holds_assets = AVMUtils.holdsAssets(connector, createAddressFromSTR(_account_addr)); + if (accounts_holds_assets) { + LOGGER.debug("Account holds assets.."); + + List localstates_owned = AVMUtils.getLocalStateInfoForAccount(connector, AVMUtils.createAddressFromSTR(_account_addr)); + if (localstates_owned.size()>0) { + LOGGER.debug("Found some localstates:"); + for (ApplicationLocalState localstate: localstates_owned) { + LOGGER.debug(" - localstate for appid: " + localstate.id); + } + } + + calculatedMinimumBalance = AVMUtils.calculateMinimumBalanceForASAOwnedByAccount(connector, AVMUtils.createAddressFromSTR(_account_addr)); + total_apps_optedin = AVMUtils.getTotalAppsOptedInForAccount(connector, AVMUtils.createAddressFromSTR(_account_addr)); + total_created_apps = AVMUtils.getTotalCreatedAppsForAccount(connector, AVMUtils.createAddressFromSTR(_account_addr)); + + // DEBUG + if (_debug) { + System.out.println(" - calculatedMinimumBalance (uAlgo) : " + calculatedMinimumBalance); + System.out.println(" - total_apps_optedin : " + total_apps_optedin); + System.out.println(" - total_created_apps : " + total_created_apps); + } + + /** + * ASAs + */ + if (_debug) System.out.println("getTotalAssetsOptedInForAccount()"); + if (AVMUtils.getTotalAssetsOptedInForAccount(connector, AVMUtils.createAddressFromSTR(_account_addr)) > 0L) { + if (_debug) System.out.println("Found some ASA opt-ins: "); + List asas_optins = AVMUtils.getASAOwnershipInfoForAccount(connector, AVMUtils.createAddressFromSTR(_account_addr)); + for (AssetHolding asa: asas_optins) { + if (_debug) System.out.println(" - " + asa.assetId + ": deleted=" + asa.deleted + " frozen:" + asa.isFrozen + " amount: " + asa.amount + " optedInAtRound: " + asa.optedInAtRound); + if (_debug) System.out.println("checkIfASAExists()"); + if (AVMUtils.checkIfASAExists(connector, asa.assetId)) { + if (_debug) System.out.println("getASARawJSONResponse()"); + String json = AVMUtils.getASARawJSONResponse(connector, asa.assetId); + if (_debug) System.out.println("identifyARCStandardFromASAJSON()"); + AVMNFTStandard standard = AVMUtils.identifyARCStandardFromASAJSON(connector, json); + if (_debug) System.out.println("standard: " + standard.name()); + ASAContentOnchainReply reply = AVMUtils.getASAJSON(json); + if (_debug) System.out.println("ASA name: " + reply.getParams().getName()); + if ((!asa.amount.equals(BigInteger.ZERO)) && (standard != AVMNFTStandard.UNKNOWN)) { + if (_debug) System.out.println(AVMUtils.printASAAssetOwnership(asa.amount, reply, standard)); + } else { + if (_debug) System.out.println(AVMUtils.printASAAssetOwnership(asa.amount, reply, standard)); + } + + // We need at least non 0 ASA for this to be interesting (not listing empty opt-ins) + if ((!asa.amount.equals(BigInteger.ZERO))) { + if (null != reply.getParams().getUnit_name()) { + if (standard == AVMNFTStandard.UNKNOWN) { + Double amountAlgo = Double.parseDouble("" + asa.amount.longValue()) / 1000000.0d; + tokens.put(reply.getIndex().toString(), new AVMAccountBalance(asa.amount.longValue(), amountAlgo, new AVMCurrency(reply.getParams().getName(), reply.getParams().getUnit_name(), reply.getParams().getDecimals()), false)); + } else { + nfttokens.put(reply.getIndex().toString(), new AVMNftAccountBalance(asa.amount.toString(), false, reply.getParams().getName(), reply.getParams().getUnit_name())); + } + if (_debug) System.out.println("ASA DEBUG: " + reply.getParams().getUnit_name() + " standard: " + standard); + } + } + } + } + } + } + } else { + LOGGER.warn("txCount values etc wont be accurate since no indexer is present for chain " + chain); + } + + AVMChainPortfolio portfolio = new AVMChainPortfolio(_account_addr, chain.toString(), native_balance, txCount, tokens, nfttokens, calculatedMinimumBalance, total_apps_optedin, total_created_apps, accounts_holds_assets); + chainportfolio.put(chain, portfolio); + + } + } + + } + } + } + } + + return new AVMPortfolio(_account_addr, chainportfolio, System.currentTimeMillis()/1000L); + } + + public static void printARCInfo(AVMBlockChainConnector _connector, AVMNFTStandard _standard, Long _assetID) { + if (_standard == AVMNFTStandard.ARC3) { + ARC3Asset arcasset = AVMUtils.getARC3Info(_connector, _assetID); + System.out.println(arcasset.toString()); + } + if (_standard == AVMNFTStandard.ARC19) { + ARC19Asset arcasset = AVMUtils.getARC19Info(_connector, _assetID); + System.out.println(arcasset.toString()); + } + if (_standard == AVMNFTStandard.ARC69) { + ARC69Asset arc69asset = AVMUtils.getARC69Info(_connector, _assetID); + System.out.println(arc69asset.toString()); + } + } + + public static String getARCImageURL(AVMBlockChainConnector _connector, Long _assetid) { + String asa_json = AVMUtils.getASARawJSONResponse(_connector, _assetid); + AVMNFTStandard standard = AVMUtils.identifyARCStandardFromASAJSON(_connector, asa_json); + if (standard == AVMNFTStandard.ARC3) { + ARC3Asset arcasset = AVMUtils.createARC3Asset(asa_json); + + System.out.println("assetURL: " + arcasset.getAssetURL()); + IPFSConnector ipfs_connector = new IPFSConnector(); + + // Grab the metadata + String metajson = ipfs_connector.getStringContent(arcasset.getAssetURL().replace("#arc3","")); + ARC3MetaData arcmetadata = JSONUtils.createPOJOFromJSON(metajson, ARC3MetaData.class); + return(arcmetadata.getImage()); + } + if (standard == AVMNFTStandard.ARC19) { + ARC19Asset arcasset = AVMUtils.createARC19Asset(asa_json); + String cid = AVMUtils.extractCIDFromARC19URLAndReserveAddress(arcasset.getAssetURL(), arcasset.getReserve().toString()); + + if (!"".equals(cid)) { + LOGGER.info("Resolved cid from ARC19 template to: " + cid); + IPFSConnector ipfs_connector = new IPFSConnector(); + + // Grab the metadata and print the 'image' key content + String metajson = ipfs_connector.getStringContent("ipfs://" + cid); + ARC69ARC19MetaData arcmetadata = JSONUtils.createPOJOFromJSON(metajson, ARC69ARC19MetaData.class); + return(arcmetadata.getImage()); + + } + } + if (standard == AVMNFTStandard.ARC69) { + ARC69Asset arcasset = AVMUtils.createARC69Asset(asa_json); + + // Special case, ARC69 asa with ARC19 encoded url + if (arcasset.getAssetURL().contains("template-ipfs")) { + String cid = AVMUtils.extractCIDFromARC19URLAndReserveAddress(arcasset.getAssetURL(), arcasset.getReserve().toString()); + return("ipfs://" + cid); + } else { + return(arcasset.getAssetURL()); + } + } + return "MISSING"; + } + + public static String getARCMetadataFromASAAssetID(AVMBlockChainConnector _connector, Long _assetid) { + String asa_json = AVMUtils.getASARawJSONResponse(_connector, _assetid); + + AVMNFTStandard standard = AVMUtils.identifyARCStandardFromASAJSON(_connector, asa_json); + if (standard == AVMNFTStandard.ARC3) { + ARC3Asset arcasset = AVMUtils.createARC3Asset(asa_json); + + System.out.println("assetURL: " + arcasset.getAssetURL()); + IPFSConnector ipfs_connector = new IPFSConnector(); + + // Grab the metadata + String metajson = ipfs_connector.getStringContent(arcasset.getAssetURL()); + return(metajson); + } + if (standard == AVMNFTStandard.ARC19) { + ARC19Asset arcasset = AVMUtils.createARC19Asset(asa_json); + String cid = AVMUtils.extractCIDFromARC19URLAndReserveAddress(arcasset.getAssetURL(), arcasset.getReserve().toString()); + + if (!"".equals(cid)) { + LOGGER.info("Resolved cid from ARC19 template to: " + cid); + IPFSConnector ipfs_connector = new IPFSConnector(); + + // Grab the metadata + String metajson = ipfs_connector.getStringContent("ipfs://" + cid); + return(metajson); + } + } + if (standard == AVMNFTStandard.ARC69) { + ARC69Asset arcasset = AVMUtils.createARC69Asset(asa_json); + LOGGER.debug("Using indexer to fetch latest tx note .."); + String latesttxnote = AVMUtils.getASALatestConfigTransactionNote(_connector, arcasset.getAssetID()); + latesttxnote = StringsUtils.cleanJSON(latesttxnote); + return(latesttxnote); + } + + return "N/A"; + } + + public static ArrayList getARCMetadataHistoryFromASAAssetID(AVMBlockChainConnector _connector, Long _assetid) { + String asa_json = AVMUtils.getASARawJSONResponse(_connector, _assetid); + + ArrayList result = new ArrayList(); + + AVMNFTStandard standard = AVMUtils.identifyARCStandardFromASAJSON(_connector, asa_json); + if (standard == AVMNFTStandard.ARC3) { + ARC3Asset arcasset = AVMUtils.createARC3Asset(asa_json); + + System.out.println("assetURL: " + arcasset.getAssetURL()); + IPFSConnector ipfs_connector = new IPFSConnector(); + + // Grab the metadata + String metajson = ipfs_connector.getStringContent(arcasset.getAssetURL()); + result.add(new MetaDataEntry(metajson)); + return result; + } + if (standard == AVMNFTStandard.ARC19) { + ARC19Asset arcasset = AVMUtils.createARC19Asset(asa_json); + String cid = AVMUtils.extractCIDFromARC19URLAndReserveAddress(arcasset.getAssetURL(), arcasset.getReserve().toString()); + + if (!"".equals(cid)) { + LOGGER.info("Resolved cid from ARC19 template to: " + cid); + IPFSConnector ipfs_connector = new IPFSConnector(); + + // Grab the metadata + String metajson = ipfs_connector.getStringContent("ipfs://" + cid); + result.add(new MetaDataEntry(metajson)); + return result; + } + } + if (standard == AVMNFTStandard.ARC69) { + ARC69Asset arcasset = AVMUtils.createARC69Asset(asa_json); + LOGGER.debug("Using indexer to fetch latest tx note .."); + ArrayList txnotes = AVMUtils.getASAConfigTransactionNotes(_connector, arcasset.getAssetID()); + return txnotes; + } + + return result; + } + + public static ASAVerificationStatus verifyARCAsset(AVMBlockChainConnector _connector, Long _assetid) { + String asa_json = AVMUtils.getASARawJSONResponse(_connector, _assetid); + + AVMNFTStandard standard = AVMUtils.identifyARCStandardFromASAJSON(_connector, asa_json); + LOGGER.info("Standard determined to be: " + standard); + if (standard == AVMNFTStandard.ARC3) { + ARC3Asset arc3asset = AVMUtils.createARC3Asset(asa_json); + IPFSConnector ipfs_connector = new IPFSConnector(); + + // Grab the metadata + LOGGER.info("Getting metadata from assetURL " + arc3asset.getAssetURL()); + String metajson = ipfs_connector.getStringContent(arc3asset.getAssetURL().replace("#arc3","")); + ARC3MetaData arc3metadata = JSONUtils.createPOJOFromJSON(metajson, ARC3MetaData.class); + + ASAVerificationStatus vstatus = AVMUtils.verifyARC3Asset(ipfs_connector, arc3asset, arc3metadata, metajson); + return vstatus; + } + if (standard == AVMNFTStandard.ARC19) { + ARC19Asset arc19asset = AVMUtils.createARC19Asset(asa_json); + String cid = AVMUtils.extractCIDFromARC19URLAndReserveAddress(arc19asset.getAssetURL(), arc19asset.getReserve().toString()); + + if (!"".equals(cid)) { + LOGGER.info("Resolved cid from ARC19 template to: " + cid); + IPFSConnector ipfs_connector = new IPFSConnector(); + + // Grab the metadata + String metajson = ipfs_connector.getStringContent("ipfs://" + cid); + ARC69ARC19MetaData arcmetadata = JSONUtils.createPOJOFromJSON(metajson, ARC69ARC19MetaData.class); + + ASAVerificationStatus vstatus = AVMUtils.verifyARC19Asset(ipfs_connector, arc19asset, arcmetadata, metajson); + return vstatus; + } + } + if (standard == AVMNFTStandard.ARC69) { + ARC69Asset arcasset = AVMUtils.createARC69Asset(asa_json); + + // Grab the metadata + String metajson = AVMUtils.getASALatestConfigTransactionNote(_connector, arcasset.getAssetID()); + metajson = StringsUtils.cleanJSON(metajson); + ARC69ARC19MetaData arcmetadata = JSONUtils.createPOJOFromJSON(metajson, ARC69ARC19MetaData.class); + + ASAVerificationStatus vstatus = AVMUtils.verifyARC69Asset(arcasset, arcmetadata, metajson); + return vstatus; + } + return null; + } + + public static AVMPortfolio readLatestPortfolioSnapshot(String _address, String _snapshotfolder) { + String filePath = _snapshotfolder + "/" + _address + ".json"; + File f = new File(filePath); + if (f.exists()) { + String json = FilesUtils.readAllFromFileWithPath(filePath); + AVMPortfolio chainPortfolioSnapshot = JSONUtils.createPOJOFromJSON(json, AVMPortfolio.class); + return chainPortfolioSnapshot; + } else { + return null; + } + } + + public static void updatePortfolioSnapshot(AVMPortfolio _chainPortfolio, String _snapshotfolder) { + String json = JSONUtils.createJSONFromPOJO(_chainPortfolio); + if ((null != json) && (json.length() > 10)) { + try { + FilesUtils.createFolderUnlessExists(_snapshotfolder); + FilesUtils.writeToFileUNIX(json, _snapshotfolder + "/" + _chainPortfolio.getAccount_address() + ".json"); + } catch (Exception e) { + LOGGER.error("Unable to write to " + _snapshotfolder); + SystemUtils.halt(); + } + } else { + LOGGER.error("Malformed snapshot json?"); + SystemUtils.halt(); + } + } + + public static AVMPortfolioSimple createAVMPortfolioSimple(AVMPortfolio _avm_portfolio) { + if (null == _avm_portfolio) return null; + return new AVMPortfolioSimple(_avm_portfolio.getAccount_address(), _avm_portfolio.getChainportfolio()); + } + + public static AVMPortfolioDiffResult getAVMPortfolioDiff(AVMPortfolioSimple _portfolio, AVMPortfolioSimple _portfolio_ref) { + StringBuffer sb = new StringBuffer(); + sb.append("---------------------------------------------------------------------------------------\n"); + sb.append("Portfolio summary for account: " + _portfolio.getAccount_address() + "\n\n"); + AVMPortfolioDiff portfolio_diff = null; + double minValueToTrack = 0.0001d; + int symbol_char_offset = 25; + + boolean ref_portfolio_exists = false; + String breakline = "---------------------------------------------------------------------------------------"; + String breaklinemini = "----------------------------------------------"; + + if (null != _portfolio_ref) ref_portfolio_exists = true; + + for (AVMChain chain: _portfolio.getChainportfolio().keySet()) { + AVMChainInfo chainInfo = AVMUtils.getAVMChainInfo(chain); + AVMChainPortfolio chain_portfolio = _portfolio.getChainportfolio().get(chain); + AVMChainPortfolio chain_portfolio_ref = null; + AVMChainPortfolioDiff chain_portfolio_diff = null; + + if (ref_portfolio_exists) chain_portfolio_ref = _portfolio_ref.getChainportfolio().get(chain); + /** + * Check native balance + */ + int native_name_offset = 73; + AVMAccountBalance native_balance = chain_portfolio.getNativeBalance(); + if (!native_balance.isEmpty()) { + if (ref_portfolio_exists) { + BigDecimal native_balance_refBD = null; + if (null == chain_portfolio_ref) { + native_balance_refBD = new BigDecimal(0); + } else { + AVMAccountBalance native_balance_ref = chain_portfolio_ref.getNativeBalance(); + if (native_balance_ref == null) { + native_balance_refBD = new BigDecimal(0); + } else { + native_balance_refBD = new BigDecimal(native_balance_ref.getBalanceInALGO()); + } + } + BigDecimal native_balance_BD = new BigDecimal(native_balance.getBalanceInALGO()); + BigDecimal native_balance_diff = native_balance_BD.subtract(native_balance_refBD).setScale(2, RoundingMode.HALF_UP); + if (native_balance_diff.compareTo(BigDecimal.valueOf(minValueToTrack)) > 0) { + sb.append(StringsUtils.cutAndPadStringToN(chain + " balance: ", native_name_offset) + StringsUtils.cutAndPadStringToN(" (" + native_balance.getBalanceInALGO() + " " + chainInfo.getNativeCurrency().getSymbol() + ")", symbol_char_offset) + " diff: +" + native_balance_diff + "\n"); + + // Handle cases where new chain activity is noted + if (null == chain_portfolio_ref) chain_portfolio_ref = new AVMChainPortfolio(); + if (null == chain_portfolio_diff) chain_portfolio_diff = new AVMChainPortfolioDiff(); + + // Store our diff + chain_portfolio_diff.setAccount_address(chain_portfolio.getAccount_address()); + chain_portfolio_diff.setChain(chain.toString()); + + AVMAccountBalance native_balance_ref = null; + if (null == chain_portfolio_ref.getNativeBalance()) { + native_balance_ref = new AVMAccountBalance(0L, 0.0d, chainInfo.getNativeCurrency(), true); + } else { + native_balance_ref = chain_portfolio_ref.getNativeBalance(); + } + + Long native_balance_diff_uAlgo = native_balance.getBalanceInMicroAlgo() - native_balance_ref.getBalanceInMicroAlgo(); + Double native_balance_diff_in_ALGO = Double.parseDouble(native_balance_diff_uAlgo + "") / 100000d; + chain_portfolio_diff.setNativeBalance(new AVMAccountBalance(native_balance_diff_uAlgo, native_balance_diff_in_ALGO, chainInfo.getNativeCurrency(), false)); + + } else if (native_balance_diff.compareTo(BigDecimal.valueOf(-minValueToTrack)) < 0) { + if (native_balance_diff.toString().startsWith("-")) { + sb.append(StringsUtils.cutAndPadStringToN(chain + " balance", native_name_offset) + StringsUtils.cutAndPadStringToN(" (" + NumUtils.round(native_balance.getBalanceInALGO(),2) + " " + chainInfo.getNativeCurrency().getSymbol() + ")", symbol_char_offset) + " diff: " + native_balance_diff + "\n"); + } else { + sb.append(StringsUtils.cutAndPadStringToN(chain + " balance", native_name_offset) + StringsUtils.cutAndPadStringToN(" (" + NumUtils.round(native_balance.getBalanceInALGO(),2) + " " + chainInfo.getNativeCurrency().getSymbol() + ")", symbol_char_offset) + "\n"); + } + + // Handle cases where new chain activity is noted + if (null == chain_portfolio_ref) chain_portfolio_ref = new AVMChainPortfolio(); + if (null == chain_portfolio_diff) chain_portfolio_diff = new AVMChainPortfolioDiff(); + + // Store our diff + chain_portfolio_diff.setAccount_address(chain_portfolio.getAccount_address()); + chain_portfolio_diff.setChain(chain.toString()); + + AVMAccountBalance native_balance_ref = null; + if (null == chain_portfolio_ref.getNativeBalance()) { + native_balance_ref = new AVMAccountBalance(0L, 0.0d, chainInfo.getNativeCurrency(), true); + } else { + native_balance_ref = chain_portfolio_ref.getNativeBalance(); + } + + Long native_balance_diff_uAlgo = native_balance.getBalanceInMicroAlgo() - native_balance_ref.getBalanceInMicroAlgo(); + Double native_balance_diff_in_ALGO = Double.parseDouble(native_balance_diff_uAlgo.toString())/1000000d; + chain_portfolio_diff.setNativeBalance(new AVMAccountBalance(native_balance_diff_uAlgo, native_balance_diff_in_ALGO, chainInfo.getNativeCurrency(), false)); + + } else { + sb.append(StringsUtils.cutAndPadStringToN(chain + " balance", native_name_offset) + StringsUtils.cutAndPadStringToN(" (" + NumUtils.round(native_balance.getBalanceInALGO(),2) + " " + chainInfo.getNativeCurrency().getSymbol() + ")", symbol_char_offset) + "\n"); + } + } else { + sb.append(StringsUtils.cutAndPadStringToN(chain + " balance", native_name_offset) + StringsUtils.cutAndPadStringToN(" (" + NumUtils.round(native_balance.getBalanceInALGO(),2) + " " + chainInfo.getNativeCurrency().getSymbol() + ")", symbol_char_offset) + "\n"); + } + sb.append(StringsUtils.cutAndPadStringToN(" - txCount: " + chain_portfolio.getTxCount(), 20) + "\n"); + sb.append(breakline + "\n"); + + /** + * ASA tokens + */ + StringBuffer sb_asa = new StringBuffer(); + int asa_name_offset = 14; // LP names need this .. + int asa_fullname_offset = 31; // for them LP pools .. + int asa_id_offset = 17; + + for (String asa_token_id_STR: chain_portfolio.getTokens().keySet()) { + + Long asa_token_id = null; + try { + asa_token_id = Long.parseLong(asa_token_id_STR); + } catch (Exception e) { + LOGGER.error("ASA id must be a numeric value. Current string: " + asa_token_id_STR); + SystemUtils.halt(); + } + + AVMAccountBalance token_balance = chain_portfolio.getTokens().get(asa_token_id.toString()); + if (ref_portfolio_exists) { + BigDecimal token_balance_refBD = null; + if (null == chain_portfolio_ref) { + token_balance_refBD = new BigDecimal(0); + } else { + AVMAccountBalance token_balance_ref = chain_portfolio_ref.getTokens().get(asa_token_id.toString()); + if (token_balance_ref == null) { + token_balance_refBD = new BigDecimal(0); + } else { + token_balance_refBD = new BigDecimal(token_balance_ref.getBalanceInALGO()); + } + } + + BigDecimal token_balance_BD = null; + token_balance_BD = new BigDecimal(token_balance.getBalanceInALGO()); + + BigDecimal token_balance_diff = token_balance_BD.subtract(token_balance_refBD).setScale(2, RoundingMode.HALF_UP); + if (token_balance_diff.compareTo(BigDecimal.valueOf(minValueToTrack)) > 0) { + sb_asa.append(" * [ASA] " + StringsUtils.cutAndPadStringToN(token_balance.getCurrency().getSymbol(), asa_name_offset) + StringsUtils.cutAndPadStringToN("ID: " + asa_token_id.toString(), asa_id_offset) + StringsUtils.cutAndPadStringToN(" [ " + token_balance.getCurrency().getName(), asa_fullname_offset) + "] " + StringsUtils.cutAndPadStringToN(" (" + NumUtils.round(token_balance.getBalanceInALGO(), 2) + ")", symbol_char_offset) + " diff: +" + token_balance_diff + "\n"); + + // Handle cases where new chain activity is noted + if (null == chain_portfolio_ref) chain_portfolio_ref = new AVMChainPortfolio(); + if (null == chain_portfolio_diff) chain_portfolio_diff = new AVMChainPortfolioDiff(); + + // Store our diff + chain_portfolio_diff.setAccount_address(chain_portfolio.getAccount_address()); + chain_portfolio_diff.setChain(chain.toString()); + + AVMAccountBalance token_balance_ref = null; + if (null == chain_portfolio_ref.getTokens().get(asa_token_id.toString())) { + token_balance_ref = new AVMAccountBalance(0L, 0d, chainInfo.getNativeCurrency(), true); + } else { + token_balance_ref = chain_portfolio_ref.getTokens().get(asa_token_id.toString()); + } + + Long token_balance_diff_uAlgo = token_balance.getBalanceInMicroAlgo() - token_balance_ref.getBalanceInMicroAlgo(); + Double token_balance_diff_in_ALGO = Double.parseDouble(token_balance_diff_uAlgo + "") / 100000d; + + HashMap asa_tokens_diff = chain_portfolio_diff.getAsatokens(); + + asa_tokens_diff.put(asa_token_id, new AVMAccountBalance(token_balance_diff_uAlgo, token_balance_diff_in_ALGO, new AVMCurrency(token_balance.getCurrency().getName(), token_balance.getCurrency().getSymbol(), token_balance.getCurrency().getDecimal()), false)); + chain_portfolio_diff.setAsatokens(asa_tokens_diff); + + } else if (token_balance_diff.compareTo(BigDecimal.valueOf(minValueToTrack)) < 0) { + if (token_balance_diff.toString().startsWith("-")) { + sb_asa.append(" * [ASA] " + StringsUtils.cutAndPadStringToN(token_balance.getCurrency().getSymbol(), asa_name_offset) + StringsUtils.cutAndPadStringToN("ID: " + asa_token_id.toString(), asa_id_offset) + StringsUtils.cutAndPadStringToN(" [ " + token_balance.getCurrency().getName(), asa_fullname_offset) + "] " + StringsUtils.cutAndPadStringToN(" (" + NumUtils.round(token_balance.getBalanceInALGO(), 2) + ")", symbol_char_offset) + " diff: " + token_balance_diff + "\n"); + + // Handle cases where new chain activity is noted + if (null == chain_portfolio_ref) chain_portfolio_ref = new AVMChainPortfolio(); + if (null == chain_portfolio_diff) chain_portfolio_diff = new AVMChainPortfolioDiff(); + + // Store our diff + chain_portfolio_diff.setAccount_address(chain_portfolio.getAccount_address()); + chain_portfolio_diff.setChain(chain.toString()); + + AVMAccountBalance token_balance_ref = null; + if (null == chain_portfolio_ref.getTokens().get(asa_token_id.toString())) { + token_balance_ref = new AVMAccountBalance(0L, 0.0d, chainInfo.getNativeCurrency(), true); + } else { + token_balance_ref = chain_portfolio_ref.getTokens().get(asa_token_id.toString()); + } + + Long token_balance_diff_uAlgo = token_balance.getBalanceInMicroAlgo() - token_balance_ref.getBalanceInMicroAlgo(); + Double token_balance_diff_in_ALGO = Double.parseDouble(token_balance_diff_uAlgo + "") / 1000000d; + + HashMap asa_tokens_diff = chain_portfolio_diff.getAsatokens(); + + asa_tokens_diff.put(asa_token_id, new AVMAccountBalance(token_balance_diff_uAlgo, token_balance_diff_in_ALGO, new AVMCurrency(token_balance.getCurrency().getName(), token_balance.getCurrency().getSymbol(), token_balance.getCurrency().getDecimal()), false)); + chain_portfolio_diff.setAsatokens(asa_tokens_diff); + + } else { + sb_asa.append(" * [ASA] " + StringsUtils.cutAndPadStringToN(token_balance.getCurrency().getSymbol(), asa_name_offset) + StringsUtils.cutAndPadStringToN("ID: " + asa_token_id.toString(), asa_id_offset) + StringsUtils.cutAndPadStringToN(" [ " + token_balance.getCurrency().getName(), asa_fullname_offset) + "] " + StringsUtils.cutAndPadStringToN(" (" + NumUtils.round(token_balance.getBalanceInALGO(), 2) + ")", symbol_char_offset) + "\n"); + } + + } else { + sb_asa.append(" * [ASA] " + StringsUtils.cutAndPadStringToN(token_balance.getCurrency().getSymbol(), asa_name_offset) + StringsUtils.cutAndPadStringToN("ID: " + asa_token_id.toString(), asa_id_offset) + StringsUtils.cutAndPadStringToN(" [ " + token_balance.getCurrency().getName(), asa_fullname_offset) + "] " + StringsUtils.cutAndPadStringToN(" (" + NumUtils.round(token_balance.getBalanceInALGO(), 2) + ")", symbol_char_offset) + "\n"); + } + } else { + sb_asa.append(" * [ASA] " + StringsUtils.cutAndPadStringToN(token_balance.getCurrency().getSymbol(), asa_name_offset) + StringsUtils.cutAndPadStringToN("ID: " + asa_token_id.toString(), asa_id_offset) + StringsUtils.cutAndPadStringToN(" [ " + token_balance.getCurrency().getName(), asa_fullname_offset) + "] " + StringsUtils.cutAndPadStringToN(" (" + NumUtils.round(token_balance.getBalanceInALGO(), 2) + ")", symbol_char_offset) + "\n"); + } + } + if (chain_portfolio.getTokens().keySet().size()>0) sb.append(sb_asa.toString()); + + /** + * NFT (ARC) tokens + */ + StringBuffer sb_nft = new StringBuffer(); + for (String asa_token_id_STR: chain_portfolio.getNfttokens().keySet()) { + Long asa_token_id = null; + try { + asa_token_id = Long.parseLong(asa_token_id_STR); + } catch (Exception e) { + LOGGER.error("ASA id must be a numeric value. Current string: " + asa_token_id_STR); + SystemUtils.halt(); + } + + AVMNftAccountBalance token_balance = chain_portfolio.getNfttokens().get(asa_token_id.toString()); + if (ref_portfolio_exists) { + BigInteger token_balance_refBI = null; + if (null == chain_portfolio_ref) { + token_balance_refBI = new BigInteger("0"); + } else { + AVMNftAccountBalance token_balance_ref = chain_portfolio_ref.getNfttokens().get(asa_token_id.toString()); + if (token_balance_ref == null) { + token_balance_refBI = new BigInteger(""); + } else { + token_balance_refBI = new BigInteger(token_balance_ref.getBalance()); + } + } + + BigInteger token_balance_BI = new BigInteger(token_balance.getBalance()); + BigInteger token_balance_diff = token_balance_BI.subtract(token_balance_refBI); + if (token_balance_diff.compareTo(BigInteger.ZERO) > 0) { + sb_nft.append(" * [ARC] " + StringsUtils.cutAndPadStringToN(token_balance.getSymbol(), asa_name_offset) + StringsUtils.cutAndPadStringToN("ID: " + asa_token_id.toString(), asa_id_offset) + StringsUtils.cutAndPadStringToN(" [ " + token_balance.getName(), asa_fullname_offset) + "] " + StringsUtils.cutAndPadStringToN(" (" + token_balance.getBalance() + ")", symbol_char_offset) + " diff: +" + token_balance_diff + "\n"); + + // Handle cases where new chain activity is noted + if (null == chain_portfolio_ref) chain_portfolio_ref = new AVMChainPortfolio(); + if (null == chain_portfolio_diff) chain_portfolio_diff = new AVMChainPortfolioDiff(); + + // Store our diff + chain_portfolio_diff.setAccount_address(chain_portfolio.getAccount_address()); + chain_portfolio_diff.setChain(chain.toString()); + + /* + AVMNftAccountBalance token_balance_ref = null; + if (null == chain_portfolio_ref.getTokens().get(asa_token_id.toString())) { + token_balance_ref = new AVMNftAccountBalance(token_balance.getBalance(), false, token_balance.getName(), token_balance.getSymbol()); + } else { + token_balance_ref = chain_portfolio_ref.getNfttokens().get(asa_token_id.toString()); + } + */ + + HashMap asa_tokens_diff = chain_portfolio_diff.getArctokens(); + + // Check for official ARC3 token info + ARC3Info tokenInfoARC3 = chainInfo.getNftindex().getArc3s().get(asa_token_id.toString()); + ARC69Info tokenInfoARC69 = chainInfo.getNftindex().getArc69s().get(asa_token_id.toString()); + if (null != tokenInfoARC3) { + asa_tokens_diff.put(asa_token_id, new AVMNftAccountBalance(token_balance_diff.toString(), false, token_balance.getName(), token_balance.getSymbol())); + chain_portfolio_diff.setArctokens(asa_tokens_diff); + } else if (null != tokenInfoARC69) { + asa_tokens_diff.put(asa_token_id, new AVMNftAccountBalance(token_balance_diff.toString(), false, token_balance.getName(), token_balance.getSymbol())); + chain_portfolio_diff.setArctokens(asa_tokens_diff); + } else { + System.out.println("We have no official ARC ASA token info for " + asa_token_id.toString()); + System.exit(1); + } + + } else if (token_balance_diff.compareTo(BigInteger.ZERO) < 0) { + if (token_balance_diff.toString().startsWith("-")) { + sb_nft.append(" * [ARC] " + StringsUtils.cutAndPadStringToN(token_balance.getSymbol(), asa_name_offset) + StringsUtils.cutAndPadStringToN("ID: " + asa_token_id.toString(), asa_id_offset) + StringsUtils.cutAndPadStringToN(" [ " + token_balance.getName(), asa_fullname_offset) + "] " + StringsUtils.cutAndPadStringToN(" (" + token_balance.getBalance() + ")", symbol_char_offset) + " diff: " + token_balance_diff + "\n"); + + // Handle cases where new chain activity is noted + if (null == chain_portfolio_ref) chain_portfolio_ref = new AVMChainPortfolio(); + if (null == chain_portfolio_diff) chain_portfolio_diff = new AVMChainPortfolioDiff(); + + // Store our diff + chain_portfolio_diff.setAccount_address(chain_portfolio.getAccount_address()); + chain_portfolio_diff.setChain(chain.toString()); + + /* + AVMNftAccountBalance token_balance_ref = null; + if (null == chain_portfolio_ref.getTokens().get(asa_token_id.toString())) { + token_balance_ref = new AVMNftAccountBalance(token_balance.getBalance(), false, token_balance.getName(), token_balance.getSymbol()); + } else { + token_balance_ref = chain_portfolio_ref.getNfttokens().get(asa_token_id.toString()); + } + */ + + HashMap asa_tokens_diff = chain_portfolio_diff.getArctokens(); + + // Check for official ARC3 token info + ARC3Info tokenInfoARC3 = chainInfo.getNftindex().getArc3s().get(asa_token_id.toString()); + ARC69Info tokenInfoARC69 = chainInfo.getNftindex().getArc69s().get(asa_token_id.toString()); + if (null != tokenInfoARC3) { + asa_tokens_diff.put(asa_token_id, new AVMNftAccountBalance(token_balance_diff.toString(), false, token_balance.getName(), token_balance.getSymbol())); + chain_portfolio_diff.setArctokens(asa_tokens_diff); + } else if (null != tokenInfoARC69) { + asa_tokens_diff.put(asa_token_id, new AVMNftAccountBalance(token_balance_diff.toString(), false, token_balance.getName(), token_balance.getSymbol())); + chain_portfolio_diff.setArctokens(asa_tokens_diff); + } else { + System.out.println("We have no official ARC ASA token info for " + asa_token_id.toString()); + System.exit(1); + } + + } else { + sb_nft.append(" * [ARC] " + StringsUtils.cutAndPadStringToN(token_balance.getSymbol(), asa_name_offset) + StringsUtils.cutAndPadStringToN("ID: " + asa_token_id.toString(), asa_id_offset) + StringsUtils.cutAndPadStringToN(" [ " + token_balance.getName(), asa_fullname_offset) + "] " + StringsUtils.cutAndPadStringToN(" (" + token_balance.getBalance() + ")", symbol_char_offset) + "\n"); + } + + } else { + sb_nft.append(" * [ARC] " + StringsUtils.cutAndPadStringToN(token_balance.getSymbol(), asa_name_offset) + StringsUtils.cutAndPadStringToN("ID: " + asa_token_id.toString(), asa_id_offset) + StringsUtils.cutAndPadStringToN(" [ " + token_balance.getName(), asa_fullname_offset) + "] " + StringsUtils.cutAndPadStringToN(" (" + token_balance.getBalance() + ")", symbol_char_offset) + "\n"); + } + + } else { + sb_nft.append(" * [ARC] " + StringsUtils.cutAndPadStringToN(token_balance.getSymbol(), asa_name_offset) + StringsUtils.cutAndPadStringToN("ID: " + asa_token_id.toString(), asa_id_offset) + StringsUtils.cutAndPadStringToN(" [ " + token_balance.getName(), asa_fullname_offset) + "] " + StringsUtils.cutAndPadStringToN(" (" + token_balance.getBalance() + ")", symbol_char_offset) + "\n"); + } + } + if (chain_portfolio.getNfttokens().keySet().size()>0) { + if (!chain_portfolio.getTokens().keySet().isEmpty()) sb.append(breaklinemini + "\n"); + sb.append(sb_nft.toString()); + } + + // No ASA + if (chain_portfolio.getTokens().keySet().isEmpty() && chain_portfolio.getNfttokens().keySet().isEmpty()) { + sb.append(" x [no ASA tokens]\n"); + } + + sb.append("\n"); + } + + + // Update our portfolio diff + if (null != chain_portfolio_diff) { + if (null == portfolio_diff) { + portfolio_diff = new AVMPortfolioDiff(); + portfolio_diff.setAccount_address(chain_portfolio_diff.getAccount_address()); + } + HashMap chainportfolio_diff_existing = portfolio_diff.getChainportfolio_diff(); + chainportfolio_diff_existing.put(chain, chain_portfolio_diff); + portfolio_diff.setChainportfolio_diff(chainportfolio_diff_existing); + } + + } + + return new AVMPortfolioDiffResult(sb.toString(), portfolio_diff); + } + + public static String printAVMPortfolioForAddress(AVMBlockChainUltraConnector _ultra_connector, String _account_addr) { + AVMPortfolioDiffResult portfolio_diff = getAVMPortfolioForAddress(_ultra_connector, _account_addr, true, new HashMap(), new HashMap(), false); + return portfolio_diff.getPortfolio_full_str(); + } + + public static String printAVMPortfolioForAddress(AVMBlockChainUltraConnector _ultra_connector, String _account_addr, boolean _checkfornfts, HashMap _token_restriction, HashMap _nft_restriction, boolean _debug) { + AVMPortfolioDiffResult portfolio_diff = getAVMPortfolioForAddress(_ultra_connector, _account_addr, _checkfornfts, _token_restriction, _nft_restriction, _debug); + return portfolio_diff.getPortfolio_full_str(); + } + + public static AVMPortfolioDiffResult getAVMPortfolioForAddress(AVMBlockChainUltraConnector _ultra_connector, String _account_addr, boolean _checkfornfts, HashMap _token_restriction, HashMap _nft_restriction, boolean _debug) { + + /** + * Grab the stored portfolio as ref, create if non existant + */ + LOGGER.info("Will now grab the stored portfolio .."); + AVMPortfolio chainPortfolio_init = AVMUtils.readLatestPortfolioSnapshot(_account_addr, "snapshots"); + if (null == chainPortfolio_init) { + LOGGER.info("Portfolio for wallet did not exist, creating a first snapshot" ); + chainPortfolio_init = AVMUtils.getAVMPortfolioForAccount(_ultra_connector, _account_addr, _checkfornfts, _token_restriction, _nft_restriction, _debug); + LOGGER.info("Flushing portfolio snapshot"); + AVMUtils.updatePortfolioSnapshot(chainPortfolio_init, "snapshots"); + } + + /** + * Retrieve AVM portfolio (including diffs) + */ + LOGGER.info("Getting AVM portfolio .."); + AVMPortfolio chainPortfolio_fin = AVMUtils.getAVMPortfolioForAccount(_ultra_connector, _account_addr, _checkfornfts, _token_restriction, _nft_restriction, _debug); + AVMPortfolioSimple chainPortfolio_simple_init = AVMUtils.createAVMPortfolioSimple(chainPortfolio_init); + AVMPortfolioSimple chainPortfolio_simple_fin = AVMUtils.createAVMPortfolioSimple(chainPortfolio_fin); + AVMPortfolioDiffResult portfolio_diff = AVMUtils.getAVMPortfolioDiff(chainPortfolio_simple_fin, chainPortfolio_simple_init); + AVMUtils.updatePortfolioSnapshot(chainPortfolio_fin, "snapshots"); + + return portfolio_diff; + } + +} diff --git a/src/main/java/crypto/forestfish/utils/ContractMapper.java b/src/main/java/crypto/forestfish/utils/ContractMapper.java new file mode 100644 index 0000000..09e66ae --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/ContractMapper.java @@ -0,0 +1,19 @@ +package crypto.forestfish.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import crypto.forestfish.enums.evm.PolygonERC20Token; + +public class ContractMapper { + + private static final Logger LOGGER = LoggerFactory.getLogger(ContractMapper.class); + + public static String resolveContractAddressFor(PolygonERC20Token token) { + if (PolygonERC20Token.GHST == token) return "0x385eeac5cb85a38a9a07a70c73e0a3271cfb54a7"; + + LOGGER.error("Unable to resolve contract address for token " + token.toString()); + SystemUtils.halt(); + return null; + } +} diff --git a/src/main/java/crypto/forestfish/utils/CryptUtils.java b/src/main/java/crypto/forestfish/utils/CryptUtils.java new file mode 100644 index 0000000..ddf2ce2 --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/CryptUtils.java @@ -0,0 +1,256 @@ +package crypto.forestfish.utils; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.Base64; +import java.util.Formatter; +import java.util.UUID; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.web3j.crypto.Bip32ECKeyPair; +import org.web3j.crypto.Credentials; +import org.web3j.crypto.MnemonicUtils; + +import com.algorand.algosdk.util.CryptoProvider; + +import crypto.forestfish.objects.embedded.BlockchainDetailsGeneric; +import crypto.forestfish.objects.evm.SimpleWallet; + +public class CryptUtils { + + @SuppressWarnings("unused") + private static final Logger LOGGER = LoggerFactory.getLogger(CryptUtils.class); + + public static byte[] digest(byte[] data) throws NoSuchAlgorithmException { + CryptoProvider.setupIfNeeded(); + MessageDigest digest = java.security.MessageDigest.getInstance("SHA256"); + digest.update(Arrays.copyOf(data, data.length)); + return digest.digest(); + } + + public static String calculateSHA512_STR(String str) { + return byteToHex(calculateSHA512(str)); + } + + public static byte[] calculateSHA512(String str) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-512"); + digest.reset(); + digest.update(str.getBytes("UTF-8")); + return digest.digest(); + } catch (NoSuchAlgorithmException e) { + System.out.println("Caught NoSuchAlgorithmException exception: " + Arrays.toString(e.getStackTrace())); + } catch (UnsupportedEncodingException e) { + System.out.println("Caught UnsupportedEncodingException exception: " + Arrays.toString(e.getStackTrace())); + } + return null; + } + + public static String calculateSHA512_256_STR(String str) { + return byteToHex(calculateSHA512_256(str)); + } + + public static byte[] calculateSHA512_256(String str) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-512/256"); + digest.reset(); + digest.update(str.getBytes("UTF-8")); + return digest.digest(); + } catch (NoSuchAlgorithmException e) { + System.out.println("Caught NoSuchAlgorithmException exception: " + Arrays.toString(e.getStackTrace())); + } catch (UnsupportedEncodingException e) { + System.out.println("Caught UnsupportedEncodingException exception: " + Arrays.toString(e.getStackTrace())); + } + return null; + } + + public static String calculateSHA256_STR(String str) { + return byteToHex(calculateSHA256(str)); + } + + public static byte[] calculateSHA256(String str) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + digest.reset(); + digest.update(str.getBytes("UTF-8")); + return digest.digest(); + } catch (NoSuchAlgorithmException e) { + System.out.println("Caught NoSuchAlgorithmException exception: " + Arrays.toString(e.getStackTrace())); + } catch (UnsupportedEncodingException e) { + System.out.println("Caught UnsupportedEncodingException exception: " + Arrays.toString(e.getStackTrace())); + } + return null; + } + + public static String calculateSHA1_STR(String str) { + return byteToHex(calculateSHA1(str)); + } + + public static byte[] calculateSHA1(String str) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-1"); + digest.reset(); + digest.update(str.getBytes("UTF-8")); + return digest.digest(); + } catch (NoSuchAlgorithmException e) { + System.out.println("Caught NoSuchAlgorithmException exception: " + Arrays.toString(e.getStackTrace())); + } catch (UnsupportedEncodingException e) { + System.out.println("Caught UnsupportedEncodingException exception: " + Arrays.toString(e.getStackTrace())); + } + return null; + } + + public static byte[] calculateSHA256FromByteArray(byte[] bytes) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + digest.reset(); + digest.update(bytes); + return digest.digest(); + } catch (NoSuchAlgorithmException e) { + System.out.println("Caught NoSuchAlgorithmException exception: " + Arrays.toString(e.getStackTrace())); + } + return null; + } + + public static String byteToHex(final byte[] hash) { + Formatter formatter = new Formatter(); + for (byte b : hash) { + formatter.format("%02x", b); + } + String result = formatter.toString(); + formatter.close(); + return result; + } + + public static String generateSafe288BITToken() { + SecureRandom random = new SecureRandom(); + byte[] bytes = new byte[36]; // 36 bytes * 8 = 288 bits + random.nextBytes(bytes); + String token = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); + return token; + } + + public static String bytesToHex(byte[] bytes) { + char[] hexChars = new char[bytes.length * 2]; + for (int j = 0; j < bytes.length; j++) { + int v = bytes[j] & 0xFF; + hexChars[j * 2] = HEX_ARRAY[v >>> 4]; + hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; + } + return new String(hexChars); + } + + public static String byteToHex(byte _num) { + char[] hexDigits = new char[2]; + hexDigits[0] = Character.forDigit((_num >> 4) & 0xF, 16); + hexDigits[1] = Character.forDigit((_num & 0xF), 16); + return new String(hexDigits); + } + + private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); + + public static String encodeHexString(byte[] _byteArray) { + StringBuffer hexStringBuffer = new StringBuffer(); + for (int i = 0; i < _byteArray.length; i++) { + hexStringBuffer.append(CryptUtils.byteToHex(_byteArray[i])); + } + return hexStringBuffer.toString(); + } + + public static SimpleWallet generateLowEntropyMnemonic_16_0() { + byte entropy[] = new byte[16]; + Arrays.fill(entropy, (byte) 0); + String mnemonic = MnemonicUtils.generateMnemonic(entropy); + + // derivationPathETH0 + byte[] seed0 = MnemonicUtils.generateSeed(mnemonic, ""); + Bip32ECKeyPair masterKeypair0 = Bip32ECKeyPair.generateKeyPair(seed0); + Bip32ECKeyPair childKeypair0 = Bip32ECKeyPair.deriveKeyPair(masterKeypair0, BlockchainDetailsGeneric.derivationPathETH0); + Credentials cred0 = Credentials.create(childKeypair0); + String privkey0 = "0x" + cred0.getEcKeyPair().getPrivateKey().toString(16); + + return new SimpleWallet(mnemonic, cred0, privkey0); + } + + public static SimpleWallet generateLowEntropyMnemonic_16_1() { + byte entropy[] = new byte[16]; + Arrays.fill(entropy, (byte) 255); + + String mnemonic = MnemonicUtils.generateMnemonic(entropy); + + // derivationPathETH0 + byte[] seed0 = MnemonicUtils.generateSeed(mnemonic, ""); + Bip32ECKeyPair masterKeypair0 = Bip32ECKeyPair.generateKeyPair(seed0); + Bip32ECKeyPair childKeypair0 = Bip32ECKeyPair.deriveKeyPair(masterKeypair0, BlockchainDetailsGeneric.derivationPathETH0); + Credentials cred0 = Credentials.create(childKeypair0); + String privkey0 = "0x" + cred0.getEcKeyPair().getPrivateKey().toString(16); + + return new SimpleWallet(mnemonic, cred0, privkey0); + } + + public static SimpleWallet generateLowEntropyMnemonic_32_0() { + byte entropy[] = new byte[32]; + Arrays.fill(entropy, (byte) 0); + String mnemonic = MnemonicUtils.generateMnemonic(entropy); + + // derivationPathETH0 + byte[] seed0 = MnemonicUtils.generateSeed(mnemonic, ""); + Bip32ECKeyPair masterKeypair0 = Bip32ECKeyPair.generateKeyPair(seed0); + Bip32ECKeyPair childKeypair0 = Bip32ECKeyPair.deriveKeyPair(masterKeypair0, BlockchainDetailsGeneric.derivationPathETH0); + Credentials cred0 = Credentials.create(childKeypair0); + String privkey0 = "0x" + cred0.getEcKeyPair().getPrivateKey().toString(16); + + return new SimpleWallet(mnemonic, cred0, privkey0); + } + + public static SimpleWallet generateLowEntropyMnemonic_32_1() { + byte entropy[] = new byte[32]; + Arrays.fill(entropy, (byte) 255); + + String mnemonic = MnemonicUtils.generateMnemonic(entropy); + + // derivationPathETH0 + byte[] seed0 = MnemonicUtils.generateSeed(mnemonic, ""); + Bip32ECKeyPair masterKeypair0 = Bip32ECKeyPair.generateKeyPair(seed0); + Bip32ECKeyPair childKeypair0 = Bip32ECKeyPair.deriveKeyPair(masterKeypair0, BlockchainDetailsGeneric.derivationPathETH0); + Credentials cred0 = Credentials.create(childKeypair0); + String privkey0 = "0x" + cred0.getEcKeyPair().getPrivateKey().toString(16); + + return new SimpleWallet(mnemonic, cred0, privkey0); + } + + public static int getDecimalIntFromHex(String _hex){ + String digits = "0123456789ABCDEF"; + _hex = _hex.toUpperCase(); + int val = 0; + for (int i = 0; i < _hex.length(); i++) + { + char c = _hex.charAt(i); + int d = digits.indexOf(c); + val = 16*val + d; + } + return val; + } + + private static SecureRandom random = new SecureRandom(); + private static final String ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + public static String generateRandomString() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 54; i++) { + int index = random.nextInt(ALPHABET.length()); + char randomChar = ALPHABET.charAt(index); + sb.append(randomChar); + } + return sb.toString(); + } + + public static String generateRandomStringUUID() { + return UUID.randomUUID().toString(); + } + +} diff --git a/src/main/java/crypto/forestfish/utils/DateUtils.java b/src/main/java/crypto/forestfish/utils/DateUtils.java new file mode 100644 index 0000000..f03da24 --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/DateUtils.java @@ -0,0 +1,30 @@ +package crypto.forestfish.utils; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DateUtils { + + @SuppressWarnings("unused") + private static final Logger LOGGER = LoggerFactory.getLogger(DateUtils.class); + + public static String epochInMilliSecondsToUTC(final long epoch) { + Date date = new Date(epoch); + DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + format.setTimeZone(TimeZone.getTimeZone("UTC")); + return format.format(date); + } + + public static String epochInSecondsToUTC(final long epoch) { + Date date = new Date(epoch*1000L); + DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + format.setTimeZone(TimeZone.getTimeZone("UTC")); + return format.format(date); + } + +} diff --git a/src/main/java/crypto/forestfish/utils/EVMContractUtils.java b/src/main/java/crypto/forestfish/utils/EVMContractUtils.java new file mode 100644 index 0000000..a9489e2 --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/EVMContractUtils.java @@ -0,0 +1,476 @@ +package crypto.forestfish.utils; + +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.web3j.crypto.Credentials; + +import com.esaulpaugh.headlong.abi.Address; +import com.esaulpaugh.headlong.abi.Function; +import com.esaulpaugh.headlong.abi.Tuple; +import com.esaulpaugh.headlong.util.FastHex; + +import crypto.forestfish.objects.embedded.evm.ABI; +import crypto.forestfish.objects.evm.EVMProviderException; +import crypto.forestfish.objects.evm.EVMProviderExceptionActionState; +import crypto.forestfish.objects.evm.connector.EVMBlockChainConnector; +import crypto.forestfish.objects.evm.model.erc721.ERC721ContractInfo; +import crypto.forestfish.objects.evm.model.nft.EVMERC721TokenInfo; + +public class EVMContractUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(EVMContractUtils.class); + + public static ERC721ContractInfo getERC721ContractInfo(EVMBlockChainConnector _connector, String _erc721_contract_address) { + String meth = "getERC721ContractInfo()"; + boolean allInfoOK = false; + ERC721ContractInfo result = new ERC721ContractInfo(); + + int nodeCallAttemptCount = 0; + int requestCount = 0; + while (!allInfoOK && (nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + + // contract sanitycheck + Boolean isContract = EVMUtils.isContract(_erc721_contract_address, _connector); + if (null == isContract) { + LOGGER.error("Unable to determine what is on address " + _erc721_contract_address + " on " + _connector.getChain().name() + ", trying to check if its a smart contract"); + SystemUtils.halt(); + } else if (!isContract) { + LOGGER.info("Address " + _erc721_contract_address + " on " + _connector.getChain().name() + " does not appear to be a smart contract"); + return null; + } + + // ERC721 symbol + String symbol = EVMContractUtils.getStringFromFunctionWithABI("symbol", ABI.abiERC721Token, _erc721_contract_address, _connector); + result.setSymbol(symbol); + + // ERC721 name + String name = EVMContractUtils.getStringFromFunctionWithABI("name", ABI.abiERC721Token, _erc721_contract_address, _connector); + result.setName(name); + + // ERC721 owner + String owner = EVMContractUtils.getAddressFromFunctionWithoutABI("owner", _erc721_contract_address, _connector); + result.setOwner(owner); + + // ERC721 totalSupply + BigInteger totalSupply = EVMContractUtils.getBigIntegerFromFunctionWithABI("totalSupply", ABI.abiERC721Token, _erc721_contract_address, _connector); + result.setTotalSupply(totalSupply.toString()); + + // baseURI + String baseURI = EVMContractUtils.getStringFromFunctionWithoutABI("baseURI", _erc721_contract_address, _connector); + result.setBaseuri(baseURI); + + // contract address + result.setContractAddress(_erc721_contract_address); + + return result; + + } catch (Exception ex) { + LOGGER.warn("Unable to grab ERC721ContractInfo for " + _erc721_contract_address + ", nodeCallAttemptCount=" + nodeCallAttemptCount); + + System.out.println("x: " + ex.getMessage()); + System.exit(1); + SystemUtils.sleepInSeconds(1); + + // RPC call exceptions (readonly) + EVMProviderException evmE = EVMUtils.analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmAS = EVMUtils.actAndGetStateEVMProviderException(evmE, _connector, false, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmAS.isNewEVMBlockChainConnector()) _connector = evmAS.getConnector(); + } + nodeCallAttemptCount++; + } + + return null; + } + + + private static String getStringFromFunctionWithABI(String funcName, String abiJSON, String _erc721_contract_address, EVMBlockChainConnector _connector) { + // input + String function_args_hex1 = EVMContractUtils.genFunctionArgsForEmptyArgsUsingABIJSON(funcName, abiJSON); + + // execute + String reply_rawstr1 = EVMUtils.makeUnsignedRequest(function_args_hex1, _erc721_contract_address, _connector, _connector.getTxRetryThreshold(), _connector.getConfirmTimeInSecondsBeforeRetry(), _connector.isHaltOnFailedCall()); + reply_rawstr1 = reply_rawstr1.replaceFirst("0x", ""); + LOGGER.debug("reply_rawstr: " + reply_rawstr1); + + // output + String output = EVMContractUtils.getStringFromFunctionRespWithABI(funcName, abiJSON, reply_rawstr1); + return output; + } + + public static String getStringFromFunctionWithoutABI(String _funcName, String _contract_address, EVMBlockChainConnector _connector) { + + String generic_string_funcJSON = "{\"constant\":true,\"inputs\":[],\"name\":\"" + _funcName + "\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}"; + + // input + String function_args_hex1 = EVMContractUtils.genFunctionArgsForEmptyArgsUsingFunctionJSON(_funcName, generic_string_funcJSON); + + // sanity check + if (!EVMUtils.isContract(_contract_address, _connector)) { + LOGGER.error("Specified contract address " + _contract_address + " is not a contract"); + SystemUtils.halt(); + } + + // execute + String reply_rawstr1 = EVMUtils.makeUnsignedRequest(function_args_hex1, _contract_address, _connector, _connector.getTxRetryThreshold(), _connector.getConfirmTimeInSecondsBeforeRetry(), _connector.isHaltOnFailedCall()); + if (null == reply_rawstr1) { + LOGGER.error("Got a null reply (failed call) when making unsigned request to contract address " + _contract_address); + SystemUtils.halt(); + } + reply_rawstr1 = reply_rawstr1.replaceFirst("0x", ""); + if ("".equals(reply_rawstr1)) { + LOGGER.error("Got a blank reply when making unsigned request to contract address " + _contract_address); + SystemUtils.halt(); + } + LOGGER.debug("function: " + _funcName + " reply_rawstr: " + reply_rawstr1); + + // output + String output = EVMContractUtils.getStringFromFunctionResp(generic_string_funcJSON, reply_rawstr1); + return output; + } + + public static String setStringFromFunctionWithoutABI(String _arg1, String _funcName, String _contract_address, EVMBlockChainConnector _connector, Credentials _creds) { + + String generic_string_abiJSON = "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"" + _funcName + "\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]"; + + // input + String function_args_hex1 = EVMContractUtils.genFunctionArgsForSingleStringArg(_arg1, _funcName, generic_string_abiJSON); + LOGGER.debug("function_args_hex1: " + function_args_hex1); + + // execute + String txHASH = EVMUtils.makeSignedRequest(function_args_hex1, _connector.getTxRetryThreshold(), _connector.getConfirmTimeInSecondsBeforeRetry(), _connector, _creds, _contract_address, _connector.getChaininfo().getFallbackGasLimitInUnits(), _connector.isHaltOnFailedCall()); + LOGGER.info("txHASH: " + txHASH); + + return txHASH; + } + + public static String setStringFromFunctionWithoutABI(String _arg1, String _funcName, String _contract_address, EVMBlockChainConnector _connector, Credentials _creds, String gasLimitInUnits) { + + String generic_string_abiJSON = "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"" + _funcName + "\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]"; + + // input + String function_args_hex1 = EVMContractUtils.genFunctionArgsForSingleStringArg(_arg1, _funcName, generic_string_abiJSON); + LOGGER.debug("function_args_hex1: " + function_args_hex1); + + // execute + String txHASH = EVMUtils.makeSignedRequest(function_args_hex1, _connector.getTxRetryThreshold(), _connector.getConfirmTimeInSecondsBeforeRetry(), _connector, _creds, _contract_address, gasLimitInUnits, _connector.isHaltOnFailedCall()); + LOGGER.info("txHASH: " + txHASH); + + return txHASH; + } + + public static String getAddressFromFunctionWithoutABI(String _funcName, String _contract_address, EVMBlockChainConnector _connector) { + + String generic_string_funcJSON = "{\"constant\":true,\"inputs\":[],\"name\":\"" + _funcName + "\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}"; + + // input + String function_args_hex1 = EVMContractUtils.genFunctionArgsForEmptyArgsUsingFunctionJSON(_funcName, generic_string_funcJSON); + + // execute + String reply_rawstr1 = EVMUtils.makeUnsignedRequest(function_args_hex1, _contract_address, _connector, _connector.getTxRetryThreshold(), _connector.getConfirmTimeInSecondsBeforeRetry(), _connector.isHaltOnFailedCall()); + if (null == reply_rawstr1) return null; + reply_rawstr1 = reply_rawstr1.replaceFirst("0x", ""); + LOGGER.debug("function: " + _funcName + " reply_rawstr: " + reply_rawstr1); + + // output + String output = EVMContractUtils.getAddressFromFunctionResp(generic_string_funcJSON, reply_rawstr1); + return output; + } + + public static BigInteger getBigIntegerFromFunctionWithABI(String _funcName, String _abi, String _erc721_contract_address, EVMBlockChainConnector _connector) { + // input + String function_args_hex1 = EVMContractUtils.genFunctionArgsForEmptyArgsUsingABIJSON(_funcName, _abi); + + // execute + String reply_rawstr1 = EVMUtils.makeUnsignedRequest(function_args_hex1, _erc721_contract_address, _connector, _connector.getTxRetryThreshold(), _connector.getConfirmTimeInSecondsBeforeRetry(), _connector.isHaltOnFailedCall()); + reply_rawstr1 = reply_rawstr1.replaceFirst("0x", ""); + LOGGER.debug("reply_rawstr: " + reply_rawstr1); + + // output + BigInteger output = EVMContractUtils.getBigIntegerFromFunctionResp(_funcName, ABI.abiERC721Token, reply_rawstr1); + return output; + } + + + public static void printAllFunctionsOfABI(String abiJSON) { + HashMap abiFunctions = JSONUtils.getFunctionNamesOfABIJSON(abiJSON); + int function_count = 0; + for (String function: abiFunctions.keySet()) { + System.out.println("function #" + function_count + ": " + function); + function_count++; + } + } + + + private static String getStringFromFunctionRespWithABI(String _funcName, String _abiJSON, String _response_hex) { + + // sanity check + HashMap abiFunctions = JSONUtils.getFunctionNamesOfABIJSON(_abiJSON); + if (null == abiFunctions.get(_funcName)) { + LOGGER.error("No function named " + _funcName + " for ABI abiERC721Metadata"); + SystemUtils.halt(); + } + + // parse ABI + String funcJSON = JSONUtils.getFunctionJSONUsingABI(_abiJSON, _funcName); + + // grab the string response + return getStringFromFunctionResp(funcJSON, _response_hex); + } + + public static String getStringFromFunctionResp(String _funcJSON, String _response_hex) { + + // parse function JSON + Function func = Function.fromJson(_funcJSON); + + // grab the string + String result = ""; + if ((func.getOutputs().size() == 1)) { + + // single output + String output_type = func.getOutputs().get(0).getCanonicalType(); + if ("string".equals(output_type)) { + LOGGER.debug("_response_hex: " + _response_hex); + Tuple decoded_output = func.decodeReturn(FastHex.decode(_response_hex)); + String decoded_single_str = decoded_output.get(0); + LOGGER.debug("decoded_output (string): " + decoded_single_str); + result = decoded_single_str; + } else { + LOGGER.error("Not sure how to handle this function output, its not a single string"); + LOGGER.error("nr outputs: " + func.getOutputs().size()); + System.out.println(JSONUtils.prettyPrint(_funcJSON)); + SystemUtils.halt(); + } + + } else { + LOGGER.error("Not sure how to handle this function output, its not a single string"); + LOGGER.error("nr outputs: " + func.getOutputs().size()); + System.out.println(JSONUtils.prettyPrint(_funcJSON)); + SystemUtils.halt(); + } + + return result; + } + + public static String getAddressFromFunctionResp(String _funcJSON, String _response_hex) { + + // parse function JSON + Function func = Function.fromJson(_funcJSON); + + // grab the string + String result = ""; + if ((func.getOutputs().size() == 1)) { + + // single output + String output_type = func.getOutputs().get(0).getCanonicalType(); + if ("address".equals(output_type)) { + Tuple decoded_output = func.decodeReturn(FastHex.decode(_response_hex)); + Address decoded_single_address = decoded_output.get(0); + LOGGER.info("decoded_output (address): " + decoded_single_address); + result = decoded_single_address.toString(); + } else { + LOGGER.error("Not sure how to handle this function output, its not a single string"); + LOGGER.error("nr outputs: " + func.getOutputs().size()); + System.out.println(JSONUtils.prettyPrint(_funcJSON)); + SystemUtils.halt(); + } + + } else { + LOGGER.error("Not sure how to handle this function output, its not a single string"); + LOGGER.error("nr outputs: " + func.getOutputs().size()); + System.out.println(JSONUtils.prettyPrint(_funcJSON)); + SystemUtils.halt(); + } + + return result; + } + + public static BigInteger getBigIntegerFromFunctionResp(String funcName, String abiJSON, String response_hex) { + + // sanity check + HashMap abiFunctions = JSONUtils.getFunctionNamesOfABIJSON(abiJSON); + if (null == abiFunctions.get(funcName)) { + LOGGER.error("No function named " + funcName + " for ABI abiERC721Metadata"); + SystemUtils.halt(); + } + + // parse ABI + String funcJSON = JSONUtils.getFunctionJSONUsingABI(abiJSON, funcName); + Function func = Function.fromJson(funcJSON); + + // grab the string + if ((func.getOutputs().size() == 1)) { + + // single output + String output_type = func.getOutputs().get(0).getCanonicalType(); + if ("uint256".equals(output_type)) { + Tuple decoded_output = func.decodeReturn(FastHex.decode(response_hex)); + BigInteger decoded_single = decoded_output.get(0); + return decoded_single; + } else { + LOGGER.error("Not sure how to handle this function output, its not a single uint256"); + LOGGER.error("nr outputs: " + func.getOutputs().size()); + System.out.println(JSONUtils.prettyPrint(funcJSON)); + SystemUtils.halt(); + } + + } else { + LOGGER.error("Not sure how to handle this function output, its not a single string"); + LOGGER.error("nr outputs: " + func.getOutputs().size()); + System.out.println(JSONUtils.prettyPrint(funcJSON)); + SystemUtils.halt(); + } + + return null; + } + + private static String genFunctionArgsForEmptyArgsUsingABIJSON(String funcName, String abiJSON) { + + // sanity check + HashMap abiFunctions = JSONUtils.getFunctionNamesOfABIJSON(abiJSON); + if (null == abiFunctions.get(funcName)) { + LOGGER.error("No function named " + funcName + " for provided ABI"); + System.out.println("ABI JSON: " + abiJSON); + SystemUtils.halt(); + } + + // parse ABI + String funcJSON = JSONUtils.getFunctionJSONUsingABI(abiJSON, funcName); + + return genFunctionArgsForEmptyArgsUsingFunctionJSON(funcName, funcJSON); + + } + + public static String genFunctionArgsForEmptyArgsUsingFunctionJSON(String _funcName, String _funcJSON) { + + // parse ABI + Function func = Function.fromJson(_funcJSON); + + // generate the argument + String function_args_hex = ""; + if (func.getInputs().isEmpty()) { + + // no input + Tuple function_args = Tuple.EMPTY; + ByteBuffer bb = func.encodeCall(function_args); + function_args_hex = "0x" + CryptUtils.encodeHexString(bb.array()); + + } else { + LOGGER.error("This contract input function requires input"); + LOGGER.error("nr inputs: " + func.getInputs().size()); + System.out.println(JSONUtils.prettyPrint(_funcJSON)); + SystemUtils.halt(); + } + + return function_args_hex; + } + + public static String genFunctionArgsForSingleStringArg(String _arg, String _funcName, String _abiJSON) { + + // sanity check + HashMap abiFunctions = JSONUtils.getFunctionNamesOfABIJSON(_abiJSON); + if (null == abiFunctions.get(_funcName)) { + LOGGER.error("No function named " + _funcName + " for provided ABI"); + System.out.println("ABI JSON: " + _abiJSON); + SystemUtils.halt(); + } + + // parse ABI + String funcJSON = JSONUtils.getFunctionJSONUsingABI(_abiJSON, _funcName); + Function func = Function.fromJson(funcJSON); + + // generate the argument + String function_args_hex = ""; + if (func.getInputs().isEmpty()) { + LOGGER.error("genFunctionArgsForSingleStringArg() requires an ABI with 1 string argument as input"); + SystemUtils.halt(); + } else if ((func.getInputs().size() == 1)) { + // single string input + String input_type = func.getInputs().get(0).getCanonicalType(); + if ("string".equals(input_type)) { + // 1 input string + Tuple function_args = Tuple.singleton(_arg); + ByteBuffer bb = func.encodeCall(function_args); + function_args_hex = "0x" + CryptUtils.encodeHexString(bb.array()); + } else { + LOGGER.error("Not sure how to handle this function input, its not a single string"); + LOGGER.error("nr inputs: " + func.getInputs().size()); + System.out.println(JSONUtils.prettyPrint(funcJSON)); + SystemUtils.halt(); + } + } else { + LOGGER.error("This contract input function requires input"); + LOGGER.error("nr inputs: " + func.getInputs().size()); + System.out.println(JSONUtils.prettyPrint(funcJSON)); + SystemUtils.halt(); + } + + return function_args_hex; + } + + + public static ArrayList getERC721TokenIdsOwnedBy(EVMBlockChainConnector _connector, String account_address, EVMERC721TokenInfo tokenInfo, boolean _haltOnFailedCall) { + String meth = "getERC721TokenIdsOwnedBy()"; + ArrayList tokenIds = new ArrayList(); + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + + // Own more than 10k nfts from this contract? + for (int i=0; i<=10000; i++) { + + // --------------------------------------------------------------------------------------------------- + String funcName = "tokenOfOwnerByIndex"; + String abiERC721Enumerable = ABI.abiERC721Enumerable; + String funcJSON = JSONUtils.getFunctionJSONUsingABI(abiERC721Enumerable, funcName); + if ("".equals(funcJSON)) LOGGER.error("Unable to find function " + funcName + "in ABI JSON"); + com.esaulpaugh.headlong.abi.Function func = com.esaulpaugh.headlong.abi.Function.fromJson(funcJSON); + com.esaulpaugh.headlong.abi.Address abi_account_address = com.esaulpaugh.headlong.abi.Address.wrap(com.esaulpaugh.headlong.abi.Address.toChecksumAddress(account_address)); + Tuple args = Tuple.of(abi_account_address, new BigInteger(Integer.toString(i))); + ByteBuffer bb = func.encodeCall(args); + String hexData = CryptUtils.encodeHexString(bb.array()); + // --------------------------------------------------------------------------------------------------- + + String response = EVMUtils.makeUnsignedRequest(hexData, tokenInfo.getContractAddress(), _connector, 10, 20, _haltOnFailedCall); + if (null != response) { + Integer tokenID = CryptUtils.getDecimalIntFromHex(response); + tokenIds.add(tokenID); + } else { + return tokenIds; + } + + } + return tokenIds; + } catch (Exception ex) { + if (ex.getMessage().equals("Empty value (0x) returned from contract")) { + if (tokenIds.isEmpty()) { + LOGGER.warn("Found no tokenids owned by specified address"); + } + return tokenIds; + } else { + // RPC call exceptions (readonly) + EVMProviderException evmE = EVMUtils.analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmAS = EVMUtils.actAndGetStateEVMProviderException(evmE, _connector, false, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmAS.isNewEVMBlockChainConnector()) _connector = evmAS.getConnector(); + } + } + } + LOGGER.error(meth + ": Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + +} diff --git a/src/main/java/crypto/forestfish/utils/EVMUtils.java b/src/main/java/crypto/forestfish/utils/EVMUtils.java new file mode 100644 index 0000000..4dbf4b7 --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/EVMUtils.java @@ -0,0 +1,3121 @@ +package crypto.forestfish.utils; + +import java.io.File; +import java.io.IOException; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; +import java.math.RoundingMode; +import java.nio.charset.StandardCharsets; +import java.security.InvalidParameterException; +import java.security.SecureRandom; +import java.security.SignatureException; +import java.util.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.web3j.abi.FunctionEncoder; +import org.web3j.abi.datatypes.Address; +import org.web3j.abi.datatypes.Bool; +import org.web3j.abi.datatypes.Function; +import org.web3j.abi.datatypes.generated.Uint256; +import org.web3j.contracts.eip20.generated.ERC20; +import org.web3j.contracts.eip721.generated.ERC721; +import org.web3j.crypto.Bip32ECKeyPair; +import org.web3j.crypto.Credentials; +import org.web3j.crypto.Keys; +import org.web3j.crypto.MnemonicUtils; +import org.web3j.crypto.RawTransaction; +import org.web3j.crypto.Sign; +import org.web3j.crypto.Sign.SignatureData; +import org.web3j.crypto.TransactionEncoder; +import org.web3j.protocol.Web3j; +import org.web3j.protocol.core.DefaultBlockParameterName; +import org.web3j.protocol.core.methods.request.Transaction; +import org.web3j.protocol.core.methods.response.EthBlockNumber; +import org.web3j.protocol.core.methods.response.EthChainId; +import org.web3j.protocol.core.methods.response.EthGasPrice; +import org.web3j.protocol.core.methods.response.EthGetBalance; +import org.web3j.protocol.core.methods.response.EthGetCode; +import org.web3j.protocol.core.methods.response.EthGetTransactionCount; +import org.web3j.protocol.core.methods.response.EthGetTransactionReceipt; +import org.web3j.protocol.core.methods.response.EthSendTransaction; +import org.web3j.protocol.core.methods.response.TransactionReceipt; +import org.web3j.protocol.core.methods.response.Web3ClientVersion; +import org.web3j.protocol.exceptions.TransactionException; +import org.web3j.protocol.core.DefaultBlockParameter; +import org.web3j.tx.*; +import org.web3j.tx.gas.DefaultGasProvider; +import org.web3j.tx.gas.StaticGasProvider; +import org.web3j.utils.Convert; +import org.web3j.utils.Numeric; +import org.web3j.utils.Convert.Unit; + +import crypto.forestfish.enums.AccountOrigin; +import crypto.forestfish.enums.BlockchainType; +import crypto.forestfish.enums.ExceptionType; +import crypto.forestfish.enums.TokenCategory; +import crypto.forestfish.enums.evm.EVMChain; +import crypto.forestfish.enums.evm.EVMPriceMechanism; +import crypto.forestfish.objects.evm.connector.EVMBlockChainConnector; +import crypto.forestfish.objects.evm.connector.EVMBlockChainUltraConnector; +import crypto.forestfish.objects.evm.model.chain.EVMChainIndex; +import crypto.forestfish.objects.evm.model.chain.EVMChainInfo; +import crypto.forestfish.objects.evm.model.chain.EVMCurrency; +import crypto.forestfish.objects.evm.model.erc20.ERC20TokenIndex; +import crypto.forestfish.objects.evm.model.erc20.EVMERC20TokenInfo; +import crypto.forestfish.objects.evm.model.nft.EVMERC721TokenInfo; +import crypto.forestfish.objects.evm.model.nft.EVMNFTIndex; +import crypto.forestfish.objects.evm.EVMLocalWallet; +import crypto.forestfish.objects.evm.EVMNativeValue; +import crypto.forestfish.objects.evm.EVMNftAccountBalance; +import crypto.forestfish.objects.evm.EVMPortfolio; +import crypto.forestfish.objects.evm.EVMPortfolioDiff; +import crypto.forestfish.objects.evm.EVMPortfolioSimple; +import crypto.forestfish.objects.evm.EVMProviderExceptionActionState; +import crypto.forestfish.objects.evm.EVMProviderException; +import crypto.forestfish.objects.evm.EVMTransactionExceptionEvent; +import crypto.forestfish.objects.evm.NonceCheckStatus; +import crypto.forestfish.objects.evm.PendingTxStatus; +import crypto.forestfish.objects.evm.EVMPortfolioDiffResult; +import crypto.forestfish.objects.embedded.BlockchainDetailsGeneric; +import crypto.forestfish.objects.embedded.evm.BlockchainDetailsEVM; +import crypto.forestfish.objects.evm.EVMAccountBalance; +import crypto.forestfish.objects.evm.EVMChainPortfolio; +import crypto.forestfish.objects.evm.EVMChainPortfolioDiff; + +public class EVMUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(EVMUtils.class); + + public static String SIGN_PREFIX = "\u0019Ethereum Signed Message:\n32"; + public static String signSTR(EVMLocalWallet localWallet, String message) { + return sign(localWallet.getCredentials(), message); + } + + public static String sign(Credentials cred, String message) { + byte[] hash = message.getBytes(StandardCharsets.UTF_8); + Sign.SignatureData signature = Sign.signPrefixedMessage(hash, cred.getEcKeyPair()); + String r = Numeric.toHexString(signature.getR()); + String s = Numeric.toHexString(signature.getS()); + String v = Numeric.toHexString(signature.getV()).replace("0x", ""); + return new StringBuilder(r) + .append(s) + .append(v) + .toString(); + } + + public static String generate12wordMnemonic() { + byte[] initialEntropy = new byte[16]; + SecureRandom SECURE_RANDOM = new SecureRandom(); + SECURE_RANDOM.nextBytes(initialEntropy); + String mnemonic = MnemonicUtils.generateMnemonic(initialEntropy); + return mnemonic; + } + + public static String generate24wordMnemonic() { + byte[] initialEntropy = new byte[32]; + SecureRandom SECURE_RANDOM = new SecureRandom(); + SECURE_RANDOM.nextBytes(initialEntropy); + String mnemonic = MnemonicUtils.generateMnemonic(initialEntropy); + return mnemonic; + } + + public static Long getLatestBlockNumberFromNodeAsHealthCheck(EVMChain chain, String nodeURL, Web3j web3j) { + String meth = "getLatestBlockNumberFromNodeAsHealthCheck()"; + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<2) && (requestCount<3)) { // early exit + requestCount++; + try { + EthBlockNumber result = web3j.ethBlockNumber().sendAsync().get(); + return result.getBlockNumber().longValue(); + } catch (Exception ex) { + // RPC call exceptions (readonly), without connector + EVMProviderException evmE = analyzeProviderException(chain, nodeURL, ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmE.isSleepBeforeRetry()) { + SystemUtils.sleepInSeconds(evmE.getSleepTimeInSecondsRecommended()); + } else { + SystemUtils.sleepInSeconds(1); // Always sleep for 1 sec + } + if (evmE.getExceptionType() == ExceptionType.FATAL) SystemUtils.halt(); + if (evmE.isSwitchNode()) return null; + LOGGER.warn("requestCount: " + requestCount + " nodeCallAttemptCount: " + nodeCallAttemptCount + " get latest block call to nodeURL " + nodeURL); + } + } + return null; // intentional null response on fail here + } + + public static String getNodeClientVersion(EVMBlockChainConnector _connector) { + String meth = "getNodeClientVersion"; + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + Web3ClientVersion clientVersion = _connector.getProvider_instance().web3ClientVersion().sendAsync().get(); + String version = clientVersion.getWeb3ClientVersion(); + if (null != version) { + return version + .replace("\n", "") + .replace("\r", ""); + } + return "-"; + } catch (Exception ex) { + // RPC call exceptions (readonly) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmAS = actAndGetStateEVMProviderException(evmE, _connector, false, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmAS.isNewEVMBlockChainConnector()) _connector = evmAS.getConnector(); + } + } + return "-"; + } + + public static void printNodeClientVersion(EVMBlockChainConnector connector) { + System.out.println("Client version for nodeURL " + connector.getCurrent_blockexplorerURL() + ": " + getNodeClientVersion(connector)); + } + + public static EVMAccountBalance getWalletBalanceNativeCurrency(EVMBlockChainConnector _connector, EVMLocalWallet _localWallet) { + String meth = "getWalletBalanceNativeCurrency()"; + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + return getAccountNativeBalance(_connector, _localWallet.getAddress()); + } catch (Exception ex) { + // RPC call exceptions (readonly) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmAS = actAndGetStateEVMProviderException(evmE, _connector, false, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmAS.isNewEVMBlockChainConnector()) _connector = evmAS.getConnector(); + } + } + return null; + } + + public static boolean isContractAddress(EVMBlockChainConnector _connector, String _address) { + String meth = "isContractAddress()"; + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + EthGetCode ethGetCode = _connector.getProvider_instance().ethGetCode(_address, DefaultBlockParameterName.LATEST).send(); + String s=ethGetCode.getCode(); + System.out.println("Bytecode length of address " + _address + ": " + s.length()); + if (s.length()>5) { + return true; + } else { + return false; + } + } catch (Exception ex) { + // RPC call exceptions (readonly) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmAS = actAndGetStateEVMProviderException(evmE, _connector, false, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmAS.isNewEVMBlockChainConnector()) _connector = evmAS.getConnector(); + } + } + return false; + } + + public static EVMAccountBalance getAccountNativeBalance(EVMBlockChainConnector _connector, String _address) { + String meth = "getAccountNativeBalance()"; + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + EthGetBalance ethGetBalance = _connector.getProvider_instance().ethGetBalance(_address, DefaultBlockParameterName.PENDING).send(); + BigInteger balanceWEI = ethGetBalance.getBalance(); + BigDecimal balanceETH = Convert.fromWei(ethGetBalance.getBalance().toString(), Unit.ETHER); + BigDecimal balanceInGWEI = Convert.fromWei(ethGetBalance.getBalance().toString(), Unit.GWEI); + boolean isEmpty = true; + if ((null != balanceWEI) && balanceWEI.compareTo(BigInteger.ZERO) > 0) isEmpty = false; + BigDecimal scaledBalanceInGWEI = balanceInGWEI.setScale(0, RoundingMode.HALF_UP); + return new EVMAccountBalance(balanceWEI.toString(), scaledBalanceInGWEI.toString(), balanceETH.round(new MathContext(7)).toString(), _connector.getChaininfo().getNativeCurrency(), isEmpty); + } catch (Exception ex) { + // RPC call exceptions (readonly) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmAS = actAndGetStateEVMProviderException(evmE, _connector, false, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmAS.isNewEVMBlockChainConnector()) _connector = evmAS.getConnector(); + } + } + LOGGER.error(meth + ": Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static void printWalletBalance(EVMBlockChainConnector connector, EVMLocalWallet localWallet) { + EVMAccountBalance evmwb = getWalletBalanceNativeCurrency(connector, localWallet); + if (null != evmwb) { + System.out.println(" * wallet address " + localWallet.getCredentials().getAddress() + " balance " + evmwb.getBalanceInETH() + " " + connector.getChaininfo().getNativeCurrency().getSymbol() + " [" + evmwb.getBalanceInWEI() + " wei]"); + } + } + + public static EVMAccountBalance getAccountBalanceForERC20Token(EVMBlockChainConnector connector, String account_address, String tokenName) { + EVMERC20TokenInfo tokenInfo = connector.getChaininfo().getTokenIndex().getTokens().get(tokenName); + return getAccountBalanceForERC20Token(connector, account_address, tokenInfo); + } + + public static EVMAccountBalance getAccountBalanceForERC20Token(EVMBlockChainConnector _connector, String _account_address, EVMERC20TokenInfo _tokenInfo) { + String meth = "getAccountBalanceForERC20Token() (chain: " + _connector.getChain().name() + ", token: " + _tokenInfo.getSymbol() + ")"; + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + // Readonly ERC20 + TransactionManager transactionManager = new ReadonlyTransactionManager(_connector.getProvider_instance(), _account_address); + ERC20 customERC20Contract = ERC20.load(_tokenInfo.getContractAddress(), _connector.getProvider_instance(), transactionManager, new DefaultGasProvider()); + BigInteger balanceInWEI = customERC20Contract.balanceOf(_account_address).send(); + BigDecimal balanceInETH = EVMUtils.convertBalanceInWeiToDecimals(balanceInWEI, _tokenInfo.getDecimals()); + BigDecimal balanceInGWEI = EVMUtils.convertBalanceInWeiToGwei(balanceInWEI); + boolean isEmpty = true; + if ((null != balanceInWEI) && balanceInWEI.compareTo(BigInteger.ZERO) > 0) isEmpty = false; + BigDecimal scaledBalanceInGWEI = balanceInGWEI.setScale(0, RoundingMode.HALF_UP); + return new EVMAccountBalance(balanceInWEI.toString(), scaledBalanceInGWEI.toString(), balanceInETH.toPlainString(), new EVMCurrency(_tokenInfo.getName(), _tokenInfo.getSymbol(), _tokenInfo.getDecimals()), isEmpty); + } catch (Exception ex) { + // RPC call exceptions (readonly) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmAS = actAndGetStateEVMProviderException(evmE, _connector, false, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmAS.isNewEVMBlockChainConnector()) _connector = evmAS.getConnector(); + } + } + LOGGER.error(meth + ": Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static EVMNftAccountBalance getAccountBalanceForERC721Token(EVMBlockChainConnector connector, String account_address, String tokenName) { + EVMERC721TokenInfo tokenInfo = connector.getChaininfo().getNftindex().getErc721tokens().get(tokenName); + return getAccountBalanceForERC721Token(connector, account_address, tokenInfo); + } + + public static EVMNftAccountBalance getAccountBalanceForERC721Token(EVMBlockChainConnector _connector, String _account_address, EVMERC721TokenInfo _tokenInfo) { + String meth = "getAccountBalanceForERC721Token()"; + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + // Readonly ERC721 + TransactionManager transactionManager = new ReadonlyTransactionManager(_connector.getProvider_instance(), _account_address); + ERC721 customERC721Contract = ERC721.load(_tokenInfo.getContractAddress(), _connector.getProvider_instance(), transactionManager, new DefaultGasProvider()); + + BigInteger balance = customERC721Contract.balanceOf(_account_address).send(); + boolean isEmpty = true; + if ((null != balance) && balance.compareTo(BigInteger.ZERO) > 0) isEmpty = false; + return new EVMNftAccountBalance(balance.toString(), isEmpty); + } catch (Exception ex) { + // RPC call exceptions (readonly) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmAS = actAndGetStateEVMProviderException(evmE, _connector, false, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmAS.isNewEVMBlockChainConnector()) _connector = evmAS.getConnector(); + } + } + LOGGER.error(meth + ": Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + //return new EVMNftAccountBalance(new BigInteger("0").toString(), true); + } + + public static String transferERC721Token(EVMBlockChainConnector _connector, Credentials _creds, String _target_address, String _tokenName, Long _tokenID) { + EVMERC721TokenInfo tokenInfo = _connector.getChaininfo().getNftindex().getErc721tokens().get(_tokenName); + return transferERC721Token(_connector, _creds, _target_address, tokenInfo, _tokenID, true); + } + + public static String transferERC721Token(EVMBlockChainConnector _connector, Credentials _creds, String _target_address, String _tokenName, Long _tokenID, boolean _haltOnUnconfirmedTX) { + EVMERC721TokenInfo tokenInfo = _connector.getChaininfo().getNftindex().getErc721tokens().get(_tokenName); + return transferERC721Token(_connector, _creds, _target_address, tokenInfo, _tokenID, _haltOnUnconfirmedTX); + } + + public static String transferERC721Token(EVMBlockChainConnector _connector, Credentials _creds, String _target_address, EVMERC721TokenInfo _tokenInfo, Long _tokenID, boolean _haltOnUnconfirmedTX) { + String meth = "transferERC721Token()"; + String strGasLimit = null; + boolean confirmedTransaction = false; + Boolean timeoutNoted = false; + int nodeCallAttemptCount = 0; + int requestCount = 0; + BigInteger increaseGasPriceInWEI = BigInteger.valueOf(0); + + while (!confirmedTransaction && (nodeCallAttemptCount<10) && (requestCount<15)) { + requestCount++; + try { + + /** + * stuck/pending transactions + */ + NonceCheckStatus nc_state = handleNonceState(_connector, _creds, increaseGasPriceInWEI, nodeCallAttemptCount, timeoutNoted); + if (nc_state.isEarlyexit()) return "0xearlyexit"; + + /** + * gasPrice + */ + BigInteger gasPrice = determine_gasprice(_connector, increaseGasPriceInWEI, null); + + /** + * gasLimit + */ + LOGGER.info("------------------------- gasLimit -------------------------"); + DefaultGasProvider gp = new DefaultGasProvider(); + BigInteger gasLimit = gp.getGasLimit(); + LOGGER.info(StringsUtils.cutAndPadStringToN("web3j DefaultGasProvider gasLimit", 39) + ": " + gasLimit + " units"); + if (null != strGasLimit) { + LOGGER.info(StringsUtils.cutAndPadStringToN("chain gasLimit", 39) + ": " + strGasLimit + " units"); + gasLimit = new BigInteger(strGasLimit); + } + + /** + * actual tx + */ + TransactionManager transactionManager = new RawTransactionManager(_connector.getProvider_instance(), _creds, _connector.getChaininfo().getChainId()); + StaticGasProvider gasProvider = new StaticGasProvider(gasPrice, gasLimit); + + // RW ERC721 + BigInteger zero = BigInteger.valueOf(0); + byte[] data = new byte[0]; + ERC721 customERC721Contract = ERC721.load(_tokenInfo.getContractAddress(), _connector.getProvider_instance(), transactionManager, gasProvider); + + TransactionReceipt transactionReceipt = customERC721Contract.safeTransferFrom(_creds.getAddress(), _target_address, new BigInteger(_tokenID.toString()), data, zero).send(); + String hash = transactionReceipt.getTransactionHash(); + return hash; + + } catch (Exception ex) { + // RPC tx exceptions (readwrite) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmEAS = actAndGetStateEVMProviderException(evmE, _connector, _haltOnUnconfirmedTX, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmE.isTimeout()) timeoutNoted = true; + if (evmEAS.isIncreaseGasPrice()) increaseGasPriceInWEI = increaseGasPriceInWEI.add(evmEAS.getSuggestedGasPriceIncreaseInWEI()); + if (evmEAS.isNewEVMBlockChainConnector()) _connector = evmEAS.getConnector(); + } + } + LOGGER.error(meth + ": Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + private static NonceCheckStatus handleNonceState(EVMBlockChainConnector _connector, Credentials _creds, BigInteger increaseGasPriceInWEI, int txAttemptCount, boolean timeoutNoted) { + LOGGER.info("------------------------- stuck/pending tx check -------------------------"); + // Lets first just check that our account doesnt have stuck/pending transactions + + String address = _creds.getAddress(); + PendingTxStatus pendingTX = checkForPendingTransactions(_connector, address); + if (pendingTX.isPending()) { + if (timeoutNoted) { + LOGGER.warn("We have pending (possibly stuck) transaction, but we already submitted a tx and got a timeout .. "); + LOGGER.warn("I think we are good but lost track of our tx .. the timeout probably needs to be increased for this chain .."); + return new NonceCheckStatus(pendingTX, true); + } else if (pendingTX.getNonce_diff() >= 2L) { + LOGGER.warn("The account " + _creds.getAddress() + " has a nonce diff of " + pendingTX.getNonce_diff()); + LOGGER.warn("We might have to try to reset this account. timeoutNoted=" + timeoutNoted + " txAttemptCount=" + txAttemptCount); + if (txAttemptCount>1) { + System.out.println("transactionAttemptCount is " + txAttemptCount + " so lets do it..."); + + String txhash_reset = EVMUtils.resetPendingTransactionsForAccount(_connector, _creds); + if (null == txhash_reset) { + LOGGER.error(" - Giving up on reset account transaction.."); + SystemUtils.halt(); + } else { + LOGGER.info(" - Reset account TX completed with hash: " + txhash_reset); + LOGGER.error("OK now we should be able to proceed with the actual tx"); + SystemUtils.sleepInSeconds(3); + } + } else { + System.out.println("transactionAttemptCount is " + txAttemptCount + ", is this account running txs in paralell? Lets do an early exit .."); + return new NonceCheckStatus(pendingTX, true); + } + } else { + LOGGER.error("We have pending (possibly stuck) transaction, need clear that up before proceeding."); + + LOGGER.info("First lets just try to wait it in"); + boolean pendingResolved = brieflyWaitForPendingTransactionsToClear(_connector, address); + if (pendingResolved) { + LOGGER.info("Nice, we solved a problem by only waiting .. winning .. waiting just a few more to make sure all nodes are synced"); + SystemUtils.sleepInSeconds(20); + } else { + LOGGER.warn("The account " + _creds.getAddress() + " might be stuck in pending state due to this one .."); + System.out.println("do a nonce reset automatically? ... send 0 value from/to my address?"); + + if (txAttemptCount>1) { + System.out.println("transactionAttemptCount is " + txAttemptCount + " so lets do it..."); + + String txhash_reset = EVMUtils.resetPendingTransactionsForAccount(_connector, _creds); + if (null == txhash_reset) { + LOGGER.error(" - Giving up on reset account transaction.."); + SystemUtils.halt(); + } else { + LOGGER.info(" - Reset account TX completed with hash: " + txhash_reset); + LOGGER.error("OK now we should be able to proceed with the actual tx"); + SystemUtils.sleepInSeconds(3); + } + } else { + LOGGER.info("give up .. txAttempCount is " + txAttemptCount); + return new NonceCheckStatus(pendingTX, true); + } + } + } + } + return new NonceCheckStatus(pendingTX, false); + } + + public static Boolean isOwnerOfERC721Token(EVMBlockChainConnector _connector, String _address, String _tokenName, Long _tokenID) { + EVMERC721TokenInfo tokenInfo = _connector.getChaininfo().getNftindex().getErc721tokens().get(_tokenName); + return isOwnerOfERC721Token(_connector, _address, tokenInfo, _tokenID); + } + + public static Boolean isOwnerOfERC721Token(EVMBlockChainConnector _connector, String _address, EVMERC721TokenInfo _tokenInfo, Long _tokenID) { + String meth = "isOwnerOfERC721Token()"; + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + + // Readonly ERC721 + TransactionManager transactionManager = new ReadonlyTransactionManager(_connector.getProvider_instance(), _address); + ERC721 customERC721Contract = ERC721.load(_tokenInfo.getContractAddress(), _connector.getProvider_instance(), transactionManager, new DefaultGasProvider()); + + BigInteger balance = customERC721Contract.balanceOf(_address).send(); + if (balance.longValue() > 0L) { + System.out.println(_address + " does own some of these NFTs, lets check if the tokenID matches .."); + + String owner = customERC721Contract.ownerOf(new BigInteger(_tokenID.toString())).send(); + if (owner.toLowerCase().equals(_address.toLowerCase())) { + return true; + } else { + return false; + } + + } else { + // No need to check for specific tokenID match, the address does not own any + return false; + } + + } catch (Exception ex) { + // RPC call exceptions (readonly) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmAS = actAndGetStateEVMProviderException(evmE, _connector, false, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmAS.isNewEVMBlockChainConnector()) _connector = evmAS.getConnector(); + } + } + LOGGER.error(meth + ": Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static void printWalletBalanceForERC20Token(EVMBlockChainConnector _connector, String _address, EVMERC20TokenInfo _tokenInfo) { + EVMAccountBalance bal = getAccountBalanceForERC20Token(_connector, _address, _tokenInfo); + if (null != bal) { + System.out.println(" * account address " + _address + " balance " + bal.getBalanceInETH() + " " + _tokenInfo.getSymbol() + " [" + bal.getBalanceInWEI() + " wei]"); + } + } + + public static BigDecimal convertBalanceInWeiToDecimals(BigInteger _balance, Integer _decimals) { + try { + BigDecimal ethBalanceDEC = Convert.fromWei(_balance.toString(), Unit.WEI); + long po = (long) Math.pow(10L, _decimals); + ethBalanceDEC = ethBalanceDEC.divide(new BigDecimal(po), 2, RoundingMode.HALF_UP); + return ethBalanceDEC; + } catch (Exception ex) { + LOGGER.warn("convertBalanceInWeiToDecimals() ex: " + ex.getMessage()); + } + return null; + } + + public static BigDecimal convertBalanceInWeiToEth(BigInteger _balance) { + try { + BigDecimal ethBalanceFULL = Convert.fromWei(_balance.toString(), Unit.ETHER); + return ethBalanceFULL; + } catch (Exception ex) { + LOGGER.warn("convertBalanceInWeiToEth() ex: " + ex.getMessage()); + } + return null; + } + + public static BigDecimal convertBalanceInWeiToGwei(BigInteger _balance) { + try { + BigDecimal ethBalanceGWEI = Convert.fromWei(_balance.toString(), Unit.GWEI); + return ethBalanceGWEI; + } catch (Exception ex) { + LOGGER.warn("convertBalanceInWeiToEth() ex: " + ex.getMessage()); + } + return null; + } + + public static BigInteger convertBalanceInGweiToWei(BigInteger _valueInGWEI) { + try { + BigInteger ethValueInWEI = _valueInGWEI.multiply(new BigInteger("1000000000")); + return ethValueInWEI; + } catch (Exception ex) { + LOGGER.warn("convertBalanceInWeiToEth() ex: " + ex.getMessage()); + } + return null; + } + + public static BigInteger getLatestBlockNumber(EVMBlockChainConnector _connector) { + String meth = "getLatestBlockNumber()"; + if (null == _connector) return null; + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + EthBlockNumber result = _connector.getProvider_instance().ethBlockNumber().sendAsync().get(); + return result.getBlockNumber(); + } catch (Exception ex) { + // RPC call exceptions (readonly) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmAS = actAndGetStateEVMProviderException(evmE, _connector, false, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmAS.isNewEVMBlockChainConnector()) _connector = evmAS.getConnector(); + } + } + LOGGER.error(meth + ": Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static BigInteger getLatestBlockNumberOpportunistic(EVMBlockChainConnector _connector) { + String meth = "getLatestBlockNumberOpportunistic()"; + if (null == _connector) return null; + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<3) && (requestCount<5)) { + requestCount++; + try { + EthBlockNumber result = _connector.getProvider_instance().ethBlockNumber().sendAsync().get(); + return result.getBlockNumber(); + } catch (Exception ex) { + // RPC call exceptions (readonly) + System.out.println("exception .. nodeCallAttemptCount=" + nodeCallAttemptCount + " requestCount=" + requestCount); + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmAS = actAndGetStateEVMProviderException(evmE, _connector, false, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmAS.isNewEVMBlockChainConnector()) _connector = evmAS.getConnector(); + } + } + return null; + } + + public static BigInteger getTransactionCountForAddress(EVMBlockChainConnector _connector, String _account_address) { + String meth = "getTransactionCountForAddress()"; + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + EthGetTransactionCount result = new EthGetTransactionCount(); + result = _connector.getProvider_instance().ethGetTransactionCount( + _account_address, + DefaultBlockParameter.valueOf("latest")) + .sendAsync() + .get(); + return result.getTransactionCount(); + } catch (Exception ex) { + // RPC call exceptions (readonly) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmAS = actAndGetStateEVMProviderException(evmE, _connector, false, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmAS.isNewEVMBlockChainConnector()) _connector = evmAS.getConnector(); + } + } + LOGGER.error(meth + ": Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static BigInteger getChainId(EVMBlockChainConnector _connector) { + String meth = "getChainId()"; + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + EthChainId chainId = _connector.getProvider_instance().ethChainId().send(); + return chainId.getChainId(); + } catch (Exception ex) { + // RPC call exceptions (readonly) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmAS = actAndGetStateEVMProviderException(evmE, _connector, false, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmAS.isNewEVMBlockChainConnector()) _connector = evmAS.getConnector(); + } + } + LOGGER.error(meth + ": Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static void printLatestBlockNumber(EVMBlockChainConnector _connector) { + LOGGER.info(_connector.getChaininfo().getShortName() + " (chainid: " + _connector.getChaininfo().getChainId() + ") latest block number: " + getLatestBlockNumber(_connector)); + } + + public static void printCurrentStandardGasPriceInGWEI(EVMBlockChainConnector _connector) { + LOGGER.info(_connector.getChaininfo().getShortName() + " (chainid: " + _connector.getChaininfo().getChainId() + ") current STANDARD gas price : " + getCurrentNetworkGasPriceInGWEI(_connector) + " GWEI"); + } + + public static BigDecimal getCurrentNetworkGasPriceInGWEI(EVMBlockChainConnector _connector) { + String meth = "getCurrentNetworkGasPriceInGWEI()"; + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + EthGasPrice gasPrice = _connector.getProvider_instance().ethGasPrice().send(); + BigDecimal gaspriceInGWEI = Convert.fromWei(gasPrice.getGasPrice().toString(), Unit.GWEI); + return gaspriceInGWEI; + } catch (Exception ex) { + // RPC call exceptions (readonly) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmAS = actAndGetStateEVMProviderException(evmE, _connector, false, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmAS.isNewEVMBlockChainConnector()) _connector = evmAS.getConnector(); + } + } + LOGGER.error(meth + ": Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static BigInteger getCurrentNetworkGasPriceInWEI(EVMBlockChainConnector _connector) { + String meth = "getCurrentNetworkGasPriceInWEI()"; + int nodeCallAttemptCount = 0; + int requestCount = 0; + while ((nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + EthGasPrice gasPrice = _connector.getProvider_instance().ethGasPrice().send(); + return gasPrice.getGasPrice(); + } catch (Exception ex) { + // RPC call exceptions (readonly) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmAS = actAndGetStateEVMProviderException(evmE, _connector, false, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmAS.isNewEVMBlockChainConnector()) _connector = evmAS.getConnector(); + } + } + LOGGER.error(meth + ": Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static String sendSignedRawTX(EVMBlockChainConnector _connector, Credentials _creds, String _contractAddress, String _rawData, int _initialConfirmTimeInSeconds, String _strGasLimit, boolean _haltOnUnconfirmedTX) { + String meth = "sendSignedRawTX()"; + String hash = null; + boolean bumpNoonce = false; // to force a new transaction + + boolean confirmedTransaction = false; + boolean timeoutNoted = false; + int nodeCallAttemptCount = 0; + int requestCount = 0; + BigInteger increaseGasPriceInWEI = BigInteger.valueOf(0); + + while (!confirmedTransaction && (nodeCallAttemptCount<10) && (requestCount<15)) { + requestCount++; + try { + + /** + * stuck/pending transactions + */ + NonceCheckStatus nc_state = handleNonceState(_connector, _creds, increaseGasPriceInWEI, nodeCallAttemptCount, timeoutNoted); + if (nc_state.isEarlyexit()) return "0xearlyexit"; + + /** + * nonce + */ + EthGetTransactionCount ethGetTransactionCount = _connector.getProvider_instance().ethGetTransactionCount(_creds.getAddress(), DefaultBlockParameterName.PENDING).send(); + BigInteger nonce = ethGetTransactionCount.getTransactionCount(); + if (bumpNoonce) nonce = nonce.add(new BigInteger("1")); + + /** + * gasPrice + */ + BigInteger gasPrice = determine_gasprice(_connector, increaseGasPriceInWEI, null); + + /** + * gasLimit + */ + LOGGER.info("------------------------- gasLimit -------------------------"); + DefaultGasProvider gp = new DefaultGasProvider(); + BigInteger gasLimit = gp.getGasLimit(); + LOGGER.info(StringsUtils.cutAndPadStringToN("web3j DefaultGasProvider gasLimit", 39) + ": " + gasLimit + " units"); + if (null != _strGasLimit) { + LOGGER.info(StringsUtils.cutAndPadStringToN("chain gasLimit", 39) + ": " + _strGasLimit + " units"); + gasLimit = new BigInteger(_strGasLimit); + } + + LOGGER.info("------------------------------------------------------------"); + LOGGER.info("sendSignedRawTX(): Proceeding with tx using gasPrice: " + Convert.fromWei(gasPrice.toString(), Unit.GWEI).setScale(0, RoundingMode.HALF_UP) + " gwei, gasLimit: " + gasLimit + " units, nodeCallAttemptCount=" + nodeCallAttemptCount); + + RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, gasPrice, gasLimit, _contractAddress, _rawData); + byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, Long.parseLong(_connector.getChaininfo().getChainId() + ""), _creds); + String hexSignedMessage = Numeric.toHexString(signedMessage); + + EthSendTransaction response = _connector.getProvider_instance().ethSendRawTransaction(hexSignedMessage).send(); + hash = response.getTransactionHash(); + if (null == hash) { + + // DEBUG (STILL IN DEV) + //----------------------------------------------------------------------------- + LOGGER.error("response ERROR data: " + response.getError().getData()); + LOGGER.error("response ERROR message: " + response.getError().getMessage()); + LOGGER.error("response ERROR code: " + response.getError().getCode()); + LOGGER.error("response ID: " + response.getId()); + LOGGER.error("response rawresponse: " + response.getRawResponse()); + + EVMTransactionExceptionEvent txE = handleTransactionException(_connector.getChain(), _connector.getCurrent_nodeURL(), response.getError().getMessage(), response.getError().getData()); + System.out.println("txE.getExceptionType(): " + txE.getExceptionType()); + System.out.println("txE.getSleepTimeInSecondsRecommended(): " + txE.getSleepTimeInSecondsRecommended()); + System.out.println("txE.isNodeInteraction(): " + txE.isNodeInteraction()); + System.out.println("txE.isDoubleGasPrice(): " + txE.isDoubleGasPrice()); + System.out.println("txE.isDoubleGasLimit(): " + txE.isDoubleGasLimit()); + System.out.println("txE.isSleepBeforeRetry(): " + txE.isSleepBeforeRetry()); + System.out.println("txE.isSwitchNode(): " + txE.isSwitchNode()); + System.out.println("txE.getExceptionType(): " + txE.getExceptionType()); + System.out.println("exception message: " + response.getError().getMessage()); + + if (txE.isNodeInteraction()) nodeCallAttemptCount++; + if (txE.isSleepBeforeRetry()) SystemUtils.sleepInSeconds(txE.getSleepTimeInSecondsRecommended()); + if (txE.getExceptionType() == ExceptionType.FATAL) SystemUtils.halt(); + if (txE.isSwitchNode()) _connector.selectRandomNodeURL(_connector.getCurrent_nodeURL()); + if (txE.isDoubleGasPrice()) { + //https://docs.klaytn.foundation/klaytn/design/transaction-fees, will result in 'invalid unit price' on KLAYTN + if (_connector.getChain() != EVMChain.KLAYTN) { + increaseGasPriceInWEI = increaseGasPriceInWEI.multiply(BigInteger.valueOf(2)); // x2 + } + } + if ( true && + ((txE.getExceptionType() != ExceptionType.RECOVERABLE) || (txE.getExceptionType() != ExceptionType.IGNORE)) && + _haltOnUnconfirmedTX && + true) { + LOGGER.info(meth + " haltOnUnconfirmedTX is set to true, and we have an unrecoverable exception"); + SystemUtils.halt(); + } + //----------------------------------------------------------------------------- + + if (txE.getExceptionType() == ExceptionType.MOVEON) { + LOGGER.info("Instructed to move on"); + if (_haltOnUnconfirmedTX) { + LOGGER.info("But haltOnUnconfirmedTX is true so will halt"); + SystemUtils.halt(); + } else { + LOGGER.info("Instructed to move on .. dont like it but will"); + return null; + } + } else { + SystemUtils.halt(); + } + + } else { + + LOGGER.info("txhash: " + hash); + LOGGER.info("response ID: " + response.getId()); + LOGGER.info("response error: " + response.getError()); + if (null != response.getError()) { + LOGGER.info("response error.code: " + response.getError().getCode()); + LOGGER.info("response error.data: " + response.getError().getData()); + LOGGER.info("response error.message: " + response.getError().getMessage()); + } + LOGGER.info("response reseult: " + response.getResult()); + } + + // At least give it a few seconds + LOGGER.info("Giving transaction an initial " + _initialConfirmTimeInSeconds + " seconds to get a confirmation .."); + SystemUtils.sleepInSeconds(_initialConfirmTimeInSeconds); + + // Wait for a successful transaction + if (null != response.getTransactionHash()) { + LOGGER.info("tx submitted with hash " + response.getTransactionHash()); + + int receiptPollCounter = 0; + while (!confirmedTransaction && receiptPollCounter<100) { + EthGetTransactionReceipt ethGetTransactionReceipt = _connector.getProvider_instance().ethGetTransactionReceipt(response.getTransactionHash()).send(); + LOGGER.info("ethGetTransactionReceipt: " + ethGetTransactionReceipt.getTransactionReceipt().isPresent() + " for txhash " + response.getTransactionHash()); + SystemUtils.sleepInSeconds(10); + if (ethGetTransactionReceipt.getTransactionReceipt().isPresent()) confirmedTransaction = true; + + if (null != ethGetTransactionReceipt.getError()) { + LOGGER.warn("error code: " + ethGetTransactionReceipt.getError().getCode()); + LOGGER.warn("error message: " + ethGetTransactionReceipt.getError().getMessage()); + } + + receiptPollCounter++; + + if (receiptPollCounter>20) { + LOGGER.warn("nodeCallAttemptCount: " + nodeCallAttemptCount + ", unable to grab tx receipt for " + response.getTransactionHash()); + LOGGER.info("lets make sure we increase the gas price for the next attempt"); + increaseGasPriceInWEI = increaseGasPriceInWEI.add(BigInteger.valueOf(2000000000)); // bump by 2 gwei + } + } + } + + } catch (Exception ex) { + // RPC tx exceptions (readwrite) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmEAS = actAndGetStateEVMProviderException(evmE, _connector, _haltOnUnconfirmedTX, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmE.isTimeout()) timeoutNoted = true; + if (evmEAS.isIncreaseGasPrice()) increaseGasPriceInWEI = increaseGasPriceInWEI.add(evmEAS.getSuggestedGasPriceIncreaseInWEI()); + if (evmEAS.isNewEVMBlockChainConnector()) _connector = evmEAS.getConnector(); + } + } + + if (confirmedTransaction) { + return hash; + } else { + if (_haltOnUnconfirmedTX) { + LOGGER.info("haltOnUnconfirmedTX is set to true, and we are out of retry attempts"); + SystemUtils.halt(); + } + return null; + } + + } + + + public static String sendUnsignedRawCALL(String _rawData, String _contractAddress, EVMBlockChainConnector _connector, boolean _haltOnFailedCall) { + String meth = "sendUnsignedRawCALL()"; + String hash = null; + boolean confirmedCall = false; + int nodeCallAttemptCount = 0; + int requestCount = 0; + while (!confirmedCall && (nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + TransactionManager transactionManager = new ReadonlyTransactionManager(_connector.getProvider_instance(), _contractAddress); // why need fromAddress when RO? + org.web3j.protocol.core.methods.response.EthCall ethCall = _connector.getProvider_instance().ethCall( + Transaction.createEthCallTransaction( + transactionManager.getFromAddress(), _contractAddress, _rawData), + DefaultBlockParameter.valueOf("latest")) + .send(); + String value = ethCall.getValue(); + if (null == value) { + LOGGER.warn("Response from unsigned call failed (null response)"); + } + return value; + } catch (Exception ex) { + LOGGER.info("ex: " + ex.getMessage()); + // RPC call exceptions (readonly) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmAS = actAndGetStateEVMProviderException(evmE, _connector, false, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmAS.isNewEVMBlockChainConnector()) _connector = evmAS.getConnector(); + } + } + + if (confirmedCall) { + return hash; + } else { + if (_haltOnFailedCall) { + LOGGER.info("haltOnUnconfirmedTX is set to true, and we are out of retry attempts"); + SystemUtils.halt(); + } + return null; + } + + } + + public static Boolean isContract(String _contractAddress, EVMBlockChainConnector _connector) { + String meth = "isContract()"; + boolean confirmedCall = false; + int nodeCallAttemptCount = 0; + int requestCount = 0; + while (!confirmedCall && (nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + EthGetCode ethCall = _connector.getProvider_instance().ethGetCode(_contractAddress, DefaultBlockParameter.valueOf("latest")).send(); + String code = ethCall.getCode(); + if ("0x".equals(code)) { + return false; + } else { + return true; + } + } catch (Exception ex) { + // RPC call exceptions (readonly) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmAS = actAndGetStateEVMProviderException(evmE, _connector, false, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmAS.isNewEVMBlockChainConnector()) _connector = evmAS.getConnector(); + } + } + return null; + } + + public static String sendTXWithNativeCurrency(EVMBlockChainConnector _connector, Credentials _from_wallet_credentials, String _target_address, String _strGasLimit, EVMNativeValue _evmNativeValue, boolean _haltOnUnconfirmedTX) { + String meth = "sendTXWithNativeCurrency()"; + if (EVMPriceMechanism.valueOf(_connector.getChaininfo().getPriceMechanism()) == EVMPriceMechanism.EIP1559) { + return sendTXWithNativeCurrency_LegacyPricingMechanism(_connector, _from_wallet_credentials, _target_address, _evmNativeValue, _haltOnUnconfirmedTX); + //return sendTXWithNativeCurrency_EIP1559PricingMechanism(connector, from_wallet, target_address, initialConfirmTimeInSeconds, evmNativeValue); + } else if (EVMPriceMechanism.valueOf(_connector.getChaininfo().getPriceMechanism()) == EVMPriceMechanism.LEGACY) { + return sendTXWithNativeCurrency_LegacyPricingMechanism(_connector, _from_wallet_credentials, _target_address, _evmNativeValue, _haltOnUnconfirmedTX); + } else { + LOGGER.error("Unable to comply with price mechanism named: " + _connector.getChaininfo().getPriceMechanism()); + SystemUtils.halt(); + } + LOGGER.error(meth + ": Unable to properly interact with the blockchain, out of retries .. ABORT!"); + SystemUtils.halt(); + return null; + } + + public static String sendTXWithNativeCurrency_LegacyPricingMechanism(EVMBlockChainConnector _connector, Credentials _from_wallet_credentials, String _target_address, EVMNativeValue _evmNativeValue, boolean _haltOnUnconfirmedTX) { + return sendTXWithNativeCurrency_LegacyPricingMechanism_CustomNonce(_connector, _from_wallet_credentials, _target_address, _evmNativeValue, _haltOnUnconfirmedTX, null, false); + } + + public static String sendTXWithNativeCurrency_LegacyPricingMechanism_CustomNonce(EVMBlockChainConnector _connector, Credentials _creds, String _target_address, EVMNativeValue _evmNativeValue, boolean _haltOnUnconfirmedTX, BigInteger _customNonce, boolean _forceIncreaseGas) { + String meth = "sendTXWithNativeCurrency_LegacyPricingMechanism_CustomNonce()"; + String hash = null; + Boolean timeoutNoted = false; + + boolean confirmedTransaction = false; + int nodeCallAttemptCount = 0; + BigInteger increaseGasPriceInWEI = BigInteger.valueOf(0); + if (_forceIncreaseGas) { + increaseGasPriceInWEI = increaseGasPriceInWEI.add(BigInteger.valueOf(9000000000L)); // bump by 9 gwei + } + int requestCount = 0; + + while (!confirmedTransaction && (nodeCallAttemptCount<10) && (requestCount<15)) { + requestCount++; + + /** + * customNonce + */ + if (null == _customNonce) { + + /** + * stuck/pending transactions + */ + NonceCheckStatus nc_state = handleNonceState(_connector, _creds, increaseGasPriceInWEI, nodeCallAttemptCount, timeoutNoted); + if (nc_state.isEarlyexit()) return "0xearlyexit"; + + } + + // enforce the latest nonce? + /* + EthGetTransactionCount ethGetTransactionCount_latest = null; + try { + ethGetTransactionCount_latest = _connector.getProvider_instance().ethGetTransactionCount(_creds.getAddress(), DefaultBlockParameterName.LATEST).send(); + } catch (IOException e1) { + SystemUtils.halt(); + } + _customNonce = ethGetTransactionCount_latest.getTransactionCount(); + */ + + try { + + /** + * gasPrice + */ + BigInteger gasPrice = determine_gasprice(_connector, increaseGasPriceInWEI, _customNonce); + + /** + * gasLimit + */ + LOGGER.info("------------------------- gasLimit -------------------------"); + DefaultGasProvider gp = new DefaultGasProvider(); + BigInteger gasLimit = gp.getGasLimit(); + LOGGER.info(StringsUtils.cutAndPadStringToN("web3j DefaultGasProvider gasLimit", 39) + ": " + gasLimit + " units"); + if (null != _connector.getChaininfo().getFallbackGasLimitInUnits()) { + LOGGER.info(StringsUtils.cutAndPadStringToN("Specified gasLimit", 39) + ": " + _connector.getChaininfo().getFallbackGasLimitInUnits() + " units"); + gasLimit = new BigInteger(_connector.getChaininfo().getFallbackGasLimitInUnits()); + } + + LOGGER.info("------------------------------------------------------------"); + LOGGER.info("sendTXWithNativeCurrency_LegacyPricingMechanism(): Proceeding with tx using gasPrice: " + Convert.fromWei(gasPrice.toString(), Unit.GWEI).setScale(0, RoundingMode.HALF_UP) + " gwei, gasLimit: " + gasLimit + " units, nodeCallAttemptCount=" + nodeCallAttemptCount); + LOGGER.info("TX value: " + _evmNativeValue.getVal().setScale(6, RoundingMode.HALF_UP) + " " + _connector.getChaininfo().getNativeCurrency().getSymbol()); + + try { + + if (null != _customNonce) { + LOGGER.info("We have a custom nonce .. creating raw transaction with nonce " + _customNonce); + + RawTransaction rawTransaction = RawTransaction.createEtherTransaction( + _customNonce, gasPrice, gasLimit, _target_address, new BigInteger("0")); + + byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, Long.parseLong(_connector.getChaininfo().getChainId() + ""), _creds); + String hexSignedMessage = Numeric.toHexString(signedMessage); + + EthSendTransaction response = _connector.getProvider_instance().ethSendRawTransaction(hexSignedMessage).send(); + hash = response.getTransactionHash(); + if (null == hash) { + + // DEBUG (STILL IN DEV) + //----------------------------------------------------------------------------- + LOGGER.error("response ERROR data: " + response.getError().getData()); + LOGGER.error("response ERROR message: " + response.getError().getMessage()); + LOGGER.error("response ERROR code: " + response.getError().getCode()); + LOGGER.error("response ID: " + response.getId()); + LOGGER.error("response rawresponse: " + response.getRawResponse()); + + EVMTransactionExceptionEvent txE = handleTransactionException(_connector.getChain(), _connector.getCurrent_nodeURL(), response.getError().getMessage(), response.getError().getData()); + System.out.println("txE.getExceptionType(): " + txE.getExceptionType()); + System.out.println("txE.getSleepTimeInSecondsRecommended(): " + txE.getSleepTimeInSecondsRecommended()); + System.out.println("txE.isNodeInteraction(): " + txE.isNodeInteraction()); + System.out.println("txE.isDoubleGasPrice(): " + txE.isDoubleGasPrice()); + System.out.println("txE.isDoubleGasLimit(): " + txE.isDoubleGasLimit()); + System.out.println("txE.isSleepBeforeRetry(): " + txE.isSleepBeforeRetry()); + System.out.println("txE.isSwitchNode(): " + txE.isSwitchNode()); + System.out.println("txE.getExceptionType(): " + txE.getExceptionType()); + System.out.println("exception message: " + response.getError().getMessage()); + + + if (txE.isNodeInteraction()) nodeCallAttemptCount++; + if (txE.isSleepBeforeRetry()) SystemUtils.sleepInSeconds(txE.getSleepTimeInSecondsRecommended()); + if (txE.getExceptionType() == ExceptionType.FATAL) SystemUtils.halt(); + if (txE.isSwitchNode()) _connector.selectRandomNodeURL(_connector.getCurrent_nodeURL()); + if (txE.isDoubleGasPrice()) { + //https://docs.klaytn.foundation/klaytn/design/transaction-fees, will result in 'invalid unit price' on KLAYTN + if (_connector.getChain() != EVMChain.KLAYTN) { + increaseGasPriceInWEI = increaseGasPriceInWEI.multiply(BigInteger.valueOf(2)); // x2 + } + } + if ( true && + ((txE.getExceptionType() != ExceptionType.RECOVERABLE) || (txE.getExceptionType() != ExceptionType.IGNORE)) && + _haltOnUnconfirmedTX && + true) { + LOGGER.info(meth + " haltOnUnconfirmedTX is set to true, and we have an unrecoverable exception"); + SystemUtils.halt(); + } + //----------------------------------------------------------------------------- + + if (txE.getExceptionType() == ExceptionType.MOVEON) { + LOGGER.info("Instructed to move on"); + if (_haltOnUnconfirmedTX) { + LOGGER.info("But haltOnUnconfirmedTX is true so will halt"); + SystemUtils.halt(); + } else { + LOGGER.info("Instructed to move on .. dont like it but will"); + return null; + } + } else { + SystemUtils.halt(); + } + + } else { + LOGGER.info("txhash: " + hash); + LOGGER.info("response ID: " + response.getId()); + } + + // At least give it a few seconds + LOGGER.info("Giving transaction an initial 30 seconds to get a confirmation .."); + SystemUtils.sleepInSeconds(30); + + // Wait for a successful transaction + if (null != response.getTransactionHash()) { + LOGGER.info("lets go with " + response.getTransactionHash()); + + int receiptPollCounter = 0; + while (!confirmedTransaction && receiptPollCounter<100) { + EthGetTransactionReceipt ethGetTransactionReceipt = _connector.getProvider_instance().ethGetTransactionReceipt(response.getTransactionHash()).send(); + LOGGER.info("ethGetTransactionReceipt: " + ethGetTransactionReceipt.getTransactionReceipt().isPresent() + " for txhash " + response.getTransactionHash()); + SystemUtils.sleepInSeconds(10); + if (ethGetTransactionReceipt.getTransactionReceipt().isPresent()) confirmedTransaction = true; + receiptPollCounter++; + + if (receiptPollCounter>20) { + LOGGER.warn("Unable to grab tx receipt for " + response.getTransactionHash()); + } + } + } + + + } else { + // default 40*15=600 secs + int attempts = 40; // 40 default (DEFAULT_POLLING_ATTEMPTS_PER_TX_HASH, TransactionManager) + long sleepDuration = 15000L; // 15 default (DEFAULT_BLOCK_TIME, TransactionManager/JsonRpc2_0Web3j) + + // timeout seems to be 600 seconds, not configurable + TransactionManager transactionManager = new RawTransactionManager(_connector.getProvider_instance(), _creds, _connector.getChaininfo().getChainId(), attempts, sleepDuration); + TransactionReceipt transactionReceipt = new Transfer(_connector.getProvider_instance(), transactionManager).sendFunds( + _target_address, + _evmNativeValue.getVal(), + _evmNativeValue.getUnit(), + gasPrice, + gasLimit + ).send(); + + hash = transactionReceipt.getTransactionHash(); + LOGGER.info("Transaction complete with txhash: " + hash + " at blocknr " + transactionReceipt.getBlockNumber() + " spent gas: " + transactionReceipt.getGasUsed().toString() + " units"); + confirmedTransaction = true; + } + + } catch (TransactionException te) { + System.out.println("TransactionException hash: " + te.getTransactionHash().get()); // for tx finalized this Optional wasnt reflected on blockchain? + System.out.println("TransactionException message: " + te.getMessage()); + + // Reset the account + LOGGER.warn("Do we now start polling for status of tx " + te.getTransactionHash().get() + "??"); + LOGGER.warn("The account " + _creds.getAddress() + " might be stuck in pending state due to this one. We checked prior to submitting this tx though."); + System.out.println("nodeCallAttemptCount=" + nodeCallAttemptCount); + + if (nodeCallAttemptCount>1) { + System.out.println("nodeCallAttemptCount is " + nodeCallAttemptCount + ", nonce reset on the account ..."); + + String txhash_reset = EVMUtils.resetPendingTransactionsForAccount(_connector, _creds); + if (null == txhash_reset) { + LOGGER.info(" - Giving up on reset account transaction"); + } else { + LOGGER.info(" - Reset account TX completed with hash: " + txhash_reset); + SystemUtils.sleepInSeconds(3); + } + } else { + + LOGGER.info("nah lets not nonce reset .. nodeCallAttemptCount is " + nodeCallAttemptCount); + + // Wait for a successful transaction + if (null != te.getTransactionHash().get()) { + LOGGER.info("Lets do 100x poll for status of " + te.getTransactionHash().get() + " for chain " + _connector.getChain() + " .."); + + int receiptPollCounter = 0; + while (!confirmedTransaction && receiptPollCounter<100) { + EthGetTransactionReceipt ethGetTransactionReceipt = _connector.getProvider_instance().ethGetTransactionReceipt(te.getTransactionHash().get()).send(); + LOGGER.info("ethGetTransactionReceipt: " + ethGetTransactionReceipt.getTransactionReceipt().isPresent() + " for txhash " + te.getTransactionHash().get()); + SystemUtils.sleepInSeconds(10); + if (ethGetTransactionReceipt.getTransactionReceipt().isPresent()) confirmedTransaction = true; + receiptPollCounter++; + + if (receiptPollCounter>20) { + LOGGER.warn("Unable to grab tx receipt for " + te.getTransactionHash().get()); + } + } + + if (_haltOnUnconfirmedTX) { + LOGGER.error("We cant just continue with the tx here, instructed to halt on unconfirmed tx."); + SystemUtils.halt(); + } else { + return null; + } + } else { + if (_haltOnUnconfirmedTX) { + LOGGER.error("We dont even have a txhash to poll status from, instructed to halt on unconfirmed tx. ABORT!"); + SystemUtils.halt(); + } else { + return null; + } + } + } + + // DEBUG + try { + TransactionReceipt transactionReceiptEX = te.getTransactionReceipt().get(); + System.out.println("transactionReceiptEX isStatusOK: " + transactionReceiptEX.isStatusOK()); + if (transactionReceiptEX.isStatusOK()) { + LOGGER.info("We good now at blocknr " + transactionReceiptEX.getBlockNumber() + "??"); + SystemUtils.halt(); + } else { + LOGGER.error("content: " + transactionReceiptEX.toString()); + SystemUtils.halt(); + } + } catch (Exception e) { + // Unable to get the transaction receipt + EVMTransactionExceptionEvent txE = handleTransactionException(_connector.getChain(), _connector.getCurrent_nodeURL(), te.getMessage(), "missing"); + System.out.println("txE.getExceptionType(): " + txE.getExceptionType()); + System.out.println("txE.getSleepTimeInSecondsRecommended(): " + txE.getSleepTimeInSecondsRecommended()); + System.out.println("txE.isNodeInteraction(): " + txE.isNodeInteraction()); + System.out.println("txE.isDoubleGasPrice(): " + txE.isDoubleGasPrice()); + System.out.println("txE.isDoubleGasLimit(): " + txE.isDoubleGasLimit()); + System.out.println("txE.isSleepBeforeRetry(): " + txE.isSleepBeforeRetry()); + System.out.println("txE.isSwitchNode(): " + txE.isSwitchNode()); + System.out.println("txE.getExceptionType(): " + txE.getExceptionType()); + System.out.println("exception message: " + e.getMessage()); + + if (txE.getExceptionType() == ExceptionType.MOVEON) { + LOGGER.info("Instructed to move on"); + if (_haltOnUnconfirmedTX) { + LOGGER.info("But haltOnUnconfirmedTX is true so will halt"); + SystemUtils.halt(); + } else { + LOGGER.info("Instructed to move on .. dont like it but will"); + return null; + } + } else { + SystemUtils.halt(); + } + } + + } catch (Exception ex) { + // RPC tx exceptions (readwrite) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmEAS = actAndGetStateEVMProviderException(evmE, _connector, _haltOnUnconfirmedTX, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmE.isTimeout()) timeoutNoted = true; + if (evmEAS.isIncreaseGasPrice()) increaseGasPriceInWEI = increaseGasPriceInWEI.add(evmEAS.getSuggestedGasPriceIncreaseInWEI()); + if (evmEAS.isNewEVMBlockChainConnector()) _connector = evmEAS.getConnector(); + } + } catch (Exception ex) { + // RPC tx exceptions (readwrite) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmEAS = actAndGetStateEVMProviderException(evmE, _connector, _haltOnUnconfirmedTX, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmE.isTimeout()) timeoutNoted = true; + if (evmEAS.isIncreaseGasPrice()) increaseGasPriceInWEI = increaseGasPriceInWEI.add(evmEAS.getSuggestedGasPriceIncreaseInWEI()); + if (evmEAS.isNewEVMBlockChainConnector()) _connector = evmEAS.getConnector(); + } + } + + + if (confirmedTransaction) { + return hash; + } else { + return null; + } + + } + + public static BigInteger determine_gasprice(EVMBlockChainConnector _connector, BigInteger _increaseGasPriceInWEI, BigInteger _customNonce) { + return determine_gaspriceInWEI(_connector, _increaseGasPriceInWEI, _customNonce, true); + } + + public static BigInteger determine_gaspriceInWEI(EVMBlockChainConnector _connector, BigInteger _increaseGasPriceInWEI, BigInteger _customNonce, boolean withLogOutput) { + + BigInteger gasPriceInWEI = new BigInteger("1000000000"); // start with 1 gwei + + if (withLogOutput) LOGGER.info("------------------------- gasPrice -------------------------"); + DefaultGasProvider gp0 = new DefaultGasProvider(); + gasPriceInWEI = gp0.getGasPrice(); + if (withLogOutput) LOGGER.info(StringsUtils.cutAndPadStringToN("web3j DefaultGasProvider gasPrice", 39) + ": " + Convert.fromWei(gp0.getGasPrice().toString(), Unit.GWEI).setScale(0, RoundingMode.HALF_UP) + " gwei"); + if (withLogOutput) LOGGER.info(StringsUtils.cutAndPadStringToN("forestfish fallback gasprice", 39) + ": " + Convert.fromWei(_connector.getChaininfo().getFallbackGasPriceInWEI().toString(), Unit.GWEI).setScale(0, RoundingMode.HALF_UP) + " gwei"); + try { + // By default, 1.2x the recommended network price for testnets + if (_increaseGasPriceInWEI == BigInteger.valueOf(0)) { + BigInteger networkGasPriceInWEI = getCurrentNetworkGasPriceInWEI(_connector); + if (withLogOutput) LOGGER.info(StringsUtils.cutAndPadStringToN("Network recommended gasprice", 39) + ": " + Convert.fromWei(networkGasPriceInWEI.toString(), Unit.GWEI).setScale(0, RoundingMode.HALF_UP) + " gwei (" + networkGasPriceInWEI.toString() + " wei)"); + if (_connector.getChain().toString().contains("TEST")) { + BigInteger gasPriceInWEI20PERC = networkGasPriceInWEI.divide(new BigInteger("5")); + gasPriceInWEI = networkGasPriceInWEI.add(gasPriceInWEI20PERC); // increase by x1.2 + if (withLogOutput) LOGGER.info(StringsUtils.cutAndPadStringToN("1.2x testnet recbumped gasprice", 39) + ": " + Convert.fromWei(gasPriceInWEI.toString(), Unit.GWEI).setScale(0, RoundingMode.HALF_UP) + " gwei (" + gasPriceInWEI.toString() + " wei)"); + } else { + gasPriceInWEI = networkGasPriceInWEI; + } + gasPriceInWEI = bumpGasInWeiAccordingly(_connector, gasPriceInWEI); + } else { + gasPriceInWEI = getCurrentNetworkGasPriceInWEI(_connector); + if (withLogOutput) LOGGER.info(StringsUtils.cutAndPadStringToN("Network recommended gasprico", 39) + ": " + Convert.fromWei(gasPriceInWEI.toString(), Unit.GWEI).setScale(0, RoundingMode.HALF_UP) + " gwei (" + gasPriceInWEI.toString() + " wei)"); + gasPriceInWEI = bumpGasInWeiAccordingly(_connector, gasPriceInWEI); + gasPriceInWEI = gasPriceInWEI.add(_increaseGasPriceInWEI); // finally add any bump + if (withLogOutput) LOGGER.info(StringsUtils.cutAndPadStringToN("ADJ network recommended gasprice", 39) + ": " + Convert.fromWei(gasPriceInWEI.toString(), Unit.GWEI).setScale(0, RoundingMode.HALF_UP) + " gwei (" + gasPriceInWEI.toString() + " wei)"); + } + + // always do the enforced minimum as final check + if (null != _connector.getChaininfo().getEnforcedMinGasPriceInWEI()) { + BigInteger gaspriceInWEI_min = new BigInteger(_connector.getChaininfo().getEnforcedMinGasPriceInWEI()); + if (gaspriceInWEI_min.compareTo(gasPriceInWEI) > 0) { + if (withLogOutput) LOGGER.info("We were about to move forward with gasprice " + EVMUtils.convertBalanceInWeiToGwei(gasPriceInWEI) + " gwei but network minimum setting rules so setting to " + EVMUtils.convertBalanceInWeiToGwei(gaspriceInWEI_min)); + gasPriceInWEI = gaspriceInWEI_min; + } + } + + } catch (Exception e) { + if (withLogOutput) LOGGER.warn("Caught exception while getting gasprice: " + e.getMessage() + ", moving forward with fallback gasPrice " + Convert.fromWei(_connector.getChaininfo().getFallbackGasPriceInWEI().toString(), Unit.GWEI).setScale(0, RoundingMode.HALF_UP) + " gwei"); + gasPriceInWEI = new BigInteger(_connector.getChaininfo().getFallbackGasPriceInWEI().toString()); + } + if (null != _customNonce) { + LOGGER.info("We are doing custom nonce, so doubling gas price used"); + gasPriceInWEI.multiply(new BigInteger("2")); + } + if (withLogOutput) LOGGER.info(StringsUtils.cutAndPadStringToN("Moving forward with gasprice", 39) + ": " + Convert.fromWei(gasPriceInWEI.toString(), Unit.GWEI).setScale(0, RoundingMode.HALF_UP) + " gwei (" + gasPriceInWEI.toString() + " wei)"); + + return gasPriceInWEI; + + } + + public static PendingTxStatus checkForPendingTransactions(EVMBlockChainConnector _connector, String _address) { + String meth = "checkForPendingTransactions()"; + boolean allInfoOK = false; + int nodeCallAttemptCount = 0; + int requestCount = 0; + while (!allInfoOK && (nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + EthGetTransactionCount ethGetTransactionCount_pending = _connector.getProvider_instance().ethGetTransactionCount(_address, DefaultBlockParameterName.PENDING).send(); + BigInteger nonce_pending = ethGetTransactionCount_pending.getTransactionCount(); + + EthGetTransactionCount ethGetTransactionCount_latest = _connector.getProvider_instance().ethGetTransactionCount(_address, DefaultBlockParameterName.LATEST).send(); + BigInteger nonce_latest = ethGetTransactionCount_latest.getTransactionCount(); + + if (nonce_pending.compareTo(nonce_latest) == 0) { + LOGGER.info("checkForPendingTransactions() - No pending tx for " + _address + ", all good to proceed (nonce=" + nonce_pending.longValue() + ", requestCount=" + requestCount + ")"); + return new PendingTxStatus(false, nonce_latest, nonce_pending, 0L); + } else { + LOGGER.warn("We have pending (possibly stuck) transaction:"); + LOGGER.warn(" - nonce_pending: " + nonce_pending.longValue()); + LOGGER.warn(" - nonce_latest: " + nonce_latest.longValue()); + Long nonce_diff = nonce_pending.subtract(nonce_latest).longValue(); + return new PendingTxStatus(true, nonce_latest, nonce_pending, nonce_diff); + } + + } catch (Exception ex) { + LOGGER.warn("Unable to grab pending/latest nonce for " + _address + ", requestCount=" + requestCount); + SystemUtils.sleepInSeconds(1); + + // RPC call exceptions (readonly) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmAS = actAndGetStateEVMProviderException(evmE, _connector, false, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmAS.isNewEVMBlockChainConnector()) _connector = evmAS.getConnector(); + } + } + + LOGGER.error("Unable to get nonce state for " + _address + ", exiting .."); + SystemUtils.halt(); + return null; + } + + public static boolean brieflyWaitForPendingTransactionsToClear(EVMBlockChainConnector _connector, String _address) { + String meth = "brieflyWaitForPendingTransactionsToClear()"; + boolean allInfoOK = false; + + int nodeCallAttemptCount = 0; + int requestCount = 0; + while (!allInfoOK && (nodeCallAttemptCount<10) && (requestCount<20)) { + requestCount++; + try { + + LOGGER.info("Brief sleep of 5 seconds before checking pending/latest nonce"); + SystemUtils.sleepInSeconds(5); + + EthGetTransactionCount ethGetTransactionCount_pending = _connector.getProvider_instance().ethGetTransactionCount(_address, DefaultBlockParameterName.PENDING).send(); + BigInteger nonce_pending = ethGetTransactionCount_pending.getTransactionCount(); + + EthGetTransactionCount ethGetTransactionCount_latest = _connector.getProvider_instance().ethGetTransactionCount(_address, DefaultBlockParameterName.LATEST).send(); + BigInteger nonce_latest = ethGetTransactionCount_latest.getTransactionCount(); + + if (nonce_pending.compareTo(nonce_latest) == 0) { + LOGGER.info("No pending tx for " + _address + ", all good to proceed (nonce=" + nonce_pending.longValue() + ", requestCount=" + requestCount + ")"); + return true; + } else { + LOGGER.info("We are waiting for pending (possibly stuck) transaction:"); + LOGGER.info(" - nonce_pending: " + nonce_pending.longValue()); + LOGGER.info(" - nonce_latest: " + nonce_latest.longValue()); + } + + } catch (Exception ex) { + LOGGER.warn("Unable to grab pending/latest nonce for " + _address + ", nodeCallAttemptCount=" + nodeCallAttemptCount); + SystemUtils.sleepInSeconds(1); + + // RPC call exceptions (readonly) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmAS = actAndGetStateEVMProviderException(evmE, _connector, false, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmAS.isNewEVMBlockChainConnector()) _connector = evmAS.getConnector(); + } + nodeCallAttemptCount++; + } + + return false; + } + + public static BigInteger bumpGasInWeiAccordingly(EVMBlockChainConnector _connector, BigInteger _gasPrice) { + + // Additional topups + if (_gasPrice.compareTo(BigInteger.valueOf(50L*1000000000L)) > 0) { + _gasPrice = _gasPrice.add(new BigInteger("12000000000")); // +12 gwei + } else if (_gasPrice.compareTo(BigInteger.valueOf(40L*1000000000L)) > 0) { + _gasPrice = _gasPrice.add(new BigInteger("10000000000")); // +10 gwei + } else if (_gasPrice.compareTo(BigInteger.valueOf(30L*1000000000L)) > 0) { + _gasPrice = _gasPrice.add(new BigInteger("8000000000")); // +8 gwei + } else if (_gasPrice.compareTo(BigInteger.valueOf(20L*1000000000L)) > 0) { + _gasPrice = _gasPrice.add(new BigInteger("5000000000")); // +5 gwei + } else if (_gasPrice.compareTo(BigInteger.valueOf(10L*1000000000L)) > 0) { + _gasPrice = _gasPrice.add(new BigInteger("3000000000")); // +3 gwei + } else if (_gasPrice.compareTo(BigInteger.valueOf(5L*1000000000L)) > 0) { + _gasPrice = _gasPrice.add(new BigInteger("1000000000")); // +1 gwei + } else if (_gasPrice.compareTo(BigInteger.valueOf(1L*1000000000L)) > 0) { + _gasPrice = _gasPrice.add(new BigInteger("500000000")); // +0.5 gwei + } else { + _gasPrice = _gasPrice.add(new BigInteger("200000000")); // +0.2 gwei + } + + // min 1 gwei fixed for selected testnets + if (false || + (_connector.getChain() == EVMChain.SCROLLALPHATEST) || + (_connector.getChain() == EVMChain.ZETAATHENSTEST) || + false) { + // intrinsic gas too low with double so lets go + _gasPrice = _gasPrice.add(new BigInteger("1000000000")); // add 1 gwei + } + + // min 9 gwei fixed for selected testnets + if (false || + (_connector.getChain() == EVMChain.BOBABNBTEST) || + (_connector.getChain() == EVMChain.SHARDEUMLIBERTY1xTEST) || + (_connector.getChain() == EVMChain.SHARDEUMLIBERTY2xTEST) || + false) { + // intrinsic gas too low with double so lets go + _gasPrice = _gasPrice.add(new BigInteger("9000000000")); // add 9 gwei + } + + return _gasPrice; + } + + public static String encodeEVMTransferData(String toAddress, BigInteger sum) { + Function function = new Function( + "transfer", + Arrays.asList(new Address(toAddress), new Uint256(sum)), // Parameters to pass as Solidity Types + Arrays.asList(new org.web3j.abi.TypeReference() {})); + return FunctionEncoder.encode(function); + } + + public static String sendTXWithERC20_LegacyPricingMechanism(EVMBlockChainConnector _connector, Credentials _creds, String _target_address, String _erc20ContractAddress, BigInteger _amountERC20InWEI, boolean _haltOnUnconfirmedTX) { + String meth = "sendTXWithERC20_LegacyPricingMechanism()"; + String hash = null; + boolean confirmedTransaction = false; + int nodeCallAttemptCount = 0; + boolean timeoutNoted = false; + int requestCount = 0; + BigInteger increaseGasPriceInWEI = BigInteger.valueOf(0); + + while (!confirmedTransaction && (nodeCallAttemptCount<10) && (requestCount<15)) { + requestCount++; + try { + + /** + * stuck/pending transactions + */ + NonceCheckStatus nc_state = handleNonceState(_connector, _creds, increaseGasPriceInWEI, nodeCallAttemptCount, timeoutNoted); + if (nc_state.isEarlyexit()) return "0xearlyexit"; + + /** + * gasPrice + */ + BigInteger gasPrice = determine_gasprice(_connector, increaseGasPriceInWEI, null); + + /** + * gasLimit + */ + LOGGER.info("------------------------- gasLimit -------------------------"); + DefaultGasProvider gp = new DefaultGasProvider(); + BigInteger gasLimit = gp.getGasLimit(); + LOGGER.info(StringsUtils.cutAndPadStringToN("web3j DefaultGasProvider gasLimit", 39) + ": " + gasLimit + " units"); + if (null != _connector.getChaininfo().getFallbackGasLimitInUnits()) { + LOGGER.info(StringsUtils.cutAndPadStringToN("Specified gasLimit", 39) + ": " + _connector.getChaininfo().getFallbackGasLimitInUnits() + " units"); + gasLimit = new BigInteger(_connector.getChaininfo().getFallbackGasLimitInUnits()); + } + if (gasPrice.longValue() < 1000000000L) gasPrice = new BigInteger("1000000000"); // 1 gwei + gasPrice = bumpGasInWeiAccordingly(_connector, gasPrice); + + LOGGER.info("------------------------------------------------------------"); + LOGGER.info("sendTXWithERC20_LegacyPricingMechanism(): Proceeding with tx attempt #" + nodeCallAttemptCount + " using gasPrice: " + Convert.fromWei(gasPrice.toString(), Unit.GWEI).setScale(0, RoundingMode.HALF_UP) + " gwei, gasLimit: " + gasLimit + " units, nodeCallAttemptCount=" + nodeCallAttemptCount); + + try { + + TransactionManager transactionManager = new RawTransactionManager(_connector.getProvider_instance(), _creds, _connector.getChaininfo().getChainId()); + String data = encodeEVMTransferData(_target_address, _amountERC20InWEI); + EthSendTransaction transactionReceipt = transactionManager.sendTransaction(gasPrice, gasLimit, _erc20ContractAddress, data, null); + + hash = transactionReceipt.getTransactionHash(); + if (null != hash) { + LOGGER.info("ERC20 Transaction complete with txhash: " + hash); + confirmedTransaction = true; + } else { + if (null != transactionReceipt.getError()) { + EVMTransactionExceptionEvent txE = handleTransactionException(_connector.getChain(), _connector.getCurrent_nodeURL(), transactionReceipt.getError().getMessage(), transactionReceipt.getError().getData()); + + //------------------------------------------------------------------------- + boolean debug_tx = true; + if (debug_tx) System.out.println("transactionReceipt ID: " + transactionReceipt.getId()); // 802 + if (debug_tx) System.out.println("transactionReceipt error code: " + transactionReceipt.getError().getCode()); + if (debug_tx) System.out.println("transactionReceipt error message: " + transactionReceipt.getError().getMessage()); + if (debug_tx) System.out.println("txE.getExceptionType(): " + txE.getExceptionType()); + if (debug_tx) System.out.println("txE.getSleepTimeInSecondsRecommended(): " + txE.getSleepTimeInSecondsRecommended()); + if (debug_tx) System.out.println("txE.isNodeInteraction(): " + txE.isNodeInteraction()); + if (debug_tx) System.out.println("txE.isDoubleGasPrice(): " + txE.isDoubleGasPrice()); + if (debug_tx) System.out.println("txE.isDoubleGasLimit(): " + txE.isDoubleGasLimit()); + if (debug_tx) System.out.println("txE.isSleepBeforeRetry(): " + txE.isSleepBeforeRetry()); + if (debug_tx) System.out.println("txE.isSwitchNode(): " + txE.isSwitchNode()); + if (debug_tx) System.out.println("txE.getExceptionType(): " + txE.getExceptionType()); + + if (txE.isNodeInteraction()) nodeCallAttemptCount++; + if (txE.isSleepBeforeRetry()) SystemUtils.sleepInSeconds(txE.getSleepTimeInSecondsRecommended()); + if (txE.getExceptionType() == ExceptionType.FATAL) SystemUtils.halt(); + if (txE.isSwitchNode()) _connector.selectRandomNodeURL(_connector.getCurrent_nodeURL()); + if (txE.isDoubleGasPrice()) { + //https://docs.klaytn.foundation/klaytn/design/transaction-fees, will result in 'invalid unit price' on KLAYTN + if (_connector.getChain() != EVMChain.KLAYTN) { + increaseGasPriceInWEI = increaseGasPriceInWEI.multiply(BigInteger.valueOf(2)); // x2 + } + } + //-------------------------------------------------------- + + if (txE.getExceptionType() == ExceptionType.MOVEON) { + LOGGER.info("Instructed to move on"); + if (_haltOnUnconfirmedTX) { + LOGGER.info("But haltOnUnconfirmedTX is true so will halt"); + SystemUtils.halt(); + } else { + LOGGER.info("Instructed to move on .. dont like it but will"); + return null; + } + } else { + LOGGER.error("getting out"); + SystemUtils.halt(); + } + } else { + LOGGER.error("Got a blank transaction receipt and no error message"); + SystemUtils.halt(); + } + LOGGER.error("gettin out"); + SystemUtils.halt(); + } + + } catch (Exception e) { + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), e, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + + //---------------------------------------------------------------- + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmE.isTimeout()) timeoutNoted = true; + if (evmE.isSleepBeforeRetry()) { + SystemUtils.sleepInSeconds(evmE.getSleepTimeInSecondsRecommended()); + } else { + SystemUtils.sleepInSeconds(1); // Always sleep for 1 sec + } + if (evmE.getExceptionType() == ExceptionType.FATAL) SystemUtils.halt(); + if (evmE.isSwitchNode()) _connector.selectRandomNodeURL(_connector.getCurrent_nodeURL()); + if (evmE.isIncreaseGasPrice()) { + //https://docs.klaytn.foundation/klaytn/design/transaction-fees, will result in 'invalid unit price' on KLAYTN + if (_connector.getChain() != EVMChain.KLAYTN) { + increaseGasPriceInWEI = increaseGasPriceInWEI.add(BigInteger.valueOf(2000000000L)); // bump by 2 gwei + } + } + if ( true && + ((evmE.getExceptionType() != ExceptionType.RECOVERABLE) || (evmE.getExceptionType() != ExceptionType.IGNORE)) && + _haltOnUnconfirmedTX && + true) { + LOGGER.info(meth + " haltOnUnconfirmedTX is set to true, and we have an unrecoverable exception"); + SystemUtils.halt(); + } + //---------------------------------------------------------------- + + } + + } catch (Exception ex) { + // RPC tx exceptions (readwrite) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmEAS = actAndGetStateEVMProviderException(evmE, _connector, _haltOnUnconfirmedTX, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmE.isTimeout()) timeoutNoted = true; + if (evmEAS.isIncreaseGasPrice()) increaseGasPriceInWEI = increaseGasPriceInWEI.add(evmEAS.getSuggestedGasPriceIncreaseInWEI()); + if (evmEAS.isNewEVMBlockChainConnector()) _connector = evmEAS.getConnector(); + } + } + + if (confirmedTransaction) { + return hash; + } else { + return null; + } + } + + public static String sendTXWithNativeCurrency_EIP1559PricingMechanism(EVMBlockChainConnector _connector, Credentials _from_wallet_credentials, String _target_address, int _initialConfirmTimeInSeconds, String _strGasLimit, EVMNativeValue _evmNativeValue, boolean _haltOnUnconfirmedTX, BigInteger _customNonce) { + return sendTXWithNativeCurrency_EIP1559PricingMechanism_WithCustomNonce(_connector, _from_wallet_credentials, _target_address, _initialConfirmTimeInSeconds, _strGasLimit, _evmNativeValue, _haltOnUnconfirmedTX, null); + } + + public static String sendTXWithNativeCurrency_EIP1559PricingMechanism_WithCustomNonce(EVMBlockChainConnector _connector, Credentials _creds, String _target_address, int _initialConfirmTimeInSeconds, String _strGasLimit, EVMNativeValue _evmNativeValue, boolean _haltOnUnconfirmedTX, BigInteger _customNonce) { + String meth = "sendTXWithNativeCurrency_EIP1559PricingMechanism_WithCustomNonce()"; + String hash = null; + boolean confirmedTransaction = false; + boolean timeoutNoted = false; + int nodeCallAttemptCount = 0; + int requestCount = 0; + BigInteger increaseGasPriceInWEI = BigInteger.valueOf(0); + + while (!confirmedTransaction && (nodeCallAttemptCount<10) && (requestCount<15)) { + requestCount++; + try { + + /** + * stuck/pending transactions + */ + NonceCheckStatus nc_state = handleNonceState(_connector, _creds, increaseGasPriceInWEI, nodeCallAttemptCount, timeoutNoted); + if (nc_state.isEarlyexit()) return "0xearlyexit"; + + /** + * gasPrice + */ + BigInteger gasPrice = determine_gasprice(_connector, increaseGasPriceInWEI, null); + + /** + * gasLimit + */ + LOGGER.info("------------------------- gasLimit -------------------------"); + DefaultGasProvider gp = new DefaultGasProvider(); + BigInteger gasLimit = gp.getGasLimit(); + LOGGER.info(StringsUtils.cutAndPadStringToN("web3j DefaultGasProvider gasLimit", 39) + ": " + gasLimit + " units"); + if (null != _strGasLimit) { + LOGGER.info(StringsUtils.cutAndPadStringToN("Specified gasLimit", 39) + ": " + _strGasLimit + " units"); + gasLimit = new BigInteger(_strGasLimit); + } + + LOGGER.info("------------------------------------------------------------"); + LOGGER.info("sendTXWithNativeCurrency_EIP1559PricingMechanism(): Proceeding with tx using gasPrice: " + Convert.fromWei(gasPrice.toString(), Unit.GWEI).setScale(0, RoundingMode.HALF_UP) + " gwei, gasLimit: " + gasLimit + " units, nodeCallAttemptCount=" + nodeCallAttemptCount); + + try { + + System.out.println("TODO"); + SystemUtils.halt(); + + BigInteger maxPriorityFeePerGas = gasLimit; + BigInteger maxFeePerGas = BigInteger.valueOf(3_100_000_000L); + + TransactionReceipt transactionReceipt = Transfer.sendFundsEIP1559( + _connector.getProvider_instance(), + _creds, + _target_address, + _evmNativeValue.getVal(), + _evmNativeValue.getUnit(), + gasLimit, + maxPriorityFeePerGas, + maxFeePerGas + ).send(); + + hash = transactionReceipt.getTransactionHash(); + LOGGER.info("Transaction complete with txhash: " + hash + " at blocknr " + transactionReceipt.getBlockNumber() + " spent gas: " + transactionReceipt.getGasUsed().toString() + " units, effective gas price: " + transactionReceipt.getEffectiveGasPrice()); + confirmedTransaction = true; + + } catch (Exception e) { + LOGGER.error("unknown transaction error: " + e.getMessage()); + SystemUtils.halt(); + } + } catch (Exception ex) { + // RPC tx exceptions (readwrite) + EVMProviderException evmE = analyzeProviderException(_connector.getChain(), _connector.getCurrent_nodeURL(), ex, meth); + if (evmE.isTimeout() && (requestCount>=5)) evmE.setSwitchNode(true); // give up on timeout retries and switch node + EVMProviderExceptionActionState evmEAS = actAndGetStateEVMProviderException(evmE, _connector, _haltOnUnconfirmedTX, nodeCallAttemptCount); + if (evmE.isNodeInteraction()) nodeCallAttemptCount++; + if (evmE.isTimeout()) timeoutNoted = true; + if (evmEAS.isIncreaseGasPrice()) increaseGasPriceInWEI = increaseGasPriceInWEI.add(evmEAS.getSuggestedGasPriceIncreaseInWEI()); + if (evmEAS.isNewEVMBlockChainConnector()) _connector = evmEAS.getConnector(); + } + } + + if (confirmedTransaction) { + return hash; + } else { + return null; + } + } + + static EVMProviderExceptionActionState actAndGetStateEVMProviderException(EVMProviderException _evmE, EVMBlockChainConnector _connector, boolean _haltOnUnconfirmedTX, int _nodeCallAttemptCount) { + String meth = "actAndGetStateEVMProviderException()"; + boolean increaseGasPrice = false; + BigInteger suggestedGasPriceIncreaseInWEI = BigInteger.valueOf(0); + + boolean newEVMBlockChainConnector = false; + EVMBlockChainConnector connector = _connector; + + if (_evmE.isSleepBeforeRetry()) { + SystemUtils.sleepInSeconds(_evmE.getSleepTimeInSecondsRecommended()); + } else { + SystemUtils.sleepInSeconds(1); // Always sleep for 1 sec + } + if (_evmE.getExceptionType() == ExceptionType.FATAL) { + LOGGER.info("ExceptionType is FATAL, exiting .."); + SystemUtils.halt(); + } + + boolean forceswitchNode = false; + if (_nodeCallAttemptCount >= 5) { + forceswitchNode = true; + LOGGER.info("We have tried to recover using this node but unsuccessful so far, lets switch node"); + } + if (_evmE.isSwitchNode() || forceswitchNode) { + newEVMBlockChainConnector = true; + connector.selectRandomNodeURL(_connector.getCurrent_nodeURL()); + } + if (_evmE.isIncreaseGasPrice()) { + //https://docs.klaytn.foundation/klaytn/design/transaction-fees, will result in 'invalid unit price' on KLAYTN + if (_connector.getChain() != EVMChain.KLAYTN) { + increaseGasPrice = true; + suggestedGasPriceIncreaseInWEI = suggestedGasPriceIncreaseInWEI.add(BigInteger.valueOf(4000000000L)); // bump by 4 gwei + } + } + if ( true && + ((_evmE.getExceptionType() != ExceptionType.RECOVERABLE) || (_evmE.getExceptionType() != ExceptionType.IGNORE)) && + _haltOnUnconfirmedTX && + true) { + LOGGER.info(meth + " haltOnUnconfirmedTX is set to true, and we have an unrecoverable exception"); + SystemUtils.halt(); + } + + return new EVMProviderExceptionActionState(increaseGasPrice, suggestedGasPriceIncreaseInWEI, newEVMBlockChainConnector, connector); + } + + static EVMProviderException analyzeProviderException(EVMChain _chain, String _nodeURL, Exception _ex, String _func) { + String meth = "analyzeProviderException()"; + boolean nodeInteraction = false; + boolean sleepBeforeRetry = false; + boolean increaseGasPrice = false; + int sleepTimeInSecondsRecommended = 5; + ExceptionType exceptionType = ExceptionType.UNKNOWN; + boolean switchNode = false; + boolean timeout = false; + + if (false || + _ex.getMessage().contains("timeout") || + _ex.getMessage().contains("timed out") || + false) { + // java.net.SocketTimeoutException: connect timed out + // java.net.SocketTimeoutException: Read timed out + LOGGER.info("Got a timeout for nodeURL " + _nodeURL + ".. will retry .. ex: " + _ex.getMessage()); + nodeInteraction = false; + sleepBeforeRetry = true; + sleepTimeInSecondsRecommended = 5; + exceptionType = ExceptionType.RECOVERABLE; + timeout = true; + } else if (false || + (_ex.getMessage().contains("Failed to connect")) || + (_ex.getMessage().contains("Connection reset")) || + (_ex.getMessage().contains("No route to host")) || + (_ex.getMessage().contains("closed")) || + (_ex.getMessage().contains("Remote host terminated the handshake")) || + false) { + // java.net.ConnectException: Failed to connect to + // java.net.SocketException: Connection reset + // javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake + LOGGER.warn("Got a connection reset from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (false || + _ex.getMessage().contains("UnknownHostException") || + _ex.getMessage().contains("No such host is known") || + false) { + LOGGER.info("Unable to resolve host using nodeURL " + _nodeURL + ".. will not retry and switch provider, move on to next node"); + exceptionType = ExceptionType.IGNORE; + sleepBeforeRetry = true; + sleepTimeInSecondsRecommended = 1; + switchNode = true; + } else if (_ex.getMessage().contains("must be in format")) { + // https://github.com/web3j/web3j/issues/1643 + LOGGER.info("Likely issue getting gas price (or generic response decode error) from nodeURL " + _nodeURL + ".. will not retry, move on to next node. Error message: " + _ex.getMessage()); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("No value present")) { + // No value present + LOGGER.info("Got a no value present error from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("404;")) { + LOGGER.warn("Got a 404 non JSON response from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (false || + (_ex.getMessage().contains("500") && _ex.getMessage().toLowerCase().contains("internal")) || + (_ex.getMessage().toLowerCase().contains("internal error")) || + false) { + //

500 Internal Server Error

+ // 500; internal error + // Internal error + // 500; Internal Server Error + LOGGER.warn("Got a 500 internal server error response from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (false || + _ex.getMessage().contains("Unexpected character") || + _ex.getMessage().contains("Invalid response received") || + _ex.getMessage().contains("out of range") || + false) { + // org.web3j.protocol.exceptions.ClientConnectionException: Invalid response received: 521; + // https://zksync.drpc.org: Numeric value (4294935296) out of range of int (-2147483648 - 2147483647) at [Source: (ByteArrayInputStream); line: 1, column: 79] (through reference chain: org.web3j.protocol.core.methods.response.EthGasPrice["error"]->org.web3j.protocol.core.Response$Error["code"])" + LOGGER.info("Got an unknown/invalid RPC reply from nodeURL " + _nodeURL + ".. will not retry, move on to next node. ex: " + _ex.getMessage()); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("502 Bad Gateway")) { + // 502; 502 Bad Gateway

502 Bad Gateway

+ LOGGER.warn("Got a 502 non JSON response from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("503")) { + // 503;

503 Service Unavailable

+ LOGGER.warn("Got a 503 non JSON response from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("503 Service Temporarily Unavailable")) { + //

503 Service Temporarily Unavailable

+ LOGGER.warn("Got a 503 non JSON response from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("unexpected")) { + // java.io.IOException: unexpected end of stream on + LOGGER.warn("Got a 503 non JSON response from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("mempool is full")) { + LOGGER.warn("Got a mempool full response from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().toLowerCase().contains("maximum load")) { + // Maximum load exceeded. + LOGGER.warn("Got a 503 non JSON response from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + sleepBeforeRetry = true; + sleepTimeInSecondsRecommended = 10; + switchNode = true; + } else if (_ex.getMessage().contains("PKIX path")) { + // javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException + // javax.net.ssl.SSLHandshakeException: PKIX path validation failed: java.security.cert.CertPathValidatorException: validity check failed + LOGGER.warn("Got an invalid SSL cert from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("javax.net.ssl.SSLPeerUnverifiedException")) { + // javax.net.ssl.SSLPeerUnverifiedException: Hostname json-rpc.evmos.blockhunters.org not verified: + //certificate: sha256/U95EtMx8zsqjbErAr71y57SwDgA2rZnTLlTIvQqMRzE= + // DN: CN=raa.namecheap.com + // subjectAltNames: [raa.namecheap.com, www.raa.namecheap.com] + LOGGER.warn("Got an invalid SSL cert from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("405 Not Allowed")) { + //

405 Not Allowed

+ LOGGER.warn("Got a 405 response from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("Contract Call has been reverted by the EVM with the reason")) { + // Contract Call has been reverted by the EVM with the reason: 'Cannot fulfill request' + LOGGER.warn("Got a contract call reverted from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().toLowerCase().contains("invalid numeric")) { + // Invalid numeric value: Leading zeroes not allowed + LOGGER.warn("Got invalid numeric value from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("access_denied")) { + // javax.net.ssl.SSLHandshakeException: Received fatal alert: access_denied (caused by cloudflare-eth.com, AV?) + LOGGER.warn("Got accessed denied from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("Transaction receipt was not generated after 600 seconds for transaction")) { + // Transaction receipt was not generated after 600 seconds for transaction + LOGGER.warn("Missing tx receipt from nodeURL " + _nodeURL + ".. will not retry, we dont know how to poll for the tx id"); + exceptionType = ExceptionType.FATAL; + } else if (false || + _ex.getMessage().toLowerCase().contains("transaction nonce") || + _ex.getMessage().toLowerCase().contains("invalid nonce") || + false) { + // ZETACHAINTEST: invalid nonce; got 276, expected 277: invalid sequence: invalid sequence + // Transaction nonce != 1 txNonce:0 + LOGGER.warn(_func + " - Nonce mismatch, you need to make sure you have no pending txs (or clear them first): " + _ex.getMessage()); + nodeInteraction = true; + exceptionType = ExceptionType.FATAL; + } else if (_ex.getMessage().contains("replacement transaction underpriced")) { + // replacement transaction underpriced + LOGGER.warn("Got replacement transaction underpriced from nodeURL " + _nodeURL + ".. will increase gasprice and try again"); + exceptionType = ExceptionType.RECOVERABLE; + increaseGasPrice = true; + } else if (_ex.getMessage().contains("already known")) { + // already known + LOGGER.warn("Got replacement transaction underpriced from nodeURL " + _nodeURL + ".. will increase gasprice and try again"); + exceptionType = ExceptionType.RECOVERABLE; + increaseGasPrice = true; + } else if (_ex.getMessage().contains("transaction underpriced")) { + // JsonRpcError thrown with code -32000. Message: transaction underpriced + LOGGER.warn("Got transaction underpriced from nodeURL " + _nodeURL + ".. will increase gasprice and try again"); + exceptionType = ExceptionType.RECOVERABLE; + increaseGasPrice = true; + } else if (_ex.getMessage().contains("invalid unit price")) { + // invalid unit price, https://pkg.go.dev/github.com/klaytn/klaytn/blockchain + LOGGER.warn("Got invalid unit price from " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("invalid sender")) { + LOGGER.warn("Got invalid sender from nodeURL " + _nodeURL + ".. will not retry since this usually means your specified chain/network id is misformed"); + exceptionType = ExceptionType.FATAL; + } else if (_ex.getMessage().contains("Unable to determine sync status of node")) { + // org.web3j.ens.EnsResolutionException: Unable to determine sync status of node + LOGGER.warn("Got a sync status unknown from nodeURL " + _nodeURL + ".. will not retry since this usually means your specified address is misformed"); + exceptionType = ExceptionType.FATAL; + } else if (_ex.getMessage().contains("only replay-protected (EIP-155) transactions allowed over RPC")) { + // only replay-protected (EIP-155) transactions allowed over RPC + LOGGER.warn("Got a replay-protection error from nodeURL " + _nodeURL + ".. will not retry since this usually means you didnt ship the chain id with your tx, fix your code"); + exceptionType = ExceptionType.FATAL; + } else if (_ex.getMessage().contains("insufficient funds for gas")) { + // insufficient funds for gas * price + value + LOGGER.warn("Got insufficient funds for gas from nodeURL " + _nodeURL + ".. will not retry since this usually means you need to top up the account or attempted to transfer amount which left nothing for gas"); + exceptionType = ExceptionType.FATAL; + } else if (_ex.getMessage().toLowerCase().contains("invalid chain id")) { + // Invalid chain id. + LOGGER.warn("Got invalid chain id from nodeURL " + _nodeURL + ".. will not retry since this usually means you need to top up the account"); + exceptionType = ExceptionType.FATAL; + } else if (false || + _ex.getMessage().toLowerCase().contains("insufficient funds") || + _ex.getMessage().toLowerCase().contains("insufficient balance") || + false) { + // INTERNAL_ERROR: insufficient funds + LOGGER.warn("Got insufficient funds from nodeURL " + _nodeURL + ".. will not retry since this usually means you need to top up the account"); + exceptionType = ExceptionType.FATAL; + } else if (_ex.getMessage().toLowerCase().contains("nonce too low")) { + // INTERNAL_ERROR: nonce too low + LOGGER.warn("Got nonce too low from nodeURL " + _nodeURL + ".. this usually means you screwed up when passing a custom nonce"); + if (_chain == EVMChain.BASETEST) { + LOGGER.info("This does happen from time to time on the BASE test network though, lets retry"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else { + LOGGER.info("This should not happen for " + _chain + ", exiting"); + exceptionType = ExceptionType.FATAL; + } + } else if (_ex.getMessage().toLowerCase().contains("revert")) { + // Failed to submit transaction: Failed to validate the transaction. Reason: Validation revert: Account validation error: Error function_selector = 0x, data = 0x + // Transaction 0x4926dad... has failed with status: 0x0. Gas used: 29603. Revert reason: 'execution reverted'. + LOGGER.warn("Got revert from nodeURL " + _nodeURL + ".. will not retry since likely major issue: " + _ex.getMessage()); + exceptionType = ExceptionType.FATAL; + } else if (_ex.getMessage().contains("Invalid response received: 403")) { + // Invalid response received: 403; Request Blocked. Contact Flux Team. + LOGGER.warn("Got a 403 response from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("Invalid response received: 410")) { + // Network decommissioned, please use Goerli or Sepolia instead + LOGGER.warn("Got a 410 resource GONE response from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("Invalid response received: 525")) { + // Invalid response received: 525 + LOGGER.warn("Got an SSL handshake failed response from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains(_nodeURL.replace("https://",""))) { + // eth.plexnode.wtf (node just echoes its fqdn back) + // polygon-bor.publicnode.com (node just echoes its fqdn back) + LOGGER.warn("Got the FQDN echoed back as response while communicating with " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (false || + _ex.getMessage().contains("No content to map due to end-of-input") || + _ex.getMessage().contains("Cannot deserialize value of type") || + false) { + // com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input + // Cannot deserialize value of type `java.lang.String` from Object value (token `JsonToken.START_OBJECT`) + LOGGER.warn("Got a bad response from nodeURL " + _nodeURL + ".. will not retry, move on to next node"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().equals("Empty value (0x) returned from contract")) { + LOGGER.warn(_func + " - Contract address does not seem to exist, received the following error: " + _ex.getMessage() + ", may be transitory (rare)"); + nodeInteraction = true; + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (false || + _ex.getMessage().contains("transaction underpriced") || + _ex.getMessage().contains("intrinsic gas too low") || + false) { + LOGGER.warn("Gas price likely too low, update your min gas calculations for " + _chain + ", exception: " + _ex.getMessage()); + nodeInteraction = true; + exceptionType = ExceptionType.FATAL; + } else if (_ex.getMessage().contains("Invalid response received: 429")) { + if (false || + _ex.getMessage().contains("daily request count exceeded") || + _ex.getMessage().contains("You have sent too many requests in a given amount of time") || + false) { + LOGGER.info("RPC Node limit reached for nodeURL " + _nodeURL + ", we should probably cool down: " + _ex.getMessage()); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else if (_ex.getMessage().contains("ran out of cu")) { + // org.web3j.protocol.exceptions.ClientConnectionException: Invalid response received: 429; {"jsonrpc":"2.0","id":null,"error":{"code":-32005,"message":"ran out of cu"}} + LOGGER.info("429 error noted for nodeURL " + _nodeURL + ": " + _ex.getMessage() + ", lets try again"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } else { + LOGGER.error("Generic 429 error from nodeURL " + _nodeURL + ": " + _ex.getMessage() + ", update analyzeProviderException() .. "); + LOGGER.info("429 error noted for nodeURL " + _nodeURL + ": " + _ex.getMessage() + ", lets try again"); + exceptionType = ExceptionType.IGNORE; + switchNode = true; + } + } else { + exceptionType = ExceptionType.UNKNOWN; + LOGGER.error(meth + ": Unknown error from nodeURL " + _nodeURL + ", response: \"" + _ex.getMessage() + "\", update " + meth); + LOGGER.error(meth + ": Unknown response noted while communicating with " + _nodeURL); + SystemUtils.halt(); + } + + return new EVMProviderException(exceptionType, nodeInteraction, sleepBeforeRetry, increaseGasPrice, sleepTimeInSecondsRecommended, switchNode, timeout); + } + + private static EVMTransactionExceptionEvent handleTransactionException(EVMChain _chain, String _nodeURL, String _errorMessage, String _data) { + String meth = "handleTransactionException()"; + boolean nodeInteraction = false; + boolean sleepBeforeRetry = false; + boolean doubleGasPrice = false; + boolean doubleGasLimit = false; + int sleepTimeInSecondsRecommended = 5; + ExceptionType exceptionType = ExceptionType.UNKNOWN; + boolean switchNode = false; + boolean dupTransaction = false; + + if (false || + _errorMessage.contains("insufficient funds") || + false) { + // INTERNAL_ERROR: insufficient funds + LOGGER.warn("Got insufficient funds for gas from nodeURL " + _nodeURL + ".. will not retry since this usually means you need to top up the account"); + exceptionType = ExceptionType.FATAL; + } else if (false || + _errorMessage.contains("receipt was not generated after") || + false) { + // Transaction receipt was not generated after 600 seconds for transaction + LOGGER.info("Got a transaction receipt timeout for nodeURL " + _nodeURL + ".. ex: " + _errorMessage); + nodeInteraction = true; + exceptionType = ExceptionType.MOVEON; + } else if (false || + _errorMessage.toLowerCase().contains("internal error") || + _errorMessage.toLowerCase().contains("internal_error") || + false) { + // Internal error + LOGGER.info("Got a 500 internal error for nodeURL " + _nodeURL + ".. ex: " + _errorMessage); + nodeInteraction = true; + exceptionType = ExceptionType.MOVEON; + } else if (false || + _errorMessage.toLowerCase().contains("invalid parameters: tx") || + false) { + // Invalid parameters: tx (https://developer.confluxnetwork.org/sending-tx/en/transaction_send_common_error/) + LOGGER.info("Got invalid parameters from nodeURL " + _nodeURL + ".. ex: " + _errorMessage + " data: " + _data); + nodeInteraction = true; + exceptionType = ExceptionType.MOVEON; + } else if (_errorMessage.contains("already known")) { + LOGGER.warn("Transaction gave an \"already known\" response, which means you may have submitted the same transaction twice"); + dupTransaction = true; + nodeInteraction = true; + exceptionType = ExceptionType.MOVEON; + } else if (_errorMessage.contains("replacement transaction underpriced")) { + // https://ethereum.stackexchange.com/questions/27256/error-replacement-transaction-underpriced/44875 + LOGGER.warn("Transaction gave an \"replacement transaction\" response, which means you may have submitted the same transaction twice"); + dupTransaction = true; + nodeInteraction = true; + exceptionType = ExceptionType.MOVEON; + } else if (false || + _errorMessage.contains("transaction underpriced") || + _errorMessage.contains("intrinsic gas too low") || + false) { + doubleGasPrice = true; + nodeInteraction = true; + exceptionType = ExceptionType.RECOVERABLE; + } else if (_errorMessage.contains("nonce too low")) { + nodeInteraction = true; + exceptionType = ExceptionType.FATAL; + } else if (_errorMessage.contains("insufficient funds for gas")) { + nodeInteraction = true; + exceptionType = ExceptionType.FATAL; + } else if (_errorMessage.contains("gas limit too low")) { + // gas limit too low: 21000 (gas limit) < 21596 (intrinsic gas): out of gas: out of gas (https://evm.testnet.kava.io) + nodeInteraction = true; + doubleGasLimit = true; + exceptionType = ExceptionType.RECOVERABLE; + } else { + exceptionType = ExceptionType.UNKNOWN; + LOGGER.error(meth + ": Unknown tx error from nodeURL " + _nodeURL + ": " + _errorMessage + ", update " + meth); + LOGGER.error(meth + ": Unknown response noted while communicating with " + _nodeURL); + SystemUtils.halt(); + } + + return new EVMTransactionExceptionEvent(exceptionType, nodeInteraction, sleepBeforeRetry, doubleGasPrice, doubleGasLimit, sleepTimeInSecondsRecommended, switchNode, dupTransaction); + } + + public static boolean isValidEthereumAddress(final String _ethereumAddress) { + if (_ethereumAddress == null || !_ethereumAddress.startsWith("0x") || _ethereumAddress.length() != 42) return false; + if (!_ethereumAddress.matches("^0x[0-9a-fA-F]{40}$")) { + return false; + } + if (containsUppercase(_ethereumAddress)) { + return isValidEthereumAddressWithChecksum(_ethereumAddress); + } + return true; + } + + public static boolean containsUppercase(String str) { + for (int i = 0; i < str.length(); i++) { + if (Character.isUpperCase(str.charAt(i))) { + return true; + } + } + return false; + } + + public static boolean isValidEthereumAddressWithChecksum(String _ethereumAddress) { + if (_ethereumAddress == null || !_ethereumAddress.startsWith("0x") || _ethereumAddress.length() != 42) return false; + String addressLC = _ethereumAddress.substring(2).toLowerCase(); + String addressCHECKSUM = Keys.toChecksumAddress(addressLC); + if (_ethereumAddress.equals(addressCHECKSUM)) return true; + return false; + } + + public static EVMChainInfo getEVMChainInfo(EVMChain _shortname) { + EVMChainIndex idx = BlockchainDetailsEVM.generateEVMChainIndex(); + return idx.getNetworks().get(_shortname); + } + + public static EVMBlockChainConnector getEVMChainConnector(EVMChain _shortname) { + return new EVMBlockChainConnector(_shortname); + } + + public static EVMBlockChainConnector getEVMChainConnector(EVMChain _shortname, boolean nodeOptimized) { + return new EVMBlockChainConnector(_shortname, nodeOptimized); + } + + public static EVMBlockChainConnector getEVMChainConnector(EVMChain _shortname, String _forced_nodeURL) { + return new EVMBlockChainConnector(_shortname, _forced_nodeURL); + } + + public static String makeSignedRequest(String _hexData, int _txRetryThreshold, int _confirmTimeInSecondsBeforeRetry, EVMBlockChainConnector _connector, Credentials _creds, String _contractAddress, boolean _haltOnUnconfirmedTX) { + return makeSignedRequest(_hexData, _txRetryThreshold, _confirmTimeInSecondsBeforeRetry, _connector, _creds, _contractAddress, _connector.getChaininfo().getFallbackGasLimitInUnits(), _haltOnUnconfirmedTX); + } + + public static String makeSignedRequest(String _hexData, int _txRetryThreshold, int _confirmTimeInSecondsBeforeRetry, EVMBlockChainConnector _connector, Credentials _creds, String _contractAddress, String _gaslimitInUnits, boolean _haltOnUnconfirmedTX) { + String txHASH = null; + int txCounter = 0; + boolean txAttemptsCompleted = false; + while (!txAttemptsCompleted && txCounter <= _txRetryThreshold) { + LOGGER.info("Sending request: " + _hexData); + + txHASH = EVMUtils.sendSignedRawTX(_connector, _creds, _contractAddress, _hexData, _confirmTimeInSecondsBeforeRetry, _gaslimitInUnits, _haltOnUnconfirmedTX); + if (null == txHASH) { + LOGGER.warn("Transaction failed, will sleep 10 seconds and try again (attempt #" + txCounter + ")"); + SystemUtils.sleepInSeconds(10); + txCounter++; + } else { + System.out.println("txHASH: " + txHASH); + txAttemptsCompleted = true; + } + + if (!txAttemptsCompleted && txCounter == 20) { + LOGGER.warn("Unable to get a transaction receipt after multiple attempts .. we can still check if kinship still got bumped"); + } + + } + return txHASH; + } + + public static String makeUnsignedRequest(String _hexData, String _contractAddress, EVMBlockChainConnector _connector) { + int txCounter = 0; + boolean txCallCompleted = false; + while (!txCallCompleted && txCounter <= _connector.getTxRetryThreshold()) { + //LOGGER.info("Sending request: " + _hexData); + String reply = EVMUtils.sendUnsignedRawCALL(_hexData, _contractAddress, _connector, _connector.isHaltOnFailedCall()); + return reply; + } + return null; + } + + public static String makeUnsignedRequest(String _hexData, String _contractAddress, EVMBlockChainConnector _connector, int _txRetryThreshold, int _confirmTimeInSecondsBeforeRetry, boolean _haltOnFailedCall) { + int txCounter = 0; + boolean txCallCompleted = false; + while (!txCallCompleted && txCounter <= _txRetryThreshold) { + LOGGER.debug("Sending request: " + _hexData); + String reply = EVMUtils.sendUnsignedRawCALL(_hexData, _contractAddress, _connector, _haltOnFailedCall); + return reply; + } + return null; + } + + public static boolean verify(String _signature, String _message, String _address) { + byte[] msgHash = _message.getBytes(); + + String r_string = "0x" + _signature.replace("0x","").substring(0, 64); + String s_string = "0x" + _signature.replace("0x","").substring(64, 128); + String v_string = "0x" + _signature.replace("0x","").substring(128, 130); + + byte[] rbyte = Numeric.hexStringToByteArray(r_string); + byte[] sbyte = Numeric.hexStringToByteArray(s_string); + byte v = Numeric.hexStringToByteArray(v_string)[0]; + + SignatureData sd = + new SignatureData( + v, + rbyte, + sbyte); + + LOGGER.debug("validate v: " + Numeric.toHexString(sd.getV())); + LOGGER.debug("validate r: " + Numeric.toHexString(sd.getR())); + LOGGER.debug("validate s: " + Numeric.toHexString(sd.getS())); + + String addressRecovered = null; + boolean match = false; + + try { + BigInteger recoveredKey = Sign.signedPrefixedMessageToKey(msgHash, sd); + if (recoveredKey != null) { + addressRecovered = "0x" + Keys.getAddress(recoveredKey); + LOGGER.debug("addressRecovered: " + addressRecovered); + if (addressRecovered.equals(_address)) match = true; + } + + } catch (SignatureException e) { + e.printStackTrace(); + } + + return match; + } + + public static EVMPortfolio getEVMPortfolioForAccount(EVMBlockChainUltraConnector _ultra_connector, String _account_addr) { + return getEVMPortfolioForAccount(_ultra_connector, _account_addr, true, null, null, false); + } + + public static EVMPortfolio getEVMPortfolioForAccount(EVMBlockChainUltraConnector _ultra_connector, String _account_addr, boolean debug) { + return getEVMPortfolioForAccount(_ultra_connector, _account_addr, true, null, null, debug); + } + + public static EVMPortfolio getEVMPortfolioForAccount(EVMBlockChainUltraConnector _ultra_connector, String _account_addr, boolean _checkForNFTs, HashMap _erc20_restriction, HashMap _nft_restriction, boolean _debug) { + HashMap chainportfolio = new HashMap<>(); + + for (EVMChain chain: EVMChain.values()) { + if (_debug) System.out.println("chain: " + chain); + + /** + * Verify RPC node connectivity + */ + EVMBlockChainConnector connector_temp = _ultra_connector.getConnectors().get(chain); + if (null == connector_temp) { + LOGGER.debug("We dont have a valid connector for chain " + chain); + } else { + BigInteger latestBlockNr = EVMUtils.getLatestBlockNumberOpportunistic(connector_temp); + if (null == latestBlockNr) { + LOGGER.warn("Seems we cant get a good connection to the chain " + chain); + LOGGER.info("Skipping and will move on .."); + } else { + + if (_debug) LOGGER.info("We have a valid connector for chain " + chain +", latestBlockNr=" + latestBlockNr); + + HashMap erc20tokens = new HashMap<>(); + HashMap erc721tokens = new HashMap<>(); + HashMap erc1155tokens = new HashMap<>(); + EVMAccountBalance native_balance = null; + + EVMChainInfo chainInfo = EVMUtils.getEVMChainInfo(chain); + if (BlockchainType.valueOf(chainInfo.getType()) == _ultra_connector.getChainType()) { + EVMBlockChainConnector connector = _ultra_connector.getConnectors().get(chain); + + if (null != connector) { + BigInteger txCount = EVMUtils.getTransactionCountForAddress(connector, _account_addr); + + /** + * Check native balance + */ + native_balance = EVMUtils.getAccountNativeBalance(connector, _account_addr); + if ((null != native_balance) && (!native_balance.isEmpty())) { + + /** + * Check presence of known ERC-20 tokens on chain + */ + ERC20TokenIndex idx = chainInfo.getTokenIndex(); + for (String tokenName: idx.getTokens().keySet()) { + if (_debug) System.out.println(" ... " + tokenName); + if (false || + (null == _erc20_restriction) || // no restriction + ((null != _erc20_restriction) && (null != _erc20_restriction.get(tokenName))) || // restriction but match + false) { + EVMERC20TokenInfo tokenInfo = idx.getTokens().get(tokenName); + if (isEVMNoiseToken(tokenInfo.getCategory())) { + // skip + } else { + EVMAccountBalance token_balance = EVMUtils.getAccountBalanceForERC20Token(connector, _account_addr, tokenInfo); + + // Decimals debug + if (_debug && (chain == EVMChain.POLYGON) && ("WETH".equals(tokenName))) { + System.out.println(tokenName + " token_balance: " + token_balance.toString()); + } + + if (!token_balance.isEmpty()) { + erc20tokens.put(tokenName, token_balance); + } + } + } + } + + /** + * Check presence of known ERC-721 tokens on chain + */ + if (_checkForNFTs) { + EVMNFTIndex idx_nft = chainInfo.getNftindex(); + for (String nftName: idx_nft.getErc721tokens().keySet()) { + if (false || + (null == _nft_restriction) || // no restriction + ((null != _nft_restriction) && (null != _nft_restriction.get(nftName))) || // restriction but match + false) { + EVMERC721TokenInfo nftInfo = idx_nft.getErc721tokens().get(nftName); + if (isEVMNoiseToken(nftInfo.getCategory())) { + // skip + } else { + EVMNftAccountBalance nft_balance = EVMUtils.getAccountBalanceForERC721Token(connector, _account_addr, nftInfo); + if (!nft_balance.isEmpty()) { + erc721tokens.put(nftName, nft_balance); + } + } + } + } + } + + /** + * Check presence of known ERC-1155 tokens on chain + */ + /* + NFTIndex idx_nft_1155 = chainInfo.getNftindex(); + for (String nftName: idx_nft_1155.getErc1155tokens().keySet()) { + EVMERC1155TokenInfo nftInfo = idx_nft_1155.getErc1155tokens().get(nftName); + if (false || + (TokenCategory.valueOf(nftInfo.getCategory()) == TokenCategory.UNKNOWN) || + (TokenCategory.valueOf(nftInfo.getCategory()) == TokenCategory.SCAM) || + false) { + // skip + } else { + EVMNftAccountBalance nft_balance = EVMUtils.getAccountBalanceForERC1155Token(connector, account_addr, nftInfo); + if (!nft_balance.isEmpty()) { + erc1155tokens.put(nftName, nft_balance); + } + } + } + */ + + EVMChainPortfolio portfolio = new EVMChainPortfolio(_account_addr, chain.toString(), native_balance, txCount.toString(), erc20tokens, erc721tokens, erc1155tokens); + chainportfolio.put(chain, portfolio); + } + } + } + } + } + + } + + return new EVMPortfolio(_account_addr, chainportfolio, System.currentTimeMillis()/1000L); + } + + private static boolean isEVMNoiseToken(String _category) { + if (false || + (TokenCategory.valueOf(_category) == TokenCategory.UNKNOWN) || + (TokenCategory.valueOf(_category) == TokenCategory.SCAM) || + (TokenCategory.valueOf(_category) == TokenCategory.WRECKED) || + false) { + return true; + } + return false; + } + + public static EVMPortfolioDiffResult getEVMPortfolioAsString(EVMPortfolioSimple _portfolio) { + return getEVMPortfolioDiff(_portfolio, null); + } + + + public static ArrayList getFirst10AccountsFromMnemonic(String _mnemonic, String _passphrase) { + ArrayList creds = new ArrayList(); + + LOGGER.debug("Recovering wallet from mnemonic \" " + _mnemonic + " \" and passphrase \"" + _passphrase + "\""); + + // derivationPathETH0 + byte[] seed0 = MnemonicUtils.generateSeed(_mnemonic, _passphrase); + Bip32ECKeyPair masterKeypair0 = Bip32ECKeyPair.generateKeyPair(seed0); + Bip32ECKeyPair childKeypair0 = Bip32ECKeyPair.deriveKeyPair(masterKeypair0, BlockchainDetailsGeneric.derivationPathETH0); + Credentials cred0 = Credentials.create(childKeypair0); + + creds.add(cred0); + + // derivationPathETH1 + byte[] seed1 = MnemonicUtils.generateSeed(_mnemonic, _passphrase); + Bip32ECKeyPair masterKeypair1 = Bip32ECKeyPair.generateKeyPair(seed1); + Bip32ECKeyPair childKeypair1 = Bip32ECKeyPair.deriveKeyPair(masterKeypair1, BlockchainDetailsGeneric.derivationPathETH1); + Credentials cred1 = Credentials.create(childKeypair1); + creds.add(cred1); + + // derivationPathETH2 + byte[] seed2 = MnemonicUtils.generateSeed(_mnemonic, _passphrase); + Bip32ECKeyPair masterKeypair2 = Bip32ECKeyPair.generateKeyPair(seed2); + Bip32ECKeyPair childKeypair2 = Bip32ECKeyPair.deriveKeyPair(masterKeypair2, BlockchainDetailsGeneric.derivationPathETH2); + Credentials cred2 = Credentials.create(childKeypair2); + creds.add(cred2); + + // derivationPathETH3 + byte[] seed3 = MnemonicUtils.generateSeed(_mnemonic, _passphrase); + Bip32ECKeyPair masterKeypair3 = Bip32ECKeyPair.generateKeyPair(seed3); + Bip32ECKeyPair childKeypair3 = Bip32ECKeyPair.deriveKeyPair(masterKeypair3, BlockchainDetailsGeneric.derivationPathETH3); + Credentials cred3 = Credentials.create(childKeypair3); + creds.add(cred3); + + // derivationPathETH4 + byte[] seed4 = MnemonicUtils.generateSeed(_mnemonic, _passphrase); + Bip32ECKeyPair masterKeypair4 = Bip32ECKeyPair.generateKeyPair(seed4); + Bip32ECKeyPair childKeypair4 = Bip32ECKeyPair.deriveKeyPair(masterKeypair4, BlockchainDetailsGeneric.derivationPathETH4); + Credentials cred4 = Credentials.create(childKeypair4); + creds.add(cred4); + + // derivationPathETH5 + byte[] seed5 = MnemonicUtils.generateSeed(_mnemonic, _passphrase); + Bip32ECKeyPair masterKeypair5 = Bip32ECKeyPair.generateKeyPair(seed5); + Bip32ECKeyPair childKeypair5 = Bip32ECKeyPair.deriveKeyPair(masterKeypair5, BlockchainDetailsGeneric.derivationPathETH5); + Credentials cred5 = Credentials.create(childKeypair5); + creds.add(cred5); + + // derivationPathETH6 + byte[] seed6 = MnemonicUtils.generateSeed(_mnemonic, _passphrase); + Bip32ECKeyPair masterKeypair6 = Bip32ECKeyPair.generateKeyPair(seed6); + Bip32ECKeyPair childKeypair6 = Bip32ECKeyPair.deriveKeyPair(masterKeypair6, BlockchainDetailsGeneric.derivationPathETH6); + Credentials cred6 = Credentials.create(childKeypair6); + creds.add(cred6); + + // derivationPathETH7 + byte[] seed7 = MnemonicUtils.generateSeed(_mnemonic, _passphrase); + Bip32ECKeyPair masterKeypair7 = Bip32ECKeyPair.generateKeyPair(seed7); + Bip32ECKeyPair childKeypair7 = Bip32ECKeyPair.deriveKeyPair(masterKeypair7, BlockchainDetailsGeneric.derivationPathETH7); + Credentials cred7 = Credentials.create(childKeypair7); + creds.add(cred7); + + // derivationPathETH8 + byte[] seed8 = MnemonicUtils.generateSeed(_mnemonic, _passphrase); + Bip32ECKeyPair masterKeypair8 = Bip32ECKeyPair.generateKeyPair(seed8); + Bip32ECKeyPair childKeypair8 = Bip32ECKeyPair.deriveKeyPair(masterKeypair8, BlockchainDetailsGeneric.derivationPathETH8); + Credentials cred8 = Credentials.create(childKeypair8); + creds.add(cred8); + + // derivationPathETH9 + byte[] seed9 = MnemonicUtils.generateSeed(_mnemonic, _passphrase); + Bip32ECKeyPair masterKeypair9 = Bip32ECKeyPair.generateKeyPair(seed9); + Bip32ECKeyPair childKeypair9 = Bip32ECKeyPair.deriveKeyPair(masterKeypair9, BlockchainDetailsGeneric.derivationPathETH9); + Credentials cred9 = Credentials.create(childKeypair9); + creds.add(cred9); + + return creds; + } + + + public static ArrayList getFirst10AccountsFromMnemonic(String _mnemonic) { + return getFirst10AccountsFromMnemonic(_mnemonic, ""); + } + + public static void printFirst10AccountsFromMnemonic(String _mnemonic) { + ArrayList creds = EVMUtils.getFirst10AccountsFromMnemonic(_mnemonic); + int counter = 0; + for (Credentials cred: creds) { + String hex = cred.getEcKeyPair().getPrivateKey().toString(16); + System.out.println("Account #" + counter + " public=" + cred.getAddress() + " private=0x" + hex); + counter++; + } + } + + public static EVMPortfolioDiffResult getEVMPortfolioDiff(EVMPortfolioSimple _portfolio, EVMPortfolioSimple _portfolio_ref) { + StringBuffer sb = new StringBuffer(); + sb.append("---------------------------------------------------------------------------------------\n"); + sb.append("Portfolio summary for account: " + _portfolio.getAccount_address() + "\n\n"); + EVMPortfolioDiff portfolio_diff = null; + double minValueToTrack = 0.0001d; + int symbol_char_offset = 45; + + boolean ref_portfolio_exists = false; + String breakline = "---------------------------------------------------------------------------------------"; + String breaklinemini = "----------------------------------------------"; + + if (null != _portfolio_ref) ref_portfolio_exists = true; + + for (EVMChain chain: _portfolio.getChainportfolio().keySet()) { + EVMChainInfo chainInfo = EVMUtils.getEVMChainInfo(chain); + EVMChainPortfolio chain_portfolio = _portfolio.getChainportfolio().get(chain); + EVMChainPortfolio chain_portfolio_ref = null; + EVMChainPortfolioDiff chain_portfolio_diff = null; + + if (ref_portfolio_exists) chain_portfolio_ref = _portfolio_ref.getChainportfolio().get(chain); + /** + * Check native balance + */ + int native_name_offset = 73; + EVMAccountBalance native_balance = chain_portfolio.getNativeBalance(); + if (!native_balance.isEmpty()) { + if (ref_portfolio_exists) { + BigDecimal native_balance_refBD = null; + if (null == chain_portfolio_ref) { + native_balance_refBD = new BigDecimal(0); + } else { + EVMAccountBalance native_balance_ref = chain_portfolio_ref.getNativeBalance(); + if (native_balance_ref == null) { + native_balance_refBD = new BigDecimal(0); + } else { + native_balance_refBD = new BigDecimal(native_balance_ref.getBalanceInETH()); + } + } + BigDecimal native_balance_BD = new BigDecimal(native_balance.getBalanceInETH()); + BigDecimal native_balance_diff = native_balance_BD.subtract(native_balance_refBD).setScale(2, RoundingMode.HALF_UP); + if (native_balance_diff.compareTo(BigDecimal.valueOf(minValueToTrack)) > 0) { + sb.append(StringsUtils.cutAndPadStringToN(chain + " balance: ", native_name_offset) + StringsUtils.cutAndPadStringToN(" (" + native_balance.getBalanceInETH() + " " + chainInfo.getNativeCurrency().getSymbol() + ")", symbol_char_offset) + " diff: +" + native_balance_diff + "\n"); + + // Handle cases where new chain activity is noted + if (null == chain_portfolio_ref) chain_portfolio_ref = new EVMChainPortfolio(); + if (null == chain_portfolio_diff) chain_portfolio_diff = new EVMChainPortfolioDiff(); + + // Store our diff + chain_portfolio_diff.setAccount_address(chain_portfolio.getAccount_address()); + chain_portfolio_diff.setChain(chain.toString()); + + EVMAccountBalance native_balance_ref = null; + if (null == chain_portfolio_ref.getNativeBalance()) { + native_balance_ref = new EVMAccountBalance("0", "0", "0", chainInfo.getNativeCurrency(), true); + } else { + native_balance_ref = chain_portfolio_ref.getNativeBalance(); + } + + BigInteger native_balance_diff_wei = new BigInteger(native_balance.getBalanceInWEI()).subtract(new BigInteger(native_balance_ref.getBalanceInWEI())); + BigDecimal native_balance_diff_in_gwei = Convert.fromWei(native_balance_diff_wei.toString(), Unit.GWEI); + chain_portfolio_diff.setNativeBalance(new EVMAccountBalance(native_balance_diff_wei.toString(), native_balance_diff_in_gwei.toString(), native_balance_diff.toString(), chainInfo.getNativeCurrency(), false)); + + } else if (native_balance_diff.compareTo(BigDecimal.valueOf(-minValueToTrack)) < 0) { + if (native_balance_diff.toString().startsWith("-")) { + sb.append(StringsUtils.cutAndPadStringToN(chain + " balance", native_name_offset) + StringsUtils.cutAndPadStringToN(" (" + native_balance.getBalanceInETH() + " " + chainInfo.getNativeCurrency().getSymbol() + ")", symbol_char_offset) + " diff: " + native_balance_diff + "\n"); + } else { + sb.append(StringsUtils.cutAndPadStringToN(chain + " balance", native_name_offset) + StringsUtils.cutAndPadStringToN(" (" + native_balance.getBalanceInETH() + " " + chainInfo.getNativeCurrency().getSymbol() + ")", symbol_char_offset) + "\n"); + } + + // Handle cases where new chain activity is noted + if (null == chain_portfolio_ref) chain_portfolio_ref = new EVMChainPortfolio(); + if (null == chain_portfolio_diff) chain_portfolio_diff = new EVMChainPortfolioDiff(); + + // Store our diff + chain_portfolio_diff.setAccount_address(chain_portfolio.getAccount_address()); + chain_portfolio_diff.setChain(chain.toString()); + + EVMAccountBalance native_balance_ref = null; + if (null == chain_portfolio_ref.getNativeBalance()) { + native_balance_ref = new EVMAccountBalance("0", "0", "0", chainInfo.getNativeCurrency(), true); + } else { + native_balance_ref = chain_portfolio_ref.getNativeBalance(); + } + + BigInteger native_balance_diff_wei = new BigInteger(native_balance.getBalanceInWEI()).subtract(new BigInteger(native_balance_ref.getBalanceInWEI())); + BigDecimal native_balance_diff_in_gwei = Convert.fromWei(native_balance_diff_wei.toString(), Unit.GWEI); + chain_portfolio_diff.setNativeBalance(new EVMAccountBalance(native_balance_diff_wei.toString(), native_balance_diff_in_gwei.toString(), native_balance_diff.toString(), chainInfo.getNativeCurrency(), false)); + + } else { + sb.append(StringsUtils.cutAndPadStringToN(chain + " balance", native_name_offset) + StringsUtils.cutAndPadStringToN(" (" + native_balance.getBalanceInETH() + " " + chainInfo.getNativeCurrency().getSymbol() + ")", symbol_char_offset) + "\n"); + } + } else { + sb.append(StringsUtils.cutAndPadStringToN(chain + " balance", native_name_offset) + StringsUtils.cutAndPadStringToN(" (" + native_balance.getBalanceInETH() + " " + chainInfo.getNativeCurrency().getSymbol() + ")", symbol_char_offset) + "\n"); + } + sb.append(StringsUtils.cutAndPadStringToN(" - txCount: " + chain_portfolio.getTxCount(), 20) + "\n"); + sb.append(breakline + "\n"); + + /** + * ERC-20 tokens + */ + StringBuffer sb_20 = new StringBuffer(); + int erc20_name_offset = 24; // LP names need this .. + int erc20_val_offset = 36; // for them meme tokens .. + + // when ERC20 tokens disappear we need to catch + HashMap token_currency = new HashMap<>(); + HashMap erc20_tokens = new HashMap<>(); + + if ((null != chain_portfolio_ref) && (null != chain_portfolio_ref.getErc20tokens())) { + for (String tokenName: chain_portfolio_ref.getErc20tokens().keySet()) { + EVMAccountBalance token_balance_ref = chain_portfolio_ref.getErc20tokens().get(tokenName); + token_currency.put(tokenName, token_balance_ref.getCurrency()); + erc20_tokens.put(tokenName, token_balance_ref); + } + } + for (String tokenName: chain_portfolio.getErc20tokens().keySet()) { + EVMAccountBalance token_balance = chain_portfolio.getErc20tokens().get(tokenName); + token_currency.put(tokenName, token_balance.getCurrency()); + erc20_tokens.put(tokenName, token_balance); + } + + for (String tokenName: erc20_tokens.keySet()) { + + EVMERC20TokenInfo tokenInfo = chainInfo.getTokenIndex().getTokens().get(tokenName); + if (null == tokenInfo) { + LOGGER.warn("No tokenInfo available for token " + tokenName + ", chain " + chain + ", removed?"); + } else { + + EVMAccountBalance token_balance = chain_portfolio.getErc20tokens().get(tokenName); + if (ref_portfolio_exists) { + + // ref portfolio + BigDecimal token_balance_refBD = null; + if (null == chain_portfolio_ref) { + token_balance_refBD = new BigDecimal(0); + } else { + EVMAccountBalance token_balance_ref = chain_portfolio_ref.getErc20tokens().get(tokenName); + if (token_balance_ref == null) { + token_balance_refBD = new BigDecimal(0); + } else { + token_balance_refBD = new BigDecimal(token_balance_ref.getBalanceInETH()); + } + } + + // new portfolio (not null) + BigDecimal token_balance_BD = null; + if (token_balance == null) { + token_balance = new EVMAccountBalance("0", "0", "0", token_currency.get(tokenName), true); + token_balance_BD = new BigDecimal(0); + } else { + token_balance_BD = new BigDecimal(token_balance.getBalanceInETH()); + } + + BigDecimal token_balance_diff = token_balance_BD.subtract(token_balance_refBD).setScale(2, RoundingMode.HALF_UP); + if (token_balance_diff.compareTo(BigDecimal.valueOf(minValueToTrack)) > 0) { + sb_20.append(" * [ERC20] " + StringsUtils.cutAndPadStringToN(tokenName,erc20_name_offset) + ": " + StringsUtils.cutAndPadStringToN(token_balance.getBalanceInGWEIPrettyPrint() + " gwei", erc20_val_offset) + StringsUtils.cutAndPadStringToN(" (" + token_balance.getBalanceInETHPrettyPrint() + " " + tokenName + ")", symbol_char_offset) + " diff: +" + token_balance_diff + "\n"); + + // Handle cases where new chain activity is noted + if (null == chain_portfolio_ref) chain_portfolio_ref = new EVMChainPortfolio(); + if (null == chain_portfolio_diff) chain_portfolio_diff = new EVMChainPortfolioDiff(); + + // Store our diff + chain_portfolio_diff.setAccount_address(chain_portfolio.getAccount_address()); + chain_portfolio_diff.setChain(chain.toString()); + + EVMAccountBalance token_balance_ref = null; + if (null == chain_portfolio_ref.getErc20tokens().get(tokenName)) { + token_balance_ref = new EVMAccountBalance("0", "0", "0", chainInfo.getNativeCurrency(), true); + } else { + token_balance_ref = chain_portfolio_ref.getErc20tokens().get(tokenName); + } + + BigInteger token_balance_diff_wei = new BigInteger(token_balance.getBalanceInWEI()).subtract(new BigInteger(token_balance_ref.getBalanceInWEI())); + BigDecimal token_balance_diff_in_gwei = Convert.fromWei(token_balance_diff_wei.toString(), Unit.GWEI); + + HashMap erc20tokens_diff = chain_portfolio_diff.getErc20tokens(); + erc20tokens_diff.put(tokenName, new EVMAccountBalance(token_balance_diff_wei.toString(), token_balance_diff_in_gwei.toString(), token_balance_diff.toString(), new EVMCurrency(tokenInfo.getName(), tokenInfo.getSymbol(), tokenInfo.getDecimals()), false)); + chain_portfolio_diff.setErc20tokens(erc20tokens_diff); + + } else if (token_balance_diff.compareTo(BigDecimal.valueOf(minValueToTrack)) < 0) { + if (token_balance_diff.toString().startsWith("-")) { + sb_20.append(" * [ERC20] " + StringsUtils.cutAndPadStringToN(tokenName,erc20_name_offset) + ": " + StringsUtils.cutAndPadStringToN(token_balance.getBalanceInGWEIPrettyPrint() + " gwei", erc20_val_offset) + StringsUtils.cutAndPadStringToN(" (" + token_balance.getBalanceInETHPrettyPrint() + " " + tokenName + ")", symbol_char_offset) + " diff: " + token_balance_diff + "\n"); + + // Handle cases where new chain activity is noted + if (null == chain_portfolio_ref) chain_portfolio_ref = new EVMChainPortfolio(); + if (null == chain_portfolio_diff) chain_portfolio_diff = new EVMChainPortfolioDiff(); + + // Store our diff + chain_portfolio_diff.setAccount_address(chain_portfolio.getAccount_address()); + chain_portfolio_diff.setChain(chain.toString()); + + EVMAccountBalance token_balance_ref = null; + if (null == chain_portfolio_ref.getErc20tokens().get(tokenName)) { + token_balance_ref = new EVMAccountBalance("0", "0", "0", chainInfo.getNativeCurrency(), true); + } else { + token_balance_ref = chain_portfolio_ref.getErc20tokens().get(tokenName); + } + + BigInteger token_balance_diff_wei = new BigInteger(token_balance.getBalanceInWEI()).subtract(new BigInteger(token_balance_ref.getBalanceInWEI())); + BigDecimal token_balance_diff_in_gwei = Convert.fromWei(token_balance_diff_wei.toString(), Unit.GWEI); + + HashMap erc20tokens_diff = chain_portfolio_diff.getErc20tokens(); + erc20tokens_diff.put(tokenName, new EVMAccountBalance(token_balance_diff_wei.toString(), token_balance_diff_in_gwei.toString(), token_balance_diff.toString(), new EVMCurrency(tokenInfo.getName(), tokenInfo.getSymbol(), tokenInfo.getDecimals()), false)); + chain_portfolio_diff.setErc20tokens(erc20tokens_diff); + + } else { + sb_20.append(" * [ERC20] " + StringsUtils.cutAndPadStringToN(tokenName,erc20_name_offset) + ": " + StringsUtils.cutAndPadStringToN(token_balance.getBalanceInGWEIPrettyPrint() + " gwei", erc20_val_offset) + StringsUtils.cutAndPadStringToN(" (" + token_balance.getBalanceInETHPrettyPrint() + " " + tokenName + ")", symbol_char_offset) + "\n"); + } + + } else { + sb_20.append(" * [ERC20] " + StringsUtils.cutAndPadStringToN(tokenName,erc20_name_offset) + ": " + StringsUtils.cutAndPadStringToN(token_balance.getBalanceInGWEIPrettyPrint() + " gwei", erc20_val_offset) + StringsUtils.cutAndPadStringToN(" (" + token_balance.getBalanceInETHPrettyPrint() + " " + tokenName + ")", symbol_char_offset) + "\n"); + } + } else { + BigDecimal token_balance_BD = null; + token_balance_BD = new BigDecimal(token_balance.getBalanceInETH()); + sb_20.append(" * [ERC20] " + StringsUtils.cutAndPadStringToN(tokenName,erc20_name_offset) + ": " + StringsUtils.cutAndPadStringToN(token_balance.getBalanceInGWEI() + " gwei", erc20_val_offset) + StringsUtils.cutAndPadStringToN(" (" + token_balance_BD.setScale(0, RoundingMode.HALF_UP) + " " + tokenName + ")", symbol_char_offset) + "\n"); + } + } + } + if (chain_portfolio.getErc20tokens().keySet().size()>0) sb.append(sb_20.toString()); + + /** + * ERC-721 tokens + */ + StringBuffer sb_721 = new StringBuffer(); + for (String nftName: chain_portfolio.getErc721tokens().keySet()) { + EVMNftAccountBalance nft_balance = chain_portfolio.getErc721tokens().get(nftName); + String unit = "nft"; + BigInteger nft_bal_BI = new BigInteger(nft_balance.getBalance()); + if (nft_bal_BI.compareTo(BigInteger.ONE) > 0) unit = "nfts"; + sb_721.append(" * [ERC721] " + StringsUtils.cutAndPadStringToN(nftName,23) + ": " + StringsUtils.cutAndPadStringToN(nft_bal_BI + " " + unit, 16) + "\n"); + } + if (chain_portfolio.getErc721tokens().keySet().size()>0) { + if (!chain_portfolio.getErc20tokens().keySet().isEmpty()) sb.append(breaklinemini + "\n"); + sb.append(sb_721.toString()); + } + + /** + * ERC-1155 tokens + */ + StringBuffer sb_1155 = new StringBuffer(); + for (String nftName: chain_portfolio.getErc1155tokens().keySet()) { + if (sb_1155.isEmpty()) sb.append(sb_1155.toString() + "\n"); + EVMNftAccountBalance nft_balance = chain_portfolio.getErc1155tokens().get(nftName); + sb_1155.append(" * [ERC1155] " + StringsUtils.cutAndPadStringToN(nftName,23) + ": " + StringsUtils.cutAndPadStringToN(nft_balance.getBalance() + " nft", 8)); + } + if (chain_portfolio.getErc1155tokens().keySet().size()>0) { + if (!chain_portfolio.getErc20tokens().keySet().isEmpty()) sb.append(breaklinemini + "\n"); + System.out.println(sb_1155.toString() + "\n"); + } + + // No ERC20, ERC721 or ERC1155 tokens + if (chain_portfolio.getErc20tokens().keySet().isEmpty() && chain_portfolio.getErc721tokens().keySet().isEmpty() && chain_portfolio.getErc1155tokens().keySet().isEmpty()) { + sb.append(" x [no ERC20/ERC721/ERC1155 tokens]\n"); + } + sb.append("\n"); + } + + // Update our portfolio diff + if (null != chain_portfolio_diff) { + if (null == portfolio_diff) { + portfolio_diff = new EVMPortfolioDiff(); + portfolio_diff.setAccount_address(chain_portfolio_diff.getAccount_address()); + } + HashMap chainportfolio_diff_existing = portfolio_diff.getChainportfolio_diff(); + chainportfolio_diff_existing.put(chain, chain_portfolio_diff); + portfolio_diff.setChainportfolio_diff(chainportfolio_diff_existing); + } + + } + + return new EVMPortfolioDiffResult(sb.toString(), portfolio_diff); + } + + public static void updatePortfolioSnapshot(EVMPortfolio _chainPortfolio, String _snapshotfolder) { + String json = JSONUtils.createJSONFromPOJO(_chainPortfolio); + if ((null != json) && (json.length() > 10)) { + try { + FilesUtils.createFolderUnlessExists(_snapshotfolder); + FilesUtils.writeToFileUNIX(json, _snapshotfolder + "/" + _chainPortfolio.getAccount_address() + ".json"); + } catch (Exception e) { + LOGGER.error("Unable to write to " + _snapshotfolder); + SystemUtils.halt(); + } + } else { + LOGGER.error("Malformed snapshot json?"); + SystemUtils.halt(); + } + } + + public static EVMPortfolio readLatestPortfolioSnapshot(String _address, String _snapshotfolder) { + String filePath = _snapshotfolder + "/" + _address + ".json"; + File f = new File(filePath); + if (f.exists()) { + String json = FilesUtils.readAllFromFileWithPath(filePath); + EVMPortfolio chainPortfolioSnapshot = JSONUtils.createPOJOFromJSON(json, EVMPortfolio.class); + return chainPortfolioSnapshot; + } else { + return null; + } + } + + public static String resetPendingTransactionsForAccount(EVMBlockChainConnector _connector, Credentials _cred) { + EVMNativeValue val = new EVMNativeValue(new BigDecimal(0), Unit.ETHER); + + // Get the lowest existing "stuck" nonce transaction + BigInteger nonce = null; + boolean grabbed_nonce = false; + int tryCounter = 0; + while (!grabbed_nonce && (tryCounter<5)) { + try { + EthGetTransactionCount ethGetTransactionCount = _connector.getProvider_instance().ethGetTransactionCount(_cred.getAddress(), DefaultBlockParameterName.PENDING).send(); + nonce = ethGetTransactionCount.getTransactionCount(); + grabbed_nonce = true; + } catch (IOException e) { + LOGGER.warn("Caught exception while grabbing nonce: " + e.getMessage()); + SystemUtils.sleepInSeconds(5); + } + tryCounter++; + } + + if (null == nonce) { + LOGGER.error("Unable to get the nonce for " + _cred.getAddress()); + SystemUtils.halt(); + } + + // perform the reset + String txhash = EVMUtils.sendTXWithNativeCurrency_LegacyPricingMechanism_CustomNonce(_connector, _cred, _cred.getAddress(), val, false, nonce, true); + return txhash; + } + + public static String transferNativeCurrencyOnChain(EVMBlockChainConnector _connector, Credentials _from, String _to, double _amount) { + String txhash = EVMUtils.sendTXWithNativeCurrency_LegacyPricingMechanism(_connector, _from, _to, new EVMNativeValue(new BigDecimal(_amount), Unit.ETHER), true); + return txhash; + } + + public static void sanityCheckWithEarlyExit(EVMBlockChainConnector _connector) { + BigInteger latest_blocknr = getLatestBlockNumber(_connector); + if (null == latest_blocknr) { + LOGGER.info("Unable to get the latest blocknr from our RPC node, exiting.."); + SystemUtils.halt(); + } else { + LOGGER.info("Initial sanitycheck passed, latest blocknr: " + latest_blocknr); + } + } + + @SuppressWarnings("serial") + public static void checkEthPolyPortfolio(String publicaddress) { + LOGGER.info("checkEthPolyPortfolio init()"); + LOGGER.info(" - account: " + publicaddress); + + // Launch RPC node connectors for POLYGON/ETHEREUM + EVMBlockChainUltraConnector ultra_connector = new EVMBlockChainUltraConnector(BlockchainType.PUBLIC, + new HashMap() {{ + this.put(EVMChain.POLYGON.toString(), true); + this.put(EVMChain.ETHEREUM.toString(), true); + }}); + System.out.println("EVMBlockChainUltraConnector ready .."); + + // Print EVM portfolio + EVMPortfolio evm_chainPortfolio = EVMUtils.getEVMPortfolioForAccount(ultra_connector, publicaddress); + EVMPortfolioSimple evm_chainPortfolio_simple = EVMUtils.createEVMPortfolioSimple(evm_chainPortfolio); + EVMPortfolioDiffResult portfolio_diff = EVMUtils.getEVMPortfolioAsString(evm_chainPortfolio_simple); + System.out.println(portfolio_diff.getPortfolio_full_str()); + } + + public static void checkFullPortfolio(String publicaddress) { + LOGGER.info("checkFullPortfolio init()"); + LOGGER.info(" - account: " + publicaddress); + + // Launch RPC node connectors for all known chains + EVMBlockChainUltraConnector ultra_connector = new EVMBlockChainUltraConnector(BlockchainType.PUBLIC); + System.out.println("EVMBlockChainUltraConnector ready .."); + + // Print EVM portfolio + EVMPortfolio evm_chainPortfolio = EVMUtils.getEVMPortfolioForAccount(ultra_connector, publicaddress); + EVMPortfolioSimple evm_chainPortfolio_simple = EVMUtils.createEVMPortfolioSimple(evm_chainPortfolio); + EVMPortfolioDiffResult portfolio_diff = EVMUtils.getEVMPortfolioAsString(evm_chainPortfolio_simple); + System.out.println(portfolio_diff.getPortfolio_full_str()); + } + + @SuppressWarnings("serial") + public static void checkLocalPortfolio(String publicaddress, EVMChain chain) { + LOGGER.info("checkLocalPortfolio init()"); + LOGGER.info(" - account: " + publicaddress); + + if (true && + !chain.toString().contains("GANACHE") && + !chain.toString().contains("HARDHAT") && + true) { + LOGGER.error("You sure you are connecting to a local ganache/hardhat chain?"); + LOGGER.error("Selected chain: " + chain); + SystemUtils.halt(); + } + + // Launch RPC node connectors for LOCAL networks + EVMBlockChainUltraConnector ultra_connector = new EVMBlockChainUltraConnector(BlockchainType.LOCAL, + new HashMap() {{ + this.put(chain.toString(), true); + }}); + System.out.println("EVMBlockChainUltraConnector ready .."); + + // Print EVM portfolio + EVMPortfolio evm_chainPortfolio = EVMUtils.getEVMPortfolioForAccount(ultra_connector, publicaddress); + EVMPortfolioSimple evm_chainPortfolio_simple = EVMUtils.createEVMPortfolioSimple(evm_chainPortfolio); + EVMPortfolioDiffResult portfolio_diff = EVMUtils.getEVMPortfolioAsString(evm_chainPortfolio_simple); + System.out.println(portfolio_diff.getPortfolio_full_str()); + } + + + public static void evmpingpong(EVMChain _chain, String wallet001_name, String _wallet001_privatekey, String wallet002_name, String _wallet002_privatekey, double _nativeCurrencyToSendBackAndForth, int _nrIterations) { + LOGGER.info("evmpingpong init()"); + LOGGER.info(" - chain: " + _chain.toString()); + + boolean haltOnUnconfirmedTX = true; + EVMBlockChainConnector connector = new EVMBlockChainConnector(_chain); + + BigInteger latestBlockNR = EVMUtils.getLatestBlockNumber(connector); + LOGGER.info("latestBlockNR: " + latestBlockNR); + + BigInteger chainID = EVMUtils.getChainId(connector); + LOGGER.info("- chainID: " + chainID); + + BigDecimal networkGasPriceInGwei = EVMUtils.getCurrentNetworkGasPriceInGWEI(connector); + LOGGER.info("- networkGasPriceInGwei: " + networkGasPriceInGwei.setScale(0, RoundingMode.HALF_UP)); + + // Sanity check + if (EVMUtils.isValidPrivateKey(wallet001_name)) { + LOGGER.info("Did you mix up wallet name and key?"); + SystemUtils.halt(); + } + if (!EVMUtils.isValidPrivateKey(_wallet001_privatekey)) { + LOGGER.info("Not a valid private key: " + _wallet001_privatekey); + SystemUtils.halt(); + } + if (EVMUtils.isValidPrivateKey(wallet002_name)) { + LOGGER.info("Did you mix up wallet name and key?"); + SystemUtils.halt(); + } + if (!EVMUtils.isValidPrivateKey(_wallet002_privatekey)) { + LOGGER.info("Not a valid private key: " + _wallet002_privatekey); + SystemUtils.halt(); + } + + EVMLocalWallet wallet001 = new EVMLocalWallet(wallet001_name, AccountOrigin.PRIVATEKEY, "nopassword", _wallet001_privatekey); + EVMLocalWallet wallet002 = new EVMLocalWallet(wallet002_name, AccountOrigin.PRIVATEKEY, "nopassword", _wallet002_privatekey); + + BigInteger preTxCountForWallet001 = EVMUtils.getTransactionCountForAddress(connector, wallet001.getAddress()); + BigInteger preTxCountForWallet002 = EVMUtils.getTransactionCountForAddress(connector, wallet002.getAddress()); + + String preBalanceWallet001 = EVMUtils.getAccountNativeBalance(connector, wallet001.getAddress()).getBalanceInETH(); + String preBalanceWallet002 = EVMUtils.getAccountNativeBalance(connector, wallet002.getAddress()).getBalanceInETH(); + + // Wallet balance sanity check before we begin + BigDecimal wallet001_balanceBD = new BigDecimal(preBalanceWallet001); + if (wallet001_balanceBD.compareTo(BigDecimal.valueOf(_nativeCurrencyToSendBackAndForth*2d)) > 0) { + LOGGER.info(wallet001.getAddress() + " wallet001 balance: " + wallet001_balanceBD.setScale(6, RoundingMode.HALF_UP) + " " + connector.getChaininfo().getNativeCurrency().getSymbol()); + } else { + LOGGER.error(wallet001.getAddress() + " wallet001 balance: " + wallet001_balanceBD.setScale(6, RoundingMode.HALF_UP) + " " + connector.getChaininfo().getNativeCurrency().getSymbol()); + LOGGER.error("You need at least " + _nativeCurrencyToSendBackAndForth*2d + " " + connector.getChaininfo().getNativeCurrency().getSymbol()); + SystemUtils.halt(); + } + BigDecimal wallet002_balanceBD = new BigDecimal(preBalanceWallet002); + if (wallet002_balanceBD.compareTo(BigDecimal.valueOf(_nativeCurrencyToSendBackAndForth*2d)) > 0) { + LOGGER.info(wallet002.getAddress() + " wallet002 balance: " + wallet002_balanceBD.setScale(6, RoundingMode.HALF_UP) + " " + connector.getChaininfo().getNativeCurrency().getSymbol()); + } else { + LOGGER.error(wallet002.getAddress() + " wallet002 balance: " + wallet002_balanceBD.setScale(6, RoundingMode.HALF_UP) + " " + connector.getChaininfo().getNativeCurrency().getSymbol()); + LOGGER.error("You need at least " + _nativeCurrencyToSendBackAndForth*2d + " " + connector.getChaininfo().getNativeCurrency().getSymbol()); + SystemUtils.halt(); + } + + for (int i=1; i<=_nrIterations; i++) { + + int rand1 = NumUtils.randomNumWithinRangeAsInt(1, 8); + int rand2 = NumUtils.randomNumWithinRangeAsInt(1, 8); + LOGGER.info("--> iteration " + i + " rand1: " + rand1 + " rand2: " + rand2); + + /** + * ping() + * - Send funds from wallet001 --> wallet002 + */ + String txhash1 = EVMUtils.sendTXWithNativeCurrency_LegacyPricingMechanism(connector, wallet001.getCredentials(), wallet002.getAddress(), new EVMNativeValue(BigDecimal.valueOf(_nativeCurrencyToSendBackAndForth*rand1), Unit.ETHER), haltOnUnconfirmedTX); + LOGGER.info("PING TX completed with tx hash: " + txhash1); + + SystemUtils.sleepInSeconds(rand1*100); + + /** + * pong() + * - Send funds from wallet002 --> wallet001 + */ + String txhash2 = EVMUtils.sendTXWithNativeCurrency_LegacyPricingMechanism(connector, wallet002.getCredentials(), wallet001.getAddress(), new EVMNativeValue(BigDecimal.valueOf(_nativeCurrencyToSendBackAndForth*rand2), Unit.ETHER), haltOnUnconfirmedTX); + LOGGER.info("PONG TX completed with tx hash: " + txhash2); + + SystemUtils.sleepInSeconds(rand2*100); + + } + + System.out.println("--------------------------------"); + System.out.println("PRE - " + wallet001_name + " pub: " + wallet001.getAddress() + " txCount: " + preTxCountForWallet001 + " native balance: " + preBalanceWallet001); + System.out.println("POST - " + wallet001_name + " pub: " + wallet001.getAddress() + " txCount: " + EVMUtils.getTransactionCountForAddress(connector, wallet001.getAddress()) + " native balance: " + EVMUtils.getAccountNativeBalance(connector, wallet001.getAddress()).getBalanceInETH()); + System.out.println("--------------------------------"); + System.out.println("PRE - " + wallet002_name + " pub: " + wallet002.getAddress() + " txCount: " + preTxCountForWallet002 + " native balance: " + preBalanceWallet002); + System.out.println("POST - " + wallet002_name + " pub: " + wallet002.getAddress() + " txCount: " + EVMUtils.getTransactionCountForAddress(connector, wallet002.getAddress()) + " native balance: " + EVMUtils.getAccountNativeBalance(connector, wallet002.getAddress()).getBalanceInETH()); + + } + + public static boolean isValidPrivateKey(String _privateKey) { + + if (_privateKey == null || _privateKey.isEmpty()) { + LOGGER.warn("private key is empty or null"); + return false; + } + if (_privateKey.startsWith("0x")) { + _privateKey = _privateKey.replace("0x", ""); + } + + if (_privateKey.contains(" ")) { + LOGGER.warn("private key includes a space"); + return false; + } + + if (!_privateKey.matches("^[0-9a-fA-F]{64}$")) { + LOGGER.debug("private key is not hex of length 64, length: " + _privateKey); + return false; + } + + BigInteger privateKeyInt = new BigInteger(_privateKey, 16); + BigInteger maxVal = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16); + + boolean criteria1 = privateKeyInt.compareTo(BigInteger.ZERO) > 0; + boolean criteria2 = privateKeyInt.compareTo(maxVal) < 0; + + if (criteria1 && criteria2) { + return true; + } else { + LOGGER.warn("Private key does not fulfill basic BigInt criteria"); + LOGGER.warn("criteria1: " + criteria1); + LOGGER.warn("criteria2: " + criteria2); + return false; + } + } + + public static boolean isValidMnemonic(String _mnemonic) { + if (_mnemonic == null || _mnemonic.isEmpty()) { + return false; + } + + List words = Arrays.asList(_mnemonic.split("\\s+")); + if (words.size() % 3 != 0) { + return false; + } + + try { + MnemonicUtils.generateSeed(_mnemonic, ""); + return true; + } catch (InvalidParameterException e) { + return false; + } + } + + public static EVMLocalWallet initializeWallet(String _walletname, String _mnemonic, String _privkey) { + EVMLocalWallet wallet = null; + if (EVMUtils.isValidMnemonic(_mnemonic)) { + wallet = new EVMLocalWallet(_walletname, AccountOrigin.RECOVERY_MNEMONIC, "nopassword", _mnemonic); + } else if (EVMUtils.isValidPrivateKey(_privkey)) { + wallet = new EVMLocalWallet(_walletname, AccountOrigin.PRIVATEKEY, "nopassword", _privkey); + } + + // fallback to local file + if (null == wallet) wallet = new EVMLocalWallet(_walletname, AccountOrigin.EXISTING_LOCALWALLETFILE, "nopassword"); + + // Sanity check + if (!EVMUtils.isValidEthereumAddress(wallet.getCredentials().getAddress())) { + LOGGER.error(" - wallet address is not valid: " + wallet.getCredentials().getAddress()); + SystemUtils.halt(); + } + + return wallet; + } + + public static void ensureWalletHasFunds(EVMBlockChainConnector _connector, EVMLocalWallet _wallet, Double _threshold) { + EVMAccountBalance walletBalance = EVMUtils.getWalletBalanceNativeCurrency(_connector, _wallet); + if (null == walletBalance) { + LOGGER.error("Unable to get wallet balance, halting"); + SystemUtils.halt(); + } else { + // Make sure gas balance is above threshold + if (new BigDecimal(walletBalance.getBalanceInETH()).compareTo(BigDecimal.valueOf(_threshold)) < 0) { + LOGGER.error("wallet " + _wallet.getCredentials().getAddress() + " needs more funds. Halting."); + SystemUtils.halt(); + } + LOGGER.info("wallet " + _wallet.getCredentials().getAddress() + " has sufficient funds: " + walletBalance.getBalanceInETH()); + } + } + + public static EVMPortfolioSimple createEVMPortfolioSimple(EVMPortfolio _evm_portfolio) { + if (null == _evm_portfolio) return null; + return new EVMPortfolioSimple(_evm_portfolio.getAccount_address(), _evm_portfolio.getChainportfolio()); + } + +} diff --git a/src/main/java/crypto/forestfish/utils/FilesUtils.java b/src/main/java/crypto/forestfish/utils/FilesUtils.java new file mode 100644 index 0000000..ab46612 --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/FilesUtils.java @@ -0,0 +1,661 @@ +package crypto.forestfish.utils; + +import com.google.common.base.Joiner; + +import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.*; + +public class FilesUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(FilesUtils.class); + + public static void appendToFileUNIX(final String outString, final String filePath) throws Exception { + appendToFile(outString, filePath, "\n"); + } + + public static void appendToFileWindows(final String outString, final String filePath) throws Exception { + appendToFile(outString, filePath, "\r\n"); + } + + public static void appendToFile(final String outString, final String filePath, final String delimiter) throws Exception { + Writer out = null; + try { + out = new OutputStreamWriter(new FileOutputStream(filePath, true), StandardCharsets.UTF_8); + out.write(outString + delimiter); + out.flush(); + out.close(); + } catch (Exception e) { + throw e; + } finally { + IOUtils.closeQuietly(out); + } + } + + public static void writeToFileWindows(final String outString, final String filePath) throws Exception { + writeToFile(outString, filePath, "\r\n"); + } + + public static void writeToFileUnlessExistsWindows(final String outString, final String filePath) throws Exception { + File f = new File(filePath); + if (!f.exists()) { + writeToFile(outString, filePath, "\r\n"); + } + } + + public static void writeToFileUNIX(final String outString, final String filePath) throws Exception { + writeToFile(outString, filePath, "\n"); + } + + public static void writeToFileUnlessExistsUNIX(final String outString, final String filePath) throws Exception { + File f = new File(filePath); + if (!f.exists()) { + writeToFile(outString, filePath, "\n"); + } + } + + public static boolean writeToFileUnlessExistsUNIXReturnNewFileCreated(final String outString, final String filePath) throws Exception { + File f = new File(filePath); + if (!f.exists()) { + writeToFile(outString, filePath, "\n"); + return false; + } + return false; + } + + public static void writeToFile(final String outString, final String filePath, final String delimiter) throws Exception { + Writer out = null; + try { + File oldFile = new File(filePath); + if (oldFile.exists()) { + if (oldFile.delete() == false) { + LOGGER.warn("Unable to delete " + oldFile.getAbsolutePath()); + } + } + out = new OutputStreamWriter(new FileOutputStream(filePath, true), StandardCharsets.UTF_8); + out.write(outString + delimiter); + out.close(); + } catch (Exception e) { + throw e; + } finally { + IOUtils.closeQuietly(out); + } + } + + public static String readStringFromFile(String filePath) { + String returnString = null; + BufferedReader br; + try { + FileInputStream fstream = new FileInputStream(filePath); + InputStreamReader istream = new InputStreamReader(fstream, StandardCharsets.UTF_8); + br = new BufferedReader(istream); + returnString = br.readLine(); + br.close(); + } catch (IOException e1) { + LOGGER.error("Exception while reading file content of: " + filePath + " exception: " + e1.getMessage()); + } + return returnString; + } + + public static String grabLastLineFromFile(File file) { + RandomAccessFile fileHandler = null; + try { + fileHandler = new RandomAccessFile(file, "r"); + long fileLength = fileHandler.length() - 1; + StringBuilder sb = new StringBuilder(); + + for (long filePointer = fileLength; filePointer != -1; filePointer--) { + fileHandler.seek(filePointer); + int readByte = fileHandler.readByte(); + if (readByte == 0xA) { + if (filePointer == fileLength) { + continue; + } + break; + } else if (readByte == 0xD) { + if (filePointer == (fileLength - 1)) { + continue; + } + break; + } + sb.append((char) readByte); + } + String lastLine = sb.reverse().toString(); + return lastLine; + } catch (java.io.FileNotFoundException e) { + return null; + } catch (java.io.IOException e) { + return null; + } finally { + if (fileHandler != null) { + try { + fileHandler.close(); + } catch (IOException e) { + /* ignore */ + } + } + } + } + + public static void deleteFile(final String filePath) { + File hashFile = new File(filePath); + if (hashFile.exists()) { + if (hashFile.delete()) { + //LOGGER.info("Deleted file " + filePath); + } else { + LOGGER.error("Failed to delete file " + filePath); + LOGGER.error("Please check the permissions and restart dredd"); + SystemUtils.halt(); + } + } + } + + public static boolean deleteFileWithRetries(final String filePath, int nrRetriesThreshold) { + int retryCounter = 0; + boolean fileDeleted = false; + while (!fileDeleted && (retryCounter<=nrRetriesThreshold)) { + File hashFile = new File(filePath); + if (hashFile.exists()) { + if (hashFile.delete()) { + LOGGER.info("Deleted file " + filePath); + return true; + } else { + LOGGER.warn("Failed to delete file " + filePath); + LOGGER.warn("Please check the permissions and restart dredd"); + retryCounter++; + } + } else { + return true; + } + } + return false; + } + + public static List readAllLinesFrom(String primaryPath) { + + primaryPath = StringsUtils.determineExistingFilePath(primaryPath); + File priFile = new File(primaryPath); + if (!priFile.exists()) { + LOGGER.error("Fallback file does not exist at " + priFile.getAbsolutePath()); + LOGGER.error("TERMINATING... "); + SystemUtils.halt(); + } + + final Path pth = priFile.toPath(); + if (!priFile.exists()) { + try { + LOGGER.error("Found no file at " + priFile.getCanonicalPath()); + SystemUtils.halt(); + } catch (IOException e) { + LOGGER.error("IO exception while reading file: " + Arrays.toString(e.getStackTrace())); + SystemUtils.halt(); + } + } + try { + List lines = Files.readAllLines(pth, StandardCharsets.UTF_8); + return lines; + } catch (Exception e) { + LOGGER.error("IO exception while reading file " + primaryPath + ": " + Arrays.toString(e.getStackTrace())); + SystemUtils.halt(); + } + return new ArrayList(); + } + + public static List readAllLinesFromGZ(String primaryPath) { + + primaryPath = StringsUtils.determineExistingFilePath(primaryPath); + File priFile = new File(primaryPath); + if (!priFile.exists()) { + LOGGER.error("Fallback file does not exist at " + priFile.getAbsolutePath()); + LOGGER.error("TERMINATING... "); + SystemUtils.halt(); + } + + if (!priFile.exists()) { + try { + LOGGER.error("Found no file at " + priFile.getCanonicalPath()); + SystemUtils.halt(); + } catch (IOException e) { + LOGGER.error("IO exception while reading file: " + Arrays.toString(e.getStackTrace())); + SystemUtils.halt(); + } + } + try { + + BufferedReader br = null; + GzipCompressorInputStream bzIn = null; + InputStreamReader reader = null; + FileInputStream in = null; + in = new FileInputStream(priFile.getAbsolutePath()); + bzIn = new GzipCompressorInputStream(in); + reader = new InputStreamReader(bzIn, StandardCharsets.UTF_8); + br = new BufferedReader(reader, 33554432); + List lines = new ArrayList(); + String line = ""; + while ((line = br.readLine()) != null) { + if (line.isEmpty()) { + br.close(); + break; + } + lines.add(line); + } + return lines; + } catch (Exception e) { + LOGGER.error("IO exception while reading file " + primaryPath + ": " + Arrays.toString(e.getStackTrace())); + SystemUtils.halt(); + } + return new ArrayList(); + } + + public static List readAllLinesFromNoException(String primaryPath) { + + primaryPath = StringsUtils.determineExistingFilePath(primaryPath); + File priFile = new File(primaryPath); + if (!priFile.exists()) { + LOGGER.info("Fallback file does not exist at " + priFile.getAbsolutePath()); + return new ArrayList(); + } + + final Path pth = priFile.toPath(); + if (!priFile.exists()) { + try { + LOGGER.info("Found no file at " + priFile.getCanonicalPath()); + return new ArrayList(); + } catch (IOException e) { + LOGGER.warn("IO exception while reading file: " + Arrays.toString(e.getStackTrace())); + return new ArrayList(); + } + } + try { + List lines = Files.readAllLines(pth, StandardCharsets.UTF_8); + return lines; + } catch (Exception e) { + LOGGER.error("IO exception while reading file: " + Arrays.toString(e.getStackTrace())); + return new ArrayList(); + } + } + + public static List readRandomlyAllLinesButMaxFrom(String primaryPath, int maxReturn) { + File priFile = new File(primaryPath); + String secondaryPath = primaryPath.replaceFirst("/", ""); + File secFile = new File(secondaryPath); + if (!priFile.exists()) { + if (!secFile.exists()) { + LOGGER.error("Fallback file does not exist at " + secFile.getAbsolutePath()); + LOGGER.error("TERMINATING... "); + SystemUtils.halt(); + } + priFile = secFile; + } + final Path pth = priFile.toPath(); + if (!priFile.exists()) { + try { + LOGGER.error("Found no file at " + priFile.getCanonicalPath()); + SystemUtils.halt(); + } catch (IOException e) { + LOGGER.error("IO exception while reading file: " + Arrays.toString(e.getStackTrace())); + SystemUtils.halt(); + } + } + try { + List lines = Files.readAllLines(pth, StandardCharsets.UTF_8); + + long seed = System.nanoTime(); + Collections.shuffle(lines, new Random(seed)); + + ArrayList result = new ArrayList<>(); + int counter = 0; + for (String l: lines) { + if (counter < maxReturn) { + result.add(l); + } + counter++; + } + + return result; + } catch (Exception e) { + LOGGER.error("IO exception while reading file: " + Arrays.toString(e.getStackTrace())); + SystemUtils.halt(); + } + return new ArrayList<>(); + } + + public static String readAllFromFileWithPath(String primaryPath) { + File priFile = new File(primaryPath); + final Path pth = priFile.toPath(); + if (!priFile.exists()) { + try { + LOGGER.error("Found no file at " + priFile.getCanonicalPath()); + SystemUtils.halt(); + } catch (IOException e) { + LOGGER.error("IO exception while reading file: " + Arrays.toString(e.getStackTrace())); + SystemUtils.halt(); + } + } + try { + List lines = Files.readAllLines(pth, StandardCharsets.UTF_8); + String result = StringUtils.join(lines, "\n"); + return result; + } catch (Exception e) { + LOGGER.error("IO exception while reading file: " + Arrays.toString(e.getStackTrace())); + SystemUtils.halt(); + } + return ""; + } + + public static String readAllFromFile(File priFile) { + final Path pth = priFile.toPath(); + if (!priFile.exists()) { + try { + LOGGER.error("Found no file at " + priFile.getCanonicalPath()); + SystemUtils.halt(); + } catch (IOException e) { + LOGGER.error("IO exception while reading file: " + Arrays.toString(e.getStackTrace())); + SystemUtils.halt(); + } + } + try { + List lines = Files.readAllLines(pth, StandardCharsets.UTF_8); + String result = StringUtils.join(lines, "\n"); + return result; + } catch (Exception e) { + LOGGER.error("IO exception while reading file: " + Arrays.toString(e.getStackTrace())); + SystemUtils.halt(); + } + return ""; + } + + public static ArrayList getAllFilesInFolderAsList(final String f) { + String folderpath = getExistingFile2(f); + ArrayList files = new ArrayList(); + File folder = new File(folderpath); + if (folder.exists()) { + for (final File fileEntry : folder.listFiles()) { + if (fileEntry.isFile()) { + files.add(fileEntry.getAbsolutePath()); + } + } + } + return files; + } + + public static ArrayList getAllFileNamesInFolderAsList(final String f) { + String folderpath = getExistingFile2(f); + ArrayList files = new ArrayList(); + File folder = new File(folderpath); + if (folder.exists()) { + for (final File fileEntry : folder.listFiles()) { + if (fileEntry.isFile()) { + files.add(fileEntry.getName()); + } + } + } + return files; + } + + public static ArrayList getAllFileNamesInFolderAsFiles(final String f) { + String folderpath = getExistingFile2(f); + ArrayList files = new ArrayList(); + File folder = new File(folderpath); + if (folder.exists()) { + for (final File fileEntry : folder.listFiles()) { + if (fileEntry.isFile()) files.add(fileEntry); + } + } + return files; + } + + public static ArrayList getAllFoldersInFolderAsList(final String f) { + String folderpath = getExistingFile2(f); + ArrayList files = new ArrayList(); + File folder = new File(folderpath); + if (folder.exists()) { + for (final File fileEntry : folder.listFiles()) { + if (!fileEntry.isFile()) { + files.add(fileEntry.getAbsolutePath()); + } + } + } + return files; + } + + public static String getFileFromFullPath(final String fullPath) { + String[] priFileParts = fullPath.split("/"); + String file = priFileParts[priFileParts.length-1]; + return file; + } + + public static void appendToFileUNIX2(final String outString, final String filePath) throws Exception { + + // File candidate 1 + File priFile = new File(filePath); + String[] priFileParts = filePath.split("/"); + String priFolderTemp = Joiner.on("/").join(Arrays.copyOfRange(priFileParts, 0, priFileParts.length-1)); + File priFolder = new File(priFolderTemp); + + // File candidate 2 + String secondaryPath = filePath.replaceFirst("/", ""); + File secFile = new File(secondaryPath); + String[] secFileParts = secondaryPath.split("/"); + String secFolderTemp = Joiner.on("/").join(Arrays.copyOfRange(secFileParts, 0, secFileParts.length-1)); + File secFolder = new File(secFolderTemp); + + if (priFolder.exists()) { + appendToFile(outString, priFile.getAbsolutePath(), "\n"); + } else if (secFolder.exists() && !"".equals(secFolder.getPath())) { + appendToFile(outString, secFile.getAbsolutePath(), "\n"); + } else { + LOGGER.error("Folder does not exist at " + priFolder.getAbsolutePath() + ", fallback folder does not exist at " + secFolder.getAbsolutePath()); + } + } + + public static String getExistingFolder(final String folderPath) { + File folder1 = new File(folderPath); + String secondaryPath = folderPath.replaceFirst("/", ""); + File folder2 = new File(secondaryPath); + if (folder1.exists()) { + return folderPath; + } else { + if (folder2.exists()) { + return secondaryPath; + } + } + LOGGER.error("Path does not exist at " + folder1.getAbsolutePath() + ", fallback file does not exist at " + folder2.getAbsolutePath()); + SystemUtils.halt(); + return ""; + } + + public static String getExistingFile(final String filePath) { + File file1 = new File(filePath); + String secondaryPath = filePath.replaceFirst("/", ""); + File file2 = new File(secondaryPath); + if (file1.exists()) { + return filePath; + } else { + if (file2.exists()) { + return secondaryPath; + } + } + LOGGER.error("File does not exist at " + filePath + ", fallback file does not exist at " + filePath.replaceFirst("/", "")); + SystemUtils.halt(); + return ""; + } + + public static String getExistingFile2(final String filePath) { + File file1 = new File(filePath); + String secondaryPath = filePath.replaceFirst("/", ""); + File file2 = new File(secondaryPath); + if (file1.exists()) { + return filePath; + } else { + if (file2.exists()) { + return secondaryPath; + } + } + return ""; + } + + public static String getExistingFileIfPossible(final String filePath) { + File file1 = new File(filePath); + String secondaryPath = filePath.replaceFirst("/", ""); + String thirdPath = filePath.replace("\\", ""); + if (file1.exists()) { + return filePath; + } else { + File file2 = new File(secondaryPath); + if (file2.exists()) { + return secondaryPath; + } else { + File file3 = new File(thirdPath); + if (file3.exists()) { + return thirdPath; + } + } + } + LOGGER.info("File does not exist at " + filePath + ", fallback file does not exist at " + secondaryPath + " or " + thirdPath); + return ""; + } + + public static void deleteFilesInFolder(final String folderpath) { + File dir = new File(folderpath); + if (null != dir) { + if (dir.exists()) { + for (File f: dir.listFiles()) { + if (f.exists() && f.isFile()) { + LOGGER.info("Will delete file: " + f.getAbsolutePath() + " name=" + f.getName()); + if (f.delete() == false) { + LOGGER.error("Unable to delete " + f.getAbsolutePath()); + SystemUtils.halt(); + } else { + LOGGER.info("Deleted " + f.getAbsolutePath()); + } + } + } + } + } + } + + public static void deleteFilesAndFoldersInFolder(final String folderpath) { + Path path = Paths.get(folderpath); + try { + Files.walk(path) + .sorted(Comparator.reverseOrder()) + .map(Path::toFile) + .forEach(File::delete); + } catch (IOException e) { + LOGGER.error("Unable to delete folderpath " + folderpath + ", exception: " + e.getMessage()); + SystemUtils.halt(); + } + } + + public static void appendToFileUNIXNoException(final String outString, final String filePath) { + try { + appendToFile(outString, filePath, "\n"); + } catch (Exception e) { + LOGGER.info("e: " + e.getMessage()); + } + } + + public static void writeToFileUNIXNoException(final String outString, final String filePath) { + try { + writeToFile(outString, filePath, "\n"); + } catch (Exception e) { + LOGGER.info("e: " + e.getMessage()); + } + } + + public static void writeToFileUNIXHaltOnException(final String outString, final String filePath) { + try { + writeToFile(outString, filePath, "\n"); + } catch (Exception e) { + LOGGER.info("e: " + e.getMessage()); + SystemUtils.halt(); + } + } + + public static String getRelativePath(File file, File folder) { + String filePath = file.getAbsolutePath(); + String folderPath = folder.getAbsolutePath(); + if (filePath.startsWith(folderPath)) { + return filePath.substring(folderPath.length() + 1); + } else { + return null; + } + } + + public static void clearFolder(String folderPath) { + ArrayList files = FilesUtils.getAllFilesInFolderAsList(folderPath); + for (String fileName: files) { + File f1 = new File(fileName); + if (f1.exists()) { + LOGGER.info("Deleting " + fileName); + boolean deleteStatus = f1.delete(); + if (deleteStatus) { + LOGGER.error("deleteStatus: " + deleteStatus); + } + } + } + } + + public static void removeMatchingRowsFromFileUNIX(String matchString, String filePath) throws Exception { + ArrayList keepers = new ArrayList(); + List allLines = readAllLinesFrom(filePath); + for (String s: allLines) { + if (s.contains(matchString)) { + // skip + } else { + if (s.equals("")) { + // skip + } else { + keepers.add(s); + } + + } + } + writeToFileUNIX(Joiner.on("\n").join(keepers), filePath); + } + + public static boolean moveFile(String sourcePath, String targetPath) { + boolean fileMoved = true; + try { + Files.move(Paths.get(sourcePath), Paths.get(targetPath), StandardCopyOption.REPLACE_EXISTING); + } catch (Exception e) { + fileMoved = false; + LOGGER.info("Exception: " + e.getMessage()); + } + return fileMoved; + } + + public static String findANDcreateMissingFoldersFor(String full_filepath) { + File f = new File(full_filepath); + String folderPath = f.getParent(); + String existingFolderPath = getExistingFileIfPossible(folderPath); + if ("".equals(existingFolderPath)) { + System.out.println("Folder " + folderPath + " does not exist, creating"); + File folder = new File(folderPath); + if (!folder.exists()) { + folder.mkdirs(); + } + return folder.getPath(); + } else { + return existingFolderPath; + } + + } + + public static void createFolderUnlessExists(String folderpath) { + File f = new File(folderpath); + f.mkdirs(); + } + +} diff --git a/src/main/java/crypto/forestfish/utils/FormatUtils.java b/src/main/java/crypto/forestfish/utils/FormatUtils.java new file mode 100644 index 0000000..fb482d8 --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/FormatUtils.java @@ -0,0 +1,41 @@ +package crypto.forestfish.utils; + +import java.math.BigInteger; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.web3j.abi.datatypes.generated.Uint256; + +public class FormatUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(FormatUtils.class); + + public static String convertUint256ToString(Uint256 param1) { + int nrHexCharacters = 0; + if (param1.getBitSize() == 256) nrHexCharacters = 64; + if (0 == nrHexCharacters) { + LOGGER.error("Unable to handle bitsize " + param1.getBitSize() + ". we no go with uint256 no moe? fixit."); + SystemUtils.halt(); + } + return StringsUtils.prefixStringWith0sToLengthN(param1.getValue().toString(), nrHexCharacters); + } + + public static String makeUINT256WithDec2Hex(int i) { + String hex = Integer.toHexString(i); + return StringsUtils.prefixStringWith0sToLengthN(hex, 64); // bitsize 256 = 64 hex chars + } + + public static String makeUINT256WithHex(String hex) { + return StringsUtils.prefixStringWith0sToLengthN(hex, 64); // bitsize 256 = 64 hex chars + } + + public static String makeUINT256WithDec2Hex(long i) { + String hex = Long.toHexString(i); + return StringsUtils.prefixStringWith0sToLengthN(hex, 64); // bitsize 256 = 64 hex chars + } + + public static String makeUINT256WithDec2Hex(BigInteger i) { + return StringsUtils.prefixStringWith0sToLengthN(i.toString(16), 64); // bitsize 256 = 64 hex chars + } + +} diff --git a/src/main/java/crypto/forestfish/utils/GraphQLUtils.java b/src/main/java/crypto/forestfish/utils/GraphQLUtils.java new file mode 100644 index 0000000..db75d9b --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/GraphQLUtils.java @@ -0,0 +1,95 @@ +package crypto.forestfish.utils; + +import java.util.HashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +import com.netflix.graphql.dgs.client.CustomMonoGraphQLClient; +import com.netflix.graphql.dgs.client.GraphQLResponse; +import com.netflix.graphql.dgs.client.HttpResponse; +import com.netflix.graphql.dgs.client.MonoGraphQLClient; + +import reactor.core.publisher.Mono; + +public class GraphQLUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(GraphQLUtils.class); + + public static Mono executeQuery(String url, String graphqlQuery, + HashMap queryArgs, Integer retryLimit, Integer sleepTimeInSecondsBetweenRetries) { + + int theGraphErrorCount = 0; + + while (theGraphErrorCount<=retryLimit) { + + if (theGraphErrorCount>0) { + LOGGER.info("Making GraphQL query towards " + url + ", theGraphErrorCount=" + theGraphErrorCount + ", retryLimit=" + retryLimit); + } else { + LOGGER.info("Making GraphQL query towards " + url); + } + + try { + CustomMonoGraphQLClient client = MonoGraphQLClient.createCustomReactive(url, (requestUrl, headers, body) -> { + HttpHeaders httpHeaders = new HttpHeaders(); + headers.forEach(httpHeaders::addAll); + RestTemplate restTemplate = new RestTemplate(); + int graphErrorCount = 0; + while (graphErrorCount<=retryLimit) { + try { + if (graphErrorCount>0) LOGGER.info("graphErrorCount: " + graphErrorCount); + ResponseEntity exchange = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(body, httpHeaders),String.class); + return Mono.just(new HttpResponse(exchange.getStatusCode().value(), exchange.getBody(), exchange.getHeaders())); + } catch (Exception e) { + if (e.getMessage().contains("504 Gateway Time-out")) { + LOGGER.warn("transitory exception: " + e.getMessage()); + SystemUtils.sleepInSeconds(sleepTimeInSecondsBetweenRetries); + graphErrorCount++; + } else if (e.getMessage().startsWith("522")) { + LOGGER.warn("transitory exception: " + e.getMessage()); + SystemUtils.sleepInSeconds(sleepTimeInSecondsBetweenRetries); + graphErrorCount++; + } else { + LOGGER.warn("unknown exception: " + e.getMessage()); + SystemUtils.sleepInSeconds(sleepTimeInSecondsBetweenRetries); + graphErrorCount++; + } + } + graphErrorCount++; + } + LOGGER.error("Unable to properly setup a session with \"theGraph\""); + return null; + }); + + // Abort unless we have a connection + if (null == client) { + LOGGER.error("Unable to properly setup a session with \"theGraph\""); + SystemUtils.halt(); + } + Mono graphQLResponse = client.reactiveExecuteQuery(graphqlQuery, queryArgs); + if (graphQLResponse.block().hasErrors()) { + theGraphErrorCount++; + } else { + return graphQLResponse; + } + + LOGGER.info("Hold on 5 secs .."); + SystemUtils.sleepInSeconds(5); + + } catch (Exception e) { + LOGGER.warn("Caught exception: " + e.getMessage()); + LOGGER.info("Hold on 5 secs .."); + SystemUtils.sleepInSeconds(5); + } + + } + + LOGGER.error("Unable to properly communicate with \"theGraph\""); + return null; + } +} diff --git a/src/main/java/crypto/forestfish/utils/HashUtils.java b/src/main/java/crypto/forestfish/utils/HashUtils.java new file mode 100644 index 0000000..10582e6 --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/HashUtils.java @@ -0,0 +1,50 @@ +package crypto.forestfish.utils; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.util.HashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HashUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(HashUtils.class); + + public static HashMap createKStringVbooleanHashMapListFromFile(final String filePath) { + HashMap hMap = new HashMap(); + File sigFile = new File(filePath); + if (!sigFile.exists()) { + LOGGER.error("Unable to find file " + filePath); + SystemUtils.halt(); + } + BufferedReader br; + try { + br = new BufferedReader(new FileReader(filePath)); + String line = null; + line = br.readLine(); + while (line != null) { + String key = line.replace("\n", "").replace("\r", ""); + if (false || + line.equals("") || + line.contains("#") || + false) { + line = br.readLine(); + continue; + } else if (null == hMap.get(key)) { + hMap.put(key, true); + line = br.readLine(); + } else { + line = br.readLine(); + } + } + br.close(); + } catch (Exception e) { + LOGGER.error("Caught exception while parsing file: " + e.getMessage()); + SystemUtils.halt(); + } + return hMap; + } + +} diff --git a/src/main/java/crypto/forestfish/utils/HttpRequestUtils.java b/src/main/java/crypto/forestfish/utils/HttpRequestUtils.java new file mode 100644 index 0000000..5cb2df4 --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/HttpRequestUtils.java @@ -0,0 +1,157 @@ +package crypto.forestfish.utils; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.ConnectException; +import java.net.URL; +import java.net.URLConnection; + +import org.jsoup.HttpStatusException; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HttpRequestUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(HttpRequestUtils.class); + + public static String getBodyUsingGETUrlRequest(String _url) { + try { + Document doc = Jsoup.connect(_url).ignoreContentType(true) + .get(); + String res = Jsoup.parse(doc.toString()).body().text(); + return res; + } catch (ConnectException ce) { + LOGGER.warn("Connection exception: " + ce.getMessage()); + } catch (HttpStatusException he) { + LOGGER.warn("HTTP status exception: " + he.getMessage()); + } catch (IOException e) { + LOGGER.warn("e: " + e.getMessage()); + LOGGER.warn("exception class: " + e.getClass()); + } + return ""; + } + + public static String getBodyUsingGETUrlRequestOpportunistic(String _url) { + try { + Document doc = Jsoup.connect(_url) + .timeout(10000) // 10 secs + .ignoreContentType(true). + get(); + String res = Jsoup.parse(doc.toString()).body().text(); + return res; + } catch (ConnectException ce) { + LOGGER.debug("Connection exception: " + ce.getMessage()); + } catch (HttpStatusException he) { + LOGGER.debug("HTTP status exception: " + he.getMessage()); + } catch (Exception e) { + LOGGER.debug("e: " + e.getMessage()); + } + return ""; + } + + public static byte[] downloadImage(String _imageUrl) { + try { + URL url = new URL(_imageUrl); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + + URLConnection connection = url.openConnection(); + connection.setConnectTimeout(10000); // 10 secs + + try (InputStream stream = connection.getInputStream()) { + byte[] buffer = new byte[4096]; + while (true) { + int bytesRead = stream.read(buffer); + if (bytesRead < 0) { break; } + output.write(buffer, 0, bytesRead); + } + return output.toByteArray(); + } + } catch (Exception e) { + LOGGER.warn("e: " + e.getMessage()); + LOGGER.warn("exception class: " + e.getClass()); + } + + return null; + } + + public static String getBodyUsingGETUrlRequestWithCustomHeader(String _url, String _customHeaderName, String _customHeaderValue) { + try { + Document doc = Jsoup.connect(_url) + .ignoreContentType(true) + .header(_customHeaderName, _customHeaderValue) + .get(); + String res = Jsoup.parse(doc.toString()).body().text(); + return res; + } catch (ConnectException ce) { + LOGGER.warn("Connection exception: " + ce.getMessage()); + } catch (HttpStatusException he) { + LOGGER.warn("HTTP status exception: " + he.getMessage()); + } catch (IOException e) { + LOGGER.warn("e: " + e.getMessage()); + LOGGER.warn("exception class: " + e.getClass()); + } + return ""; + } + + public static String getBodyUsingGETUrlRequestAndJWTToken(String _url, String _jwtToken) { + try { + Document doc = Jsoup.connect(_url) + .header("Authorization", "Bearer " + _jwtToken) + .ignoreContentType(true) + .get(); + String res = Jsoup.parse(doc.toString()).body().text(); + return res; + } catch (ConnectException ce) { + LOGGER.warn("Connection exception: " + ce.getMessage()); + } catch (HttpStatusException he) { + LOGGER.warn("HTTP status exception: " + he.getMessage()); + } catch (IOException e) { + LOGGER.warn("e: " + e.getMessage()); + LOGGER.warn("exception class: " + e.getClass()); + } + return ""; + } + + public static String getBodyUsingUrlPOSTRequestWithJsonBody(String _url, String _jsonBody) { + try { + Document doc = Jsoup.connect(_url).ignoreContentType(true) + .requestBody(_jsonBody) + .header("Content-Type", "application/json") + .post(); + String res = Jsoup.parse(doc.toString()).body().text(); + return res; + } catch (ConnectException ce) { + LOGGER.warn("Connection exception: " + ce.getMessage()); + } catch (HttpStatusException he) { + LOGGER.warn("HTTP status exception: " + he.getMessage()); + } catch (IOException e) { + LOGGER.warn("e: " + e.getMessage()); + LOGGER.warn("exception class: " + e.getClass()); + } + return ""; + } + + public static String getBodyUsingUrlPOSTRequestWithJsonBodyAndHeader(String _url, String jsonBody, String _customHeaderName, String _customHeaderValue) { + try { + Document doc = Jsoup.connect(_url).ignoreContentType(true) + .requestBody(jsonBody) + .header("Content-Type", "application/json") + .header(_customHeaderName, _customHeaderValue) + .post(); + String res = Jsoup.parse(doc.toString()).body().text(); + return res; + } catch (ConnectException ce) { + LOGGER.warn("Connection exception: " + ce.getMessage()); + } catch (HttpStatusException he) { + LOGGER.warn("HTTP status exception: " + he.getMessage()); + } catch (IOException e) { + LOGGER.warn("e: " + e.getMessage()); + LOGGER.warn("exception class: " + e.getClass()); + } + return ""; + } + +} diff --git a/src/main/java/crypto/forestfish/utils/IPFSUtils.java b/src/main/java/crypto/forestfish/utils/IPFSUtils.java new file mode 100644 index 0000000..a8428a3 --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/IPFSUtils.java @@ -0,0 +1,98 @@ +package crypto.forestfish.utils; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import crypto.forestfish.objects.ipfs.IPFSNode; +import io.ipfs.api.IPFS; +import io.ipfs.api.MerkleNode; +import io.ipfs.api.NamedStreamable; +import io.ipfs.multihash.Multihash; + +public class IPFSUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(IPFSUtils.class); + + public static String readUTF8TextFileFromIPFS(IPFSNode ipfs_node, String base58Hash) { + IPFS ipfs = new IPFS(ipfs_node.getApi_address()); + try { + Multihash filePointer = Multihash.fromBase58(base58Hash); + byte[] fileContents = ipfs.cat(filePointer); + LOGGER.info("just read " + fileContents.length + " bytes"); + String s2 = new String(fileContents, StandardCharsets.UTF_8); + return s2; + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + public static void readFileFromIPFS(IPFSNode ipfs_node, String base58Hash, File targetFile) { + IPFS ipfs = new IPFS(ipfs_node.getApi_address()); + try { + Multihash filePointer = Multihash.fromBase58(base58Hash); + byte[] fileContents = ipfs.cat(filePointer); + + try (FileOutputStream fos = new FileOutputStream(targetFile.getAbsolutePath())) { + fos.write(fileContents); + } + + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static String writeFileToIPFS(IPFSNode ipfs_node, File f) { + IPFS ipfs = new IPFS(ipfs_node.getApi_address()); + try { + NamedStreamable.FileWrapper file = new NamedStreamable.FileWrapper(f); + MerkleNode addResult = ipfs.add(file).get(0); + Multihash pointer = addResult.hash; + LOGGER.info("Wrote " + f.getName() + " to IPFS with BASE58 file hash: " + pointer.toBase58()); + return pointer.toBase58(); + + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + public static void printIPFSNodeInfo(IPFSNode ipfs_node) { + try { + IPFS ipfs = new IPFS(ipfs_node.getApi_address()); + System.out.println("IPFS node version: " + ipfs.version()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static String extractCIDFromURL(String _ipfsUrl) { + if (null == _ipfsUrl) return ""; + if (!_ipfsUrl.contains("/ipfs/")) return ""; + try { + String cid = _ipfsUrl.split("/ipfs/")[1].split("[^a-zA-Z0-9']+")[0]; + if (isValidCIDV0(cid) || isValidCIDV1(cid)) return cid; + } catch (Exception e) { + return ""; + } + return ""; + } + + public static boolean isValidCIDV0(String s) { + if (null == s) return false; + if (!s.startsWith("Qm")) return false; + if (!StringsUtils.isValidBase58(s)) return false; + return s.matches("^[a-zA-Z0-9]{46}$"); + } + + public static boolean isValidCIDV1(String s) { + if (null == s) return false; + return s.matches("^[a-zA-Z0-9]{59}$"); // base can vary, first char for base32 'b' + } + +} diff --git a/src/main/java/crypto/forestfish/utils/JSONUtils.java b/src/main/java/crypto/forestfish/utils/JSONUtils.java new file mode 100644 index 0000000..87fe2cb --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/JSONUtils.java @@ -0,0 +1,194 @@ +package crypto.forestfish.utils; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import crypto.forestfish.objects.evm.model.solidity.ABIFunctionEntry; +import crypto.forestfish.objects.evm.moralis.MoralisERC20ContractMetaInfo; +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.reflect.TypeToken; + +public class JSONUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(JSONUtils.class); + + @SuppressWarnings("unchecked") + public static String getFunctionJSONUsingABI(String jsonSTR, String functionName) { + String result = ""; + Type type = new TypeToken>() {}.getType(); + Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + ArrayList data = gson.fromJson(jsonSTR, type); + for (Object obj: data) { + Map abiEntry = (Map) obj; + String fName = (String) abiEntry.get("name"); + if (null != fName) { + String entry_type = (String) abiEntry.get("type"); + if (null != entry_type) { + if (fName.equals(functionName)) { + if ("function".equals(entry_type)) { + //System.out.println("obj: " + obj.toString()); + result = gson.toJson(obj); + } + } + } + } + } + return result; + } + + @SuppressWarnings("unchecked") + public static HashMap getFunctionNamesOfABIJSON(String jsonSTR) { + HashMap functions = new HashMap<>(); + // Sanity check + if (!jsonSTR.startsWith("[")) { + LOGGER.error("ABI JSON needs to be an array (start with '[')"); + System.out.println("ABI JSON:"); + System.out.println(jsonSTR); + SystemUtils.halt(); + } + try { + Type type = new TypeToken>() {}.getType(); + Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + ArrayList data = gson.fromJson(jsonSTR, type); + for (Object obj: data) { + Map abiEntry = (Map) obj; + String fName = (String) abiEntry.get("name"); + String entry_type = (String) abiEntry.get("type"); + if (fName != null) { + if ("function".equals(entry_type)) { + functions.put(fName, true); + } + } + } + } catch (Exception e) { + LOGGER.error("getFunctionNamesOfABIJSON() exception: " + e.getMessage()); + System.out.println("ABI JSON:"); + System.out.println(jsonSTR); + SystemUtils.halt(); + } + return functions; + } + + @SuppressWarnings("unchecked") + public static HashMap getFunctionsOfABIJSON(String jsonSTR) { + HashMap functions = new HashMap<>(); + Type type = new TypeToken>() {}.getType(); + Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + ArrayList data = gson.fromJson(jsonSTR, type); + for (Object obj: data) { + Map abiEntry = (Map) obj; + String fName = (String) abiEntry.get("name"); + String entry_type = (String) abiEntry.get("type"); + if (fName != null) { + if ("function".equals(entry_type)) { + String result = gson.toJson(obj); + ABIFunctionEntry abiE = JSONUtils.createPOJOFromJSON(result, ABIFunctionEntry.class); + if (abiE == null) { + System.out.println("Unable to properly parse ABI json: " + jsonSTR); + SystemUtils.halt(); + } + functions.put(abiE, true); + } + } + } + return functions; + } + + public static T createPOJOFromJSON(final String jsonSTR, Class valueType) { + ObjectMapper mapper = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + T pojo = null; + try { + pojo = mapper.readValue(jsonSTR, valueType); + } catch (JsonParseException e) { + LOGGER.error("Unable to parse JSON: " + e.getClass() + ": " + e.getMessage(), e); + LOGGER.error("JSON string for above error: " + jsonSTR); + } catch (JsonMappingException e) { + LOGGER.error("Unable to map JSON: " + e.getClass() + ": " + e.getMessage(), e); + LOGGER.error("JSON string for above error: " + jsonSTR); + } catch (IOException e) { + LOGGER.error("IO exception during JSON parsing: " + e.getClass() + ": " + e.getMessage(), e); + LOGGER.error("JSON string for above error: " + jsonSTR); + } + return pojo; + } + + public static String compactPrint(final String jsonSTR) { + try { + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode jsonNode = objectMapper.readValue(jsonSTR, JsonNode.class); + return(jsonNode.toString()); + } catch (Exception e) { + LOGGER.error("Unable to JSON parse string with GSON"); + } + return jsonSTR; + } + + public static String prettyPrint(final String jsonSTR) { + try { + Gson gson = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create(); + JsonObject jobject = JsonParser.parseString(jsonSTR).getAsJsonObject(); + return gson.toJson(jobject); + } catch (Exception e) { + System.out.println("JSON: " + jsonSTR); + LOGGER.error("Unable to JSON parse string with GSON"); + } + return jsonSTR; + } + + public static String createJSONFromPOJO(Object o) { + String jsonString = ""; + try { + jsonString = JSON.toJSONString(o); + } catch (Exception e) { + LOGGER.error("Exception during JSON parsing: " + e.getClass() + ": " + e.getMessage(), e); + } + return jsonString; + } + + public static ArrayList createFromMoralisERC20ContractQueryFromJSON(String str) { + ArrayList oo = new ArrayList(); + try { + JSONArray jsonArray = JSON.parseArray(str); + for(int i=0;i getKeyNamesOfJSON(String jsonSTR) { + ArrayList keys = new ArrayList(); + JsonObject jobject = JsonParser.parseString(jsonSTR).getAsJsonObject(); + Set> entries = jobject.entrySet(); + for(Map.Entry entry: entries) { + keys.add(entry.getKey()); + } + return keys; + } + +} diff --git a/src/main/java/crypto/forestfish/utils/JWTUtils.java b/src/main/java/crypto/forestfish/utils/JWTUtils.java new file mode 100644 index 0000000..f40d1bc --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/JWTUtils.java @@ -0,0 +1,314 @@ +package crypto.forestfish.utils; + +import java.math.BigInteger; +import java.security.Key; +import java.security.PublicKey; +import java.security.Signature; +import java.util.ArrayList; +import java.util.Base64; +import java.util.HashMap; + +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.RSAPublicKeySpec; +import java.security.*; + +import javax.crypto.spec.SecretKeySpec; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import crypto.forestfish.objects.jwt.JWK; +import crypto.forestfish.objects.jwt.JWKS; +import crypto.forestfish.objects.jwt.JWTSignedDecodeResult; +import crypto.forestfish.objects.jwt.JWTUnsignedDecodeResult; +import crypto.forestfish.objects.jwt.PrivateClaims; +import crypto.forestfish.objects.jwt.PublicClaims; +import crypto.forestfish.objects.jwt.RegisteredClaims; +import crypto.forestfish.objects.jwt.TokenType; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; +import io.jsonwebtoken.Jwts; + +public class JWTUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(JWTUtils.class); + + public static JWTSignedDecodeResult decodeAndVerifyJWTUsingSecretKey(String jwtString, String jwt_secret, String jcaName) { + + boolean invalid_jwt = false; + boolean signature_valid = false; + boolean expired = true; + String token_type_str = TokenType.AUTHN.toString(); + RegisteredClaims registered_claims = new RegisteredClaims(); + PublicClaims public_claims = new PublicClaims(); + PrivateClaims private_claims = new PrivateClaims(); + + // Early exit for invalid JWT string + int splitcount = jwtString.split("\\.").length; + if (splitcount != 3) { + invalid_jwt = true; + return new JWTSignedDecodeResult(invalid_jwt, signature_valid, expired, registered_claims, public_claims, private_claims, token_type_str); + } + + // Decode signed JWT + try { + Key hmacKey = new SecretKeySpec(Base64.getDecoder().decode(jwt_secret), jcaName); + + Jws jwt = Jwts.parserBuilder() + .setSigningKey(hmacKey) + .build() + .parseClaimsJws(jwtString); + LOGGER.debug("claims: " + jwt.toString()); + + HashMap erc20_ownership = new HashMap<>(); + HashMap nft_ownership = new HashMap<>(); + + // header DEBUG + for (String claim: jwt.getBody().keySet()) { + Object val = jwt.getBody().get(claim); + LOGGER.debug(" -> claim=" + claim + " val=" + val.toString() + " class=" + val.getClass()); + + // Registered + if ("iat".equals(claim) && val.getClass().equals(Integer.class)) registered_claims.setIat((Integer) val); + if ("exp".equals(claim) && val.getClass().equals(Integer.class)) registered_claims.setExp((Integer) val); + if ("nbf".equals(claim) && val.getClass().equals(Integer.class)) registered_claims.setNbf((Integer) val); + if ("jti".equals(claim) && val.getClass().equals(String.class)) registered_claims.setJti((String) val); + if ("sub".equals(claim) && val.getClass().equals(String.class)) registered_claims.setSub((String) val); + if ("iss".equals(claim) && val.getClass().equals(String.class)) registered_claims.setIss((String) val); + if ("aud".equals(claim) && val.getClass().equals(String.class)) registered_claims.setAud((String) val); + + // Public + if ("family_name".equals(claim) && val.getClass().equals(String.class)) public_claims.setFamily_name((String) val); + if ("given_name".equals(claim) && val.getClass().equals(String.class)) public_claims.setGiven_name((String) val); + if ("nonce".equals(claim) && val.getClass().equals(String.class)) public_claims.setNonce((String) val); + + // Private + if ("evm_wallet_address".equals(claim) && val.getClass().equals(String.class)) private_claims.setEvm_wallet_address((String) val); // forestfishd + if ("token_type".equals(claim) && val.getClass().equals(String.class)) { + private_claims.setToken_type((String) val); // AUTHN/AUTHZ + token_type_str = (String) val; + } + if ("role".equals(claim) && val.getClass().equals(String.class)) private_claims.setRole((String) val); // ADMIN/CONSUMER/CONTRIBUTOR + if ("oid".equals(claim) && val.getClass().equals(String.class)) private_claims.setOid((String) val); // azure + if ("azp".equals(claim) && val.getClass().equals(String.class)) private_claims.setAzp((String) val); // azure + if ("ver".equals(claim) && val.getClass().equals(String.class)) private_claims.setVer((String) val); // azure + + if (claim.startsWith("erc20_ownership:")) { + erc20_ownership.put(claim.replace("erc20_ownership:", ""), (String) val); + } + + if (claim.startsWith("nft_ownership:")) { + nft_ownership.put(claim.replace("nft_ownership:", ""), (String) val); + } + } + private_claims.setErc20_ownership(erc20_ownership); + private_claims.setNft_ownership(nft_ownership); + + // Check expiration date + Integer exp = (Integer) jwt.getBody().get("exp"); + Long currentTimeSeconds = System.currentTimeMillis()/1000L; + if (currentTimeSeconds.intValue() < exp) expired = false; + + // we throw if signature is invalid + signature_valid = true; + + } catch (Exception e) { + if (false || + e.getMessage().contains("JWT signature does not match locally computed signature") || + e.getMessage().contains("Last unit does not have enough valid bits") || + false) { + LOGGER.warn("Invalid JWT token signature, exception: " + e.getMessage()); + } else { + LOGGER.warn("Unable to deconstruct JWT token, unknown exception: " + e.getMessage()); + } + } + + return new JWTSignedDecodeResult(invalid_jwt, signature_valid, expired, registered_claims, public_claims, private_claims, token_type_str); + + } + + public static PublicKey getPublicKey(String modulus, String exponent) { + try { + byte exponentB[] = Base64.getUrlDecoder().decode(exponent); + byte modulusB[] = Base64.getUrlDecoder().decode(modulus); + BigInteger bigExponent = new BigInteger(1,exponentB); + BigInteger bigModulus = new BigInteger(1,modulusB); + + PublicKey publicKey; + publicKey = KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(bigModulus, bigExponent)); + + return publicKey; + + } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { + LOGGER.warn("Caught exception: " + e.getMessage()); + } + return null; + } + + public static JWTSignedDecodeResult decodeAndVerifyJWTUsingJWKS(String jwtString, JWKS jwks) { + boolean invalid_jwt = false; + boolean signature_valid = false; + boolean expired = true; + String token_type_str = TokenType.AUTHN.toString(); + RegisteredClaims registered_claims = new RegisteredClaims(); + PublicClaims public_claims = new PublicClaims(); + PrivateClaims private_claims = new PrivateClaims(); + + // Early exit for invalid JWT string + int splitcount = jwtString.split("\\.").length; + if (splitcount != 3) { + invalid_jwt = true; + return new JWTSignedDecodeResult(invalid_jwt, signature_valid, expired, registered_claims, public_claims, private_claims, token_type_str); + } + + for (JWK jwk: jwks.getKeys()) { + + System.out.println("Checking public key " + jwk.getKid()); + String modulus = jwk.getN(); + String exponent = jwk.getE(); + + try { + PublicKey pubKey = getPublicKey(modulus, exponent); + + // Verify signature + String signedData = jwtString.substring(0, jwtString.lastIndexOf(".")); + String signatureB64u = jwtString.substring(jwtString.lastIndexOf(".")+1,jwtString.length()); + byte signature[] = Base64.getUrlDecoder().decode(signatureB64u); + + boolean isVerify = false; + if ("RSA".equals(jwk.getKty())) { + Signature sig = Signature.getInstance("SHA256withRSA"); + sig.initVerify(pubKey); + sig.update(signedData.getBytes()); + isVerify = sig.verify(signature); + + LOGGER.info("pub key " + jwk.getKid() + " verification: " + isVerify); + + if (isVerify) { + + // Lets populate the claims since this signature was good + Jws jwt = Jwts.parserBuilder() + .setSigningKey(pubKey) + .build() + .parseClaimsJws(jwtString); + System.out.println("claims: " + jwt.toString()); + + // header DEBUG + for (String claim: jwt.getBody().keySet()) { + Object val = jwt.getBody().get(claim); + System.out.println(" -> claim=" + claim + " val=" + val.toString() + " class=" + val.getClass()); + + // Registered + if ("iat".equals(claim) && val.getClass().equals(Integer.class)) registered_claims.setIat((Integer) val); + if ("exp".equals(claim) && val.getClass().equals(Integer.class)) registered_claims.setExp((Integer) val); + if ("nbf".equals(claim) && val.getClass().equals(Integer.class)) registered_claims.setNbf((Integer) val); + if ("jti".equals(claim) && val.getClass().equals(String.class)) registered_claims.setJti((String) val); + if ("sub".equals(claim) && val.getClass().equals(String.class)) registered_claims.setSub((String) val); + if ("iss".equals(claim) && val.getClass().equals(String.class)) registered_claims.setIss((String) val); + if ("aud".equals(claim) && val.getClass().equals(String.class)) registered_claims.setAud((String) val); + + // Public + if ("family_name".equals(claim) && val.getClass().equals(String.class)) public_claims.setFamily_name((String) val); + if ("given_name".equals(claim) && val.getClass().equals(String.class)) public_claims.setGiven_name((String) val); + if ("nonce".equals(claim) && val.getClass().equals(String.class)) public_claims.setNonce((String) val); + + // Private + if ("evm_wallet_address".equals(claim) && val.getClass().equals(String.class)) private_claims.setEvm_wallet_address((String) val); // forestfishd + if ("token_type".equals(claim) && val.getClass().equals(String.class)) { + private_claims.setToken_type((String) val); // AUTHN/AUTHZ + token_type_str = (String) val; + } + if ("role".equals(claim) && val.getClass().equals(String.class)) private_claims.setRole((String) val); // ADMIN/CONSUMER/CONTRIBUTOR + if ("oid".equals(claim) && val.getClass().equals(String.class)) private_claims.setOid((String) val); // azure + if ("azp".equals(claim) && val.getClass().equals(String.class)) private_claims.setAzp((String) val); // azure + if ("ver".equals(claim) && val.getClass().equals(String.class)) private_claims.setVer((String) val); // azure + if ("emails".equals(claim)) { + @SuppressWarnings("unchecked") + ArrayList valcasted = (ArrayList) val; + private_claims.setEmails(valcasted); + } + + } + + // Check expiration date + Integer exp = (Integer) jwt.getBody().get("exp"); + Long currentTimeSeconds = System.currentTimeMillis()/1000L; + if (currentTimeSeconds.intValue() < exp) expired = false; + + // we throw if signature is invalid + signature_valid = true; + + return new JWTSignedDecodeResult(invalid_jwt, signature_valid, expired, registered_claims, public_claims, private_claims, token_type_str); + + } + + } else { + LOGGER.warn("Skipping public key " + jwk.getKid() + " since cannot handle kty " + jwk.getKty()); + } + + } catch (Exception e) { + LOGGER.warn("Caught exceptiono: " + e.getMessage()); + } + + } + + return new JWTSignedDecodeResult(invalid_jwt, signature_valid, expired, registered_claims, public_claims, private_claims, token_type_str); + } + + public static JWTUnsignedDecodeResult decodeJWT(String jwtString) { + boolean invalid_jwt = false; + + // Early exit for invalid JWT string + int splitcount = jwtString.split("\\.").length; + if (splitcount != 3) { + invalid_jwt = true; + return new JWTUnsignedDecodeResult(true, "", "", "", ""); + } + + String[] chunks = jwtString.split("\\."); + Base64.Decoder decoder = Base64.getUrlDecoder(); + String payload = new String(decoder.decode(chunks[1])); + + /** + * Header + */ + String alg = ""; + String typ = ""; + try { + String header = new String(decoder.decode(chunks[0])); + JsonObject jobject = JsonParser.parseString(header).getAsJsonObject(); + if (null != jobject.get("alg")) alg = jobject.get("alg").getAsString(); + if (null != jobject.get("typ")) typ = jobject.get("typ").getAsString(); + } catch (Exception e) { + LOGGER.warn("Caught exception while parsing header: " + e.getMessage()); + } + + /** + * Payload + */ + String iss = "unknown"; + try { + JsonObject jobject = JsonParser.parseString(payload).getAsJsonObject(); + if (null != jobject.get("iss")) iss = jobject.get("iss").getAsString(); + } catch (Exception e) { + LOGGER.warn("Caught exception while parsing header: " + e.getMessage()); + } + + return new JWTUnsignedDecodeResult(invalid_jwt, typ, alg, iss, payload); + } + + public static JWTSignedDecodeResult decodeAndVerifyJWTUsingAzureB2C(String jwtString, String b2ctenant, String b2cflow) { + String jsonRESP = HttpRequestUtils.getBodyUsingGETUrlRequest("https://" + b2ctenant + ".b2clogin.com/" + b2ctenant + ".onmicrosoft.com/" + b2cflow + "/discovery/v2.0/keys"); + if (jsonRESP.length() > 10) { + JWKS jwks = JSONUtils.createPOJOFromJSON(jsonRESP, JWKS.class); + JWTSignedDecodeResult jwt_decoded_result = JWTUtils.decodeAndVerifyJWTUsingJWKS(jwtString, jwks); + return jwt_decoded_result; + } + return null; + } + +} diff --git a/src/main/java/crypto/forestfish/utils/MoralisUtils.java b/src/main/java/crypto/forestfish/utils/MoralisUtils.java new file mode 100644 index 0000000..8fbb9d6 --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/MoralisUtils.java @@ -0,0 +1,91 @@ +package crypto.forestfish.utils; + +import java.util.ArrayList; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import crypto.forestfish.objects.evm.moralis.MoralisERC20ContractPriceInfo; +import crypto.forestfish.enums.evm.EVMChain; +import crypto.forestfish.objects.evm.moralis.MoralisERC20ContractMetaInfo; + +public class MoralisUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(MoralisUtils.class); + + public static String mapEVMChainToMoralisChainAlias(EVMChain chain) { + String chainAlias; + switch (chain) { + case ETHEREUM: chainAlias = "eth"; + break; + case POLYGON: chainAlias = "polygon"; + break; + case ROPSTENTEST: chainAlias = "ropsten"; + break; + case RINKEBYTEST: chainAlias = "rinkeby"; + break; + case GOERLITEST: chainAlias = "goerli"; + break; + case KOVANTEST: chainAlias = "kovan"; + break; + case MUMBAITEST: chainAlias = "mumbai"; + break; + case BSC: chainAlias = "bsc"; + break; + case AVAX: chainAlias = "avalanche"; + break; + case FANTOM: chainAlias = "fantom"; + break; + case CRONOS: chainAlias = "cronos"; + break; + default: chainAlias = null; + LOGGER.warn("Unable to find Moralis mapping for chain " + chain); + break; + } + return chainAlias; + } + + public static MoralisERC20ContractMetaInfo getMoralisERC20ContractInfo(EVMChain chain, String erc20_address, String moralis_api_key) { + final String baseURL = "https://deep-index.moralis.io/api/v2/erc20/metadata?"; + final String moralis_api_key_header = "X-API-Key"; + try { + String chainMoralisAlias = MoralisUtils.mapEVMChainToMoralisChainAlias(chain); + if (null != chainMoralisAlias) { + String requestSTR = baseURL + + "chain=" + chainMoralisAlias + + "&addresses=" + erc20_address; + String res = HttpRequestUtils.getBodyUsingGETUrlRequestWithCustomHeader(requestSTR, moralis_api_key_header, moralis_api_key); + ArrayList repArr = JSONUtils.createFromMoralisERC20ContractQueryFromJSON(res); + if (repArr.size() == 0) { + return null; + } else if (repArr.size() == 1) { + return repArr.get(0); + } else if (repArr.size() > 1) { + return null; + } + } + } catch (Exception e) { + LOGGER.warn("Exception: " + e.getMessage()); + } + return null; + } + + public static MoralisERC20ContractPriceInfo getMoralisERC20ContractPriceInfo(EVMChain chain, String erc20_address, String moralis_api_key) { + final String baseURL = "https://deep-index.moralis.io/api/v2/erc20/" + erc20_address + "/price?"; + final String moralis_api_key_header = "X-API-Key"; + try { + String chainMoralisAlias = MoralisUtils.mapEVMChainToMoralisChainAlias(chain); + if (null != chainMoralisAlias) { + String requestSTR = baseURL + + "chain=" + chainMoralisAlias; + String res = HttpRequestUtils.getBodyUsingGETUrlRequestWithCustomHeader(requestSTR, moralis_api_key_header, moralis_api_key); + MoralisERC20ContractPriceInfo rep = JSONUtils.createPOJOFromJSON(res, MoralisERC20ContractPriceInfo.class); + return rep; + } + } catch (Exception e) { + LOGGER.warn("Exception: " + e.getMessage()); + } + return null; + } + +} diff --git a/src/main/java/crypto/forestfish/utils/NFTUtils.java b/src/main/java/crypto/forestfish/utils/NFTUtils.java new file mode 100644 index 0000000..0eff55f --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/NFTUtils.java @@ -0,0 +1,281 @@ +package crypto.forestfish.utils; + +import java.io.File; +import java.util.HashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import crypto.forestfish.enums.avm.AVMNFTStandard; +import crypto.forestfish.objects.avm.model.nft.metadata.ARC3MetaData; +import crypto.forestfish.objects.avm.model.nft.metadata.ARC69ARC19MetaData; +import crypto.forestfish.objects.evm.model.nft.metadata.ERC721MetaData; +import crypto.forestfish.objects.evm.model.nft.metadata.OpenSeaTrait; +import crypto.forestfish.objects.ipfs.connector.IPFSConnector; + +public class NFTUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(ContractMapper.class); + + public static ARC69ARC19MetaData convertMetadata_ERC721_to_ARC69(IPFSConnector _ipfs_connector, ERC721MetaData erc721metadata) { + + /** + * ARC69 base metadata + */ + String name = erc721metadata.getName(); + String description = erc721metadata.getDescription(); + + @SuppressWarnings("unused") + Integer decimals = null; // Assume ERC721 not fractional, but optional in the metadata + String background_color = erc721metadata.getBackground_color(); + + String image = erc721metadata.getImage(); + String external_url = erc721metadata.getExternal_url(); + String animation_url = erc721metadata.getAnimation_url(); + String image_data = erc721metadata.getImage_data(); + + //ArrayList attributes = erc721metadata.getAttributes(); // we need to get below 1024, using properties instead + + ARC69ARC19MetaData arc69_metadata = new ARC69ARC19MetaData(); + arc69_metadata.setName(name); + arc69_metadata.setDescription(description); + arc69_metadata.setBackground_color(background_color); + arc69_metadata.setImage(image); + arc69_metadata.setExternal_url(external_url); + arc69_metadata.setAnimation_url(animation_url); + //arc69_metadata.setAttributes(attributes); // we need to get below 1024, using properties instead + arc69_metadata.setImage_data(image_data); + + // attempt to convert ERC721 attributes to properties + if (null != erc721metadata.getAttributes()) { + HashMap properties = new HashMap<>(); + for (OpenSeaTrait ost: erc721metadata.getAttributes()) { + properties.put(ost.getTrait_type(), ost.getValue()); + + } + arc69_metadata.setProperties(properties); + } + + return arc69_metadata; + } + + public static ARC3MetaData convertMetadata_ERC721_to_ARC3(IPFSConnector _ipfs_connector, ERC721MetaData erc721metadata) { + + /** + * ARC3 base metadata + */ + String name = erc721metadata.getName(); + String description = erc721metadata.getDescription(); + + Integer decimals = null; // Assume ERC721 not fractional, but optional in the metadata + String background_color = erc721metadata.getBackground_color(); + + String image = erc721metadata.getImage(); + String external_url = erc721metadata.getExternal_url(); + String animation_url = erc721metadata.getAnimation_url(); + String image_data = erc721metadata.getImage_data(); + + HashMap properties_empty = new HashMap<>(); + + ARC3MetaData arc3_metadata = new ARC3MetaData(name, description, decimals, background_color, image, external_url, animation_url, properties_empty); + arc3_metadata.setImage_data(image_data); + + // image properties + if ((null != image) && isSupportedURISchema(image)) { + + // add image mimetype + String image_mimetype = determine_mimetype_from_ext(image); + if (null != image_mimetype) arc3_metadata.setImage_data_mimetype(image_mimetype); + + // download the image and calculate integrity field (base64 of sha256) + byte[] image_bytes = _ipfs_connector.getBinaryContent(arc3_metadata.getImage()); + byte[] image_sha256 = CryptUtils.calculateSHA256FromByteArray(image_bytes); + String image_sha256_base64 = StringsUtils.encodeBytesToBase64(image_sha256); + if (null != image_sha256_base64) arc3_metadata.setImage_data_integrity("sha256-" + image_sha256_base64); + } + + // animation_url properties + if ((null != animation_url) && isSupportedURISchema(animation_url)) { + + // add animation_url mimetype + String animation_url_mimetype = determine_mimetype_from_ext(animation_url); + if (null != animation_url_mimetype) arc3_metadata.setAnimation_url_mimetype(animation_url_mimetype); + + // download the animation_url and calculate integrity field (base64 of sha256) + byte[] animation_url_bytes = _ipfs_connector.getBinaryContent(arc3_metadata.getAnimation_url()); + byte[] animation_url_sha256 = CryptUtils.calculateSHA256FromByteArray(animation_url_bytes); + String animation_url_sha256_base64 = StringsUtils.encodeBytesToBase64(animation_url_sha256); + if (null != animation_url_sha256_base64) arc3_metadata.setAnimation_url_integrity("sha256-" + animation_url_sha256_base64); + } + + // external_url properties + if ((null != external_url) && isSupportedURISchema(external_url)) { + + // add external_url mimetype + String external_url_mimetype = determine_mimetype_from_ext(external_url); + if (null != external_url_mimetype) arc3_metadata.setExternal_url_mimetype(external_url_mimetype); + + // download the animation_url and calculate integrity field (base64 of sha256) + byte[] external_url_bytes = _ipfs_connector.getBinaryContent(arc3_metadata.getExternal_url()); + byte[] external_url_sha256 = CryptUtils.calculateSHA256FromByteArray(external_url_bytes); + String external_url_sha256_base64 = StringsUtils.encodeBytesToBase64(external_url_sha256); + if (null != external_url_sha256_base64) arc3_metadata.setExternal_url_integrity("sha256-" + external_url_sha256_base64); + } + + // attempt to convert ERC721 attributes to properties + if (null != erc721metadata.getAttributes()) { + HashMap properties = new HashMap<>(); + for (OpenSeaTrait ost: erc721metadata.getAttributes()) { + properties.put(ost.getTrait_type(), ost.getValue()); + + } + arc3_metadata.setProperties(properties); + } + + return arc3_metadata; + } + + private static boolean isSupportedURISchema(String _str) { + if (_str.startsWith("http://")) return true; + if (_str.startsWith("https://")) return true; + if (_str.startsWith("ipfs://")) return true; + return false; + } + + public static String determine_mimetype_from_ext(String _str) { + + // image + if (_str.endsWith(".png")) return "image/png"; + if (_str.endsWith(".jpg")) return "image/jpeg"; + if (_str.endsWith(".jpeg")) return "image/jpeg"; + + // audio + if (_str.endsWith(".ogg")) return "audio/ogg"; + + // video + if (_str.endsWith(".mp4")) return "video/mp4"; + + return null; + } + + public static boolean convertERC721MetadataFolderToARC(IPFSConnector _ipfs_connector, String _from_folder, String _to_folder, AVMNFTStandard _standard, boolean _debug) { + + boolean result = true; + + // initial sanity checks + File from_folder_file = new File (_from_folder); + if (!from_folder_file.exists()) return false; + File to_folder_file = new File (_to_folder); + if (!to_folder_file.exists()) { + if (!to_folder_file.mkdirs()) { + LOGGER.error("Target folder " + _to_folder + " did not exist and was unable to create it"); + SystemUtils.halt(); + } + } + + for (File from_file: FilesUtils.getAllFileNamesInFolderAsFiles(_from_folder)) { + if (from_file.getName().endsWith(".json")) { + + // read the erc721 metadata + String erc721_json = FilesUtils.readAllFromFile(from_file); + System.out.println("------------------------ ERC721 metadata ------------------------"); + System.out.println(JSONUtils.prettyPrint(erc721_json)); + System.out.println("-----------------------------------------------------------------"); + + + // parse the erc721 metadata + ERC721MetaData erc721_metadata = JSONUtils.createPOJOFromJSON(erc721_json, ERC721MetaData.class); + if (_debug) { + System.out.println("------------------------ ERC721 metadata ------------------------"); + System.out.println("name: " + erc721_metadata.getName()); + System.out.println("description: " + erc721_metadata.getDescription()); + System.out.println("external_url: " + erc721_metadata.getExternal_url()); + if (null != erc721_metadata.getAttributes()) { + for (OpenSeaTrait ost: erc721_metadata.getAttributes()) { + System.out.println(" - attribute: trait_type=" + ost.getTrait_type() + " value=" + ost.getValue()); + } + } + System.out.println("-----------------------------------------------------------------"); + } + + // convert the erc721 metadata to arc3 + if (AVMNFTStandard.ARC3 == _standard) { + ARC3MetaData arc3_metadata = NFTUtils.convertMetadata_ERC721_to_ARC3(_ipfs_connector, erc721_metadata); + if (null == arc3_metadata) { + LOGGER.warn("Failed to convert metadata file " + from_file.getName()); + result = false; + } else { + String arc3_json = JSONUtils.createJSONFromPOJO(arc3_metadata); + String arc3_json_prettyprint = JSONUtils.prettyPrint(arc3_json); + FilesUtils.writeToFileUNIXHaltOnException(arc3_json_prettyprint, _to_folder + "/" + from_file.getName()); + + System.out.println("--------------- ERC721 -> ARC3, metadata results ---------------"); + System.out.println(arc3_json_prettyprint); + System.out.println("----------------------------------------------------------------"); + } + } + + // convert the erc721 metadata to arc69 + if (AVMNFTStandard.ARC69 == _standard) { + ARC69ARC19MetaData arc69_metadata = NFTUtils.convertMetadata_ERC721_to_ARC69(_ipfs_connector, erc721_metadata); + if (null == arc69_metadata) { + LOGGER.warn("Failed to convert metadata file " + from_file.getName()); + result = false; + } else { + String arc69_json = JSONUtils.createJSONFromPOJO(arc69_metadata); + String arc69_json_prettyprint = JSONUtils.prettyPrint(arc69_json); + FilesUtils.writeToFileUNIXHaltOnException(arc69_json_prettyprint, _to_folder + "/" + from_file.getName()); + + System.out.println("--------------- ERC721 -> ARC69, metadata results ---------------"); + System.out.println(arc69_json_prettyprint); + System.out.println("----------------------------------------------------------------"); + } + } + } + } + + return result; + } + + public static String createUnitNameFromName(String _name) { + if (_name.length() <= 8) return _name; + + // Attempt to just shorten by clean .. + String clean = StringsUtils.onlykeepAlphaNumeric(_name); + if (clean.length() <= 8) return clean; + + StringBuffer sb1 = new StringBuffer(); + String[] parts = clean.split(" "); + boolean first = true; + for (String part: parts) { + if (StringsUtils.isOnlyAlpha(part)) { + if (first) { + sb1.append(part.charAt(0)); + first = false; + } else { + sb1.append(part.charAt(0)); + } + } else { + sb1.append("_" + part); + } + } + String short1 = sb1.toString().toUpperCase(); + if (short1.length() <= 8) return short1; + + String short2 = short1.replace("_", ""); + if (short2.length() <= 8) return short2; + + // out of options + return ""; + } + + public static String determinefragmentFromMimetype(String _url_mimetype) { + if (_url_mimetype.toLowerCase().contains("audio")) return "#a"; + if (_url_mimetype.toLowerCase().contains("image")) return "#i"; + if (_url_mimetype.toLowerCase().contains("video")) return "#v"; + if (_url_mimetype.toLowerCase().contains("pdf")) return "#p"; + if (_url_mimetype.toLowerCase().contains("text/html")) return "#h"; + return null; + } + +} diff --git a/src/main/java/crypto/forestfish/utils/NetUtils.java b/src/main/java/crypto/forestfish/utils/NetUtils.java new file mode 100644 index 0000000..dcec92d --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/NetUtils.java @@ -0,0 +1,192 @@ +package crypto.forestfish.utils; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.NetworkInterface; +import java.net.Socket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.TreeMap; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(NetUtils.class); + + public static boolean isValidIPV4(final String _ip) { + if (null == _ip) { + return false; + } else { + // Optimization + if ("::1".equals(_ip)) { + return false; + } + if ("".equals(_ip)) { + return false; + } + + // Length optimization, xxx.xxx.xxx.xxx = 15, x.x.x.x = 7 + if ((_ip.length() > 15) || (_ip.length() < 7)) { + return false; + } + + // Make sure first and last char is a digit + if (Character.isDigit(_ip.charAt(0)) && Character.isDigit(_ip.charAt(_ip.length()-1))) { + // Make sure we have 4 dots + final String[] octets = _ip.split("\\."); + if (octets.length == 4) { + try { + int octet1 = Integer.parseInt(octets[0]); + int octet2 = Integer.parseInt(octets[1]); + int octet3 = Integer.parseInt(octets[2]); + int octet4 = Integer.parseInt(octets[3]); + if (true && + (octets[0].length()<=3) && + (octets[1].length()<=3) && + (octets[2].length()<=3) && + (octets[3].length()<=3) && + (octet1 >= 0) && + (octet1 <= 255) && + (octet2 >= 0) && + (octet2 <= 255) && + (octet3 >= 0) && + (octet3 <= 255) && + (octet4 >= 0) && + (octet4 <= 255) && + true) { + return true; + } + } catch (Exception e) { + return false; + } + } + } + } + return false; + } + + public static boolean isRFC1918(final String _ip) { + if (_ip == null) return false; + if (_ip.startsWith("192.168")) return true; + if (_ip.startsWith("10.")) return true; + if (_ip.startsWith("172.16.")) return true; + if (_ip.startsWith("172.16.")) return true; + if (_ip.startsWith("172.17.")) return true; + if (_ip.startsWith("172.18.")) return true; + if (_ip.startsWith("172.19.")) return true; + if (_ip.startsWith("172.20.")) return true; + if (_ip.startsWith("172.21.")) return true; + if (_ip.startsWith("172.22.")) return true; + if (_ip.startsWith("172.23.")) return true; + if (_ip.startsWith("172.24.")) return true; + if (_ip.startsWith("172.25.")) return true; + if (_ip.startsWith("172.26.")) return true; + if (_ip.startsWith("172.27.")) return true; + if (_ip.startsWith("172.28.")) return true; + if (_ip.startsWith("172.29.")) return true; + if (_ip.startsWith("172.30.")) return true; + if (_ip.startsWith("172.31.")) return true; + return false; + } + + public static boolean isLocalHost(final String _ip) { + if (_ip == null) return false; + if (_ip.startsWith("127.")) return true; + return false; + } + + public static ArrayList determineLocalIPv4s() { + ArrayList localips = new ArrayList(); + localips.add("127.0.0.1"); + try { + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + while (interfaces.hasMoreElements()) { + NetworkInterface iface = interfaces.nextElement(); + if (iface.isLoopback() || !iface.isUp()) + continue; + Enumeration addresses = iface.getInetAddresses(); + while(addresses.hasMoreElements()) { + InetAddress addr = addresses.nextElement(); + String ip = addr.getHostAddress(); + if (isValidIPV4(ip)) localips.add(ip); + } + } + } catch (SocketException e) { + throw new RuntimeException(e); + } + return localips; + } + + public static String grabCnetworkSlice(final String ip) { + final String octets[] = ip.split("\\."); + if (octets.length == 4) { + return octets[0] + "." + octets[1] + "." + octets[2]; + } else { + return ip; + } + } + + public static TreeMap performTCPPortSweep(int port, ArrayList cnets, int startIP, int stopIP, int timeout, int threadPoolCount) { + TreeMap activeIps = new TreeMap(); + if (stopIP65535) { + LOGGER.error("invalid port " + port + " specified as input"); + SystemUtils.halt(); + } + if (port<0) { + LOGGER.error("invalid port " + port + " specified as input"); + SystemUtils.halt(); + } + try { + final ExecutorService es = Executors.newFixedThreadPool(threadPoolCount); + final List> futures = new ArrayList<>(); + for (int lastOctet = startIP; lastOctet <= stopIP; lastOctet++) { + for (String cnet: cnets) { + if ("127.0.0".equals(cnet)) { + if (lastOctet>1) continue; + } + String ip = cnet + "." + lastOctet; + if (!NetUtils.isValidIPV4(ip)) { + LOGGER.error("Invalid ip generated from input parameters: " + ip); + SystemUtils.halt(); + } + futures.add(portIsOpenForHost(es, ip, port, timeout)); + } + } + es.shutdown(); + for (final Future f : futures) { + if (f.get() != "") { + activeIps.put(f.get(), true); + } + } + } catch (Exception ex) { + } + return activeIps; + } + + public static Future portIsOpenForHost(final ExecutorService es, final String ip, final int port, final int timeout) { + return es.submit(new Callable() { + @Override public String call() { + try { + Socket socket = new Socket(); + socket.connect(new InetSocketAddress(ip, port), timeout); + socket.close(); + return ip; + } catch (Exception ex) { + return ""; + } + } + }); + } +} diff --git a/src/main/java/crypto/forestfish/utils/NotificationUtils.java b/src/main/java/crypto/forestfish/utils/NotificationUtils.java new file mode 100644 index 0000000..a548cb5 --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/NotificationUtils.java @@ -0,0 +1,50 @@ +package crypto.forestfish.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import net.pushover.client.MessagePriority; +import net.pushover.client.PushoverClient; +import net.pushover.client.PushoverMessage; +import net.pushover.client.PushoverRestClient; +import net.pushover.client.Status; + +public class NotificationUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(NotificationUtils.class); + + public static void pushover(String apiTokenUser, String apiTokenApp, String title, String message, + MessagePriority messageprio, String url, String urltitle, String selectedSound) { + + if ("".equals(apiTokenUser) || "".equals(apiTokenApp)) { + LOGGER.debug("Skipping pushover notification"); + } else { + + try { + PushoverClient client = new PushoverRestClient(); + client.pushMessage(PushoverMessage.builderWithApiToken(apiTokenApp) + .setUserId(apiTokenUser) + .build()); + + Status result = client.pushMessage(PushoverMessage + .builderWithApiToken(apiTokenApp) + .setUserId(apiTokenUser) + .setMessage(message) + .setPriority(messageprio) // HIGH|NORMAL|QUIET + .setTitle(title) + .setUrl(url) + .setTitleForURL(urltitle) + .setSound(selectedSound) + .build()); + + LOGGER.info(String.format("status: %d, request id: %s", result.getStatus(), result.getRequestId())); + + } catch (Exception e) { + System.out.println("Exception: " + e.getMessage()); + SystemUtils.halt(); + } + + } + } + +} diff --git a/src/main/java/crypto/forestfish/utils/NumUtils.java b/src/main/java/crypto/forestfish/utils/NumUtils.java new file mode 100644 index 0000000..4610860 --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/NumUtils.java @@ -0,0 +1,94 @@ +package crypto.forestfish.utils; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.RoundingMode; +import java.util.Random; + +public class NumUtils { + + // credit https://www.geeksforgeeks.org/round-the-given-number-to-nearest-multiple-of-10/ + public static int getNearestMultipleOf10(int n) { + + // Smaller multiple + int a = (n / 10) * 10; + + // Larger multiple + int b = a + 10; + + // Return of closest of two + return (n - a > b - n)? b : a; + } + + public static boolean isInteger(String s) { + try { + Integer.parseInt(s); + } catch(NumberFormatException e) { + return false; + } catch(NullPointerException e) { + return false; + } + return true; + } + + public static int randomNumWithinRangeAsInt(final int min, final int max) { + if (max == min) { + return min; + } + if (max= 1000) { + page++; + EVMWalletTxHistoryReply reply = null; + String jsonSTR = TCPIPUtils.httpGETContent("https://api.polygonscan.com/api?module=account&action=tokentx&address=" + walletAddress + "&contractaddress=" + erc20contractaddress + "&startblock=1&endblock=99999999&page=" + page + "&offset=10000&sort=asc&apikey=" + apiKey, 10); + if (null != jsonSTR) { + reply = EVMWalletTxHistoryReply.parseReply(jsonSTR); + LOGGER.debug("message: " + reply.getMessage()); + LOGGER.debug("status: " + reply.getStatus()); + LOGGER.debug("result.size(): " + reply.getResult().size()); + txCount = txCount + reply.getResult().size(); + } + } + return txCount; + } + + public static Double getERC20WalletBalance10kTx(String walletAddress, String apiKey, PolygonERC20Token token) { + String erc20contractaddress = ContractMapper.resolveContractAddressFor(token); + Double erc20Balance = 0.0d; + ArrayList batch = new ArrayList(); + + int page = 0; + int resultCount = 1000; + while (resultCount >= 1000) { + page++; + EVMWalletTxHistoryReply reply = null; + String jsonSTR = TCPIPUtils.httpGETContent("https://api.polygonscan.com/api?module=account&action=tokentx&address=" + walletAddress + "&contractaddress=" + erc20contractaddress + "&startblock=1&endblock=99999999&page=" + page + "&offset=10000&sort=asc&apikey=" + apiKey, 10); + if (null != jsonSTR) { + reply = EVMWalletTxHistoryReply.parseReply(jsonSTR); + LOGGER.debug("message: " + reply.getMessage()); + LOGGER.debug("status: " + reply.getStatus()); + LOGGER.debug("result.size(): " + reply.getResult().size()); + for (ERC20Transaction tx: reply.getResult()) { + tx.update(); + batch.add(tx); + } + resultCount = reply.getResult().size(); + } + } + + for (ERC20Transaction tx: batch) { + if (!"0".equals(tx.getValue())) { + if (walletAddress.equalsIgnoreCase(tx.getTo())) { + LOGGER.debug(DateUtils.epochInSecondsToUTC(Long.parseLong(tx.getTimeStamp())) + " +" + NumUtils.round(tx.getValueD(), 4)); + erc20Balance = erc20Balance + tx.getValueD(); + } else if (walletAddress.equalsIgnoreCase(tx.getFrom())) { + LOGGER.debug(DateUtils.epochInSecondsToUTC(Long.parseLong(tx.getTimeStamp())) + " -" + NumUtils.round(tx.getValueD(), 4)); + erc20Balance = erc20Balance - tx.getValueD(); + } else { + LOGGER.error("Found tx which is neither to/from the specified wallet " + walletAddress); + LOGGER.error("tx from: " + tx.getFrom()); + LOGGER.error("tx to: " + tx.getTo()); + SystemUtils.halt(); + } + } + } + + return erc20Balance; + } + + +} diff --git a/src/main/java/crypto/forestfish/utils/SignaUtils.java b/src/main/java/crypto/forestfish/utils/SignaUtils.java new file mode 100644 index 0000000..d286eef --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/SignaUtils.java @@ -0,0 +1,16 @@ +package crypto.forestfish.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import crypto.forestfish.objects.burst.BurstBlockChain; + +public class SignaUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(SignaUtils.class); + + public static void printNodeAddress(BurstBlockChain signumBlockChain) { + LOGGER.info("node address: " + signumBlockChain.getNodeURL()); + } + +} diff --git a/src/main/java/crypto/forestfish/utils/StringsUtils.java b/src/main/java/crypto/forestfish/utils/StringsUtils.java new file mode 100644 index 0000000..3b272c2 --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/StringsUtils.java @@ -0,0 +1,523 @@ +package crypto.forestfish.utils; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class StringsUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(StringsUtils.class); + + /** + * Identical: 1.0d + * Slightly different: 0.8d + * Completely different: 0.0d + * https://search.r-project.org/CRAN/refmans/comparator/html/LCS.html + */ + public static double lcsSimilarity(final String a, final String b) { + if (null == a) return 0.0d; + if (null == b) return 0.0d; + if ("".equals(a)) return 0.0d; + if ("".equals(b)) return 0.0d; + String result = org.apache.commons.collections4.ListUtils.longestCommonSubsequence(a, b); + double base = a.length() + b.length() - result.length(); + double similarity = result.length()/base; + return NumUtils.round(similarity, 5); + } + + public static String[] stringSplit(String[] delimiters, String input_words) { + String[] input_words_split = null; + input_words_split = input_words.split(delimiters[0], Integer.MAX_VALUE); + return input_words_split; + } + + public static boolean isHexString(String s) { + for (int i = 0; i < s.length(); i++) { + if (!isHexChar(s.charAt(i))) { + return false; + } + } + return true; + } + + public static String removeLastChar(String str) { + return removeLastChars(str, 1); + } + + public static String removeFirstChar(String str) { + return str.substring(1); + } + + public static String removeLastChars(String str, int chars) { + return str.substring(0, str.length() - chars); + } + + public static boolean isHexChar(char c) { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); + } + + public static String toUnicode(char ch) { + return String.format("\\u%04x", (int) ch); + } + + public static String encodeFileToBase64PNG(final String fileName) throws IOException { + File file = new File(fileName); + byte[] bytes = loadFile(file); + byte[] encoded = Base64.encodeBase64(bytes); + String encodedString = new String(encoded); + return "data:image/png;base64," + encodedString; + } + + public static String decodeBase64String(final String encodedString) { + Base64 base64 = new Base64(); + String decodedString = new String(base64.decode(encodedString.getBytes())); + return decodedString; + } + + public static String encodeBytesToBase64(final byte[] bytes) { + byte[] encoded = Base64.encodeBase64(bytes); + String encodedString = new String(encoded); + return encodedString; + } + + public static String encodeStringToBase64(final String str) { + byte[] bytes = str.getBytes(); + byte[] encoded = Base64.encodeBase64(bytes); + String encodedString = new String(encoded); + return encodedString; + } + + public static List ngrams(int n, String str) { + List ngrams = new ArrayList(); + String[] words = str.split(""); + for (int i = 0; i < words.length - n + 1; i++) + ngrams.add(concat(words, i, i+n)); + return ngrams; + } + + public static String concat(String[] words, int start, int end) { + StringBuilder sb = new StringBuilder(); + for (int i = start; i < end; i++) + sb.append((i > start ? " " : "") + words[i]); + return sb.toString(); + } + + public static String cleanJSON(final String _str) { + String oldString = _str; + String newString = _str; + boolean change = true; + while (change) { + newString = oldString + .replace("\r", " ") + .replace("\n", " ") + .replace(" ", " ") + .replace(",}", "}") + .replace(", }", "}") + .trim(); + newString = StringUtils.stripEnd(newString," "); + if (newString.equals(oldString)) { + change = false; + } else { + oldString = newString; + } + } + return newString; + } + + + private static byte[] loadFile(File file) throws IOException { + InputStream is = new FileInputStream(file); + + long length = file.length(); + byte[] bytes = new byte[(int)length]; + + int offset = 0; + int numRead = 0; + while (offset < bytes.length + && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) { + offset += numRead; + } + + if (offset < bytes.length) { + is.close(); + throw new IOException("Could not completely read file "+file.getName()); + } + + is.close(); + return bytes; + } + + public static String cutAndPadStringTo50(String s) { + final Integer maxLength = 50; + if (s.length() > maxLength) { + s = s.substring(0, Math.min(s.length(), maxLength)) + " ..."; + } + return s; + } + + public static String cutAndPadStringToN(String s, Integer n) { + final Integer wantedLength = n; + if (s.length() > (wantedLength-3)) { + s = s.substring(0, wantedLength-3) + ".. "; + } else if (s.length() == wantedLength) { + // we are done + } else { + while (s.length() < wantedLength) { + s = s + " "; + } + } + return s; + } + + public static String prefixStringWith0sToLengthN(String s, final Integer wantedLength) { + if (s.length() > wantedLength) { + LOGGER.info("string is longer than intended length, returning identical string"); + return s; + } else if (s.length() == wantedLength) { + // done + } else { + while (s.length() < wantedLength) { + s = "0" + s; + } + } + return s; + } + + public static String hex2String(String hex) { + return hex2String(hex, false); + + } + + public static String hex2String(String hex, boolean nullAsSpace) { + StringBuilder output = new StringBuilder(); + for (int i = 0; i < hex.length(); i+=2) { + String str = hex.substring(i, i+2); + final char c = (char)Integer.parseInt(str, 16); + if (nullAsSpace && c == 0) + output.append(' '); + else + output.append(c); + } + return output.toString(); + } + + public static String hexToAscii(String s) { + int n = s.length(); + StringBuilder sb = new StringBuilder(n / 2); + for (int i = 0; i < n; i += 2) { + char a = s.charAt(i); + char b = s.charAt(i + 1); + sb.append((char) ((hexToInt(a) << 4) | hexToInt(b))); + } + return sb.toString(); + } + + private static int hexToInt(char ch) { + System.out.println(ch); + if ('a' <= ch && ch <= 'f') { return ch - 'a' + 10; } + if ('A' <= ch && ch <= 'F') { return ch - 'A' + 10; } + if ('0' <= ch && ch <= '9') { return ch - '0'; } + throw new IllegalArgumentException(String.valueOf(ch)); + } + + public static String cutStringFromLeft(String s, Integer maxLength) { + return StringUtils.left(s,maxLength); + } + + public static String cutStringFromRight(String s, Integer maxLength) { + return StringUtils.right(s,maxLength); + } + + public static boolean isAlphanumeric(String str) { + for (int i=0; i= 0x3a && c <= 0x40) || (c > 0x5a && c <= 0x60) || c > 0x7a) { + return false; + } + } + return true; + } + + public static boolean isRandomCharacter(char ch) { + return "$+:;@<>#".indexOf(ch) >= 0; + } + + public static boolean hasAlphaUpperAndLowerAndNumeric(String str) { + boolean hasAlphaUpper = false; + boolean hasAlphaLower = false; + boolean hasNumeric = false; + + for (int i=0; i 1) { + return fullIndex[0]; + } + return inputString; + } + + public static boolean isAsciiPrintable(String str) { + if (str == null) { + return false; + } + int sz = str.length(); + for (int i = 0; i < sz; i++) { + if (isAsciiPrintable(str.charAt(i)) == false) { + return false; + } + } + return true; + } + + public static boolean isAsciiPrintable(char ch) { + return ch >= 32 && ch < 127; + } + + public static String keepOnlyAsciiPrintable(String str) { + return str.replaceAll("[^\\p{ASCII}]", ""); + } + + public static String removeLastLineBreak(String str) { + return str.replace("\n", "").replace("\r", ""); + } + + public static String removeLastDot(String string) { + int ind = string.lastIndexOf("."); + string = new StringBuilder(string).replace(ind, ind+1,"").toString(); + return string; + } + + public static String wrapWithQuotes(final long str) { + return "\"" + str + "\""; + } + + public static String wrapWithQuotes(final String str) { + return "\"" + str + "\""; + } + + public static String wrapWithQuotes(final int str) { + return "\"" + str + "\""; + } + + public static String makeOnlyFirstCharUpperCase(String input) { + input = input.toLowerCase(); + String output = input.substring(0, 1).toUpperCase() + input.substring(1); + return output; + } + + public static int orderOf(String s, ArrayList arrList) { + int order = 0; + for (String entry: arrList) { + if (s.equals(entry)) { + return order; + } else { + order++; + } + } + return order; + } + + public static HashMap wordCount(String input, String splitString, HashMap stopWords) { + HashMap result = new HashMap(); + String[] words = input.split(splitString); + for (String word: words) { + if (null == stopWords.get(word)) { + Integer value = result.get(word); + if (null == value) { + result.put(word, 1); + } else { + value++; + result.put(word, value); + } + } + } + return result; + } + + public static String extractDateFromString(String input) { + String regex = "(\\d{4}-\\d{2}-\\d{2})"; + Matcher m = Pattern.compile(regex).matcher(input); + if (m.find()) { + return m.group(1); + } else { + String regex2 = "(\\d{8})"; + Matcher m2 = Pattern.compile(regex2).matcher(input); + if (m2.find()) { + String dateCandidate = m2.group(1); + if (dateCandidate.startsWith("20")) { + return dateCandidate; + } else { + return "N/A"; + } + } else { + return "N/A"; + } + } + } + + public static String determineExistingFilePath(String filePath) { + File s = new File(filePath); + if (!s.exists()) { + String alternativeFilePath1 = filePath.replaceFirst("/", ""); + File sAlternative = new File(alternativeFilePath1); + if (sAlternative.exists()) { + filePath = alternativeFilePath1; + } else { + String alternativeFilePath2 = filePath.replaceFirst(".gen", ""); + File sAlternative2 = new File(alternativeFilePath2); + if (sAlternative2.exists()) { + filePath = alternativeFilePath2; + } else { + String alternativeFilePath3 = filePath.replaceFirst("/", "").replaceFirst(".gen", ""); + File sAlternative3 = new File(alternativeFilePath3); + if (sAlternative3.exists()) { + filePath = alternativeFilePath3; + } else { + System.out.println("Unable to find file, tried " + filePath + "," + alternativeFilePath1 + "," + alternativeFilePath2 + " and " + alternativeFilePath3); + filePath = ""; + } + } + } + } + + return filePath; + + } + + public static long countUpperCase(String inputString) { + return inputString.chars().filter((s)->Character.isUpperCase(s)).count(); + } + + public static long countLowerCase(String inputString) { + return inputString.chars().filter((s)->Character.isLowerCase(s)).count(); + } + + public static String padStart(String str, int minLength, char padChar) { + str = nullToEmpty(str); + if (str.length() >= minLength) { + return str; + } else { + StringBuilder sb = new StringBuilder(minLength); + int padCount = minLength - str.length(); + while (sb.length() < padCount) { + sb.append(padChar); + } + sb.append(str); + return sb.toString(); + } + } + + public static String nullToEmpty(String input) { + if (input != null) { + return input; + } else { + return ""; + } + } + + public static boolean isValidUUID(String _str) { + return isUUID3(_str); + } + + public static boolean isUUID1(String _str) { + if (null == _str) return false; + try{ + UUID.fromString(_str); + return true; + } catch (IllegalArgumentException exception){ + return false; + } + } + + // https://www.code4copy.com/java/validate-uuid-string-java/ + private final static Pattern UUID_REGEX_PATTERN = Pattern.compile("^[{]?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}[}]?$"); + public static boolean isUUID2(String _str) { + if (_str == null) return false; + return UUID_REGEX_PATTERN.matcher(_str).matches(); + } + + public static boolean isUUID3(String _str) { + if (null == _str) return false; + if (_str.split("-").length == 5) { + if (StringsUtils.isAlphanumeric(_str.replace("-", ""))) { + return true; + } + } + return false; + } + + public static String replaceLast(String text, String regex, String replacement) { + return text.replaceFirst("(?s)"+regex+"(?!.*?"+regex+")", replacement); + } + + public static boolean isValidBase58(String input) { + if (input == null) return false; + String base58Chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + for (char c : input.toCharArray()) { + if (base58Chars.indexOf(c) == -1) { + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/src/main/java/crypto/forestfish/utils/SystemUtils.java b/src/main/java/crypto/forestfish/utils/SystemUtils.java new file mode 100644 index 0000000..924b3f7 --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/SystemUtils.java @@ -0,0 +1,32 @@ +package crypto.forestfish.utils; + +public class SystemUtils { + + public static void halt() { + System.exit(1); + } + + public static String getSystemInformation() { + String systemInfo = System.getProperty("java.vendor") + " " + System.getProperty("java.version") + " on " + System.getProperty("os.name") + " " + System.getProperty("os.version"); + return systemInfo; + } + + public static String getQuote() { + return ""; + } + + public static void sleepInSeconds(int _seconds) { + try { + Thread.sleep(_seconds*1000); + } catch (InterruptedException e) { + } + } + + public static void sleepInMilliSecondss(int _milliseconds) { + try { + Thread.sleep(_milliseconds); + } catch (InterruptedException e) { + } + } + +} diff --git a/src/main/java/crypto/forestfish/utils/TCPIPUtils.java b/src/main/java/crypto/forestfish/utils/TCPIPUtils.java new file mode 100644 index 0000000..e3d5693 --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/TCPIPUtils.java @@ -0,0 +1,134 @@ +package crypto.forestfish.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.Socket; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; + +public class TCPIPUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(TCPIPUtils.class); + + public static String sendAndReceiveSingleLineReply(String destIp, int destPort, String data, int timeoutMs) { + final String target = destIp + ":" + destPort; + Socket socket = null; + try { + socket = new Socket(destIp, destPort); + socket.setSoTimeout(timeoutMs); + socket.getOutputStream().write(data.getBytes()); + } catch (Exception e) { + LOGGER.error("Failed to send data to \"" + target + "\". Reason: " + e.getMessage()); + if (socket != null && socket.isConnected()) { + try { + socket.close(); + } catch (Exception closeException) { + LOGGER.error("Unable to close socket to " + target + ". Reason: " + closeException.getMessage()); + } + } + return null; + } + + String reply = null; + InputStream is; + BufferedReader in; + try { + is = socket.getInputStream(); + in = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); + reply = in.readLine(); + } catch (Exception e) { + LOGGER.error("Unable to receive any or all data from socket. Reason: " + e.getMessage()); + return null; + } finally { + if (socket != null && socket.isConnected()) { + try { + socket.close(); + } catch (Exception e) { + LOGGER.error("Unable to close socket to " + target + ". Reason: " + e.getMessage()); + } + } + } + return reply; + } + + public static ArrayList sendAndReceiveMultiLineReply(String destIp, int destPort, String data, int timeoutMs) { + ArrayList response = new ArrayList(); + final String target = destIp + ":" + destPort; + Socket socket = null; + try { + socket = new Socket(destIp, destPort); + socket.setSoTimeout(timeoutMs); + socket.getOutputStream().write(data.getBytes()); + } catch (Exception e) { + LOGGER.error("Failed to send data to \"" + target + "\". Reason: " + e.getMessage()); + if (socket != null && socket.isConnected()) { + try { + socket.close(); + } catch (Exception closeException) { + LOGGER.error("Unable to close socket to " + target + ". Reason: " + closeException.getMessage()); + } + } + return null; + } + + String row = ""; + InputStream is; + BufferedReader in; + try { + is = socket.getInputStream(); + in = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); + while ((row = in.readLine()) != null) { + response.add(row); + } + } catch (Exception e) { + LOGGER.error("Unable to receive any or all data from socket. Reason: " + e.getMessage()); + return null; + } finally { + if (socket != null && socket.isConnected()) { + try { + socket.close(); + } catch (Exception e) { + LOGGER.error("Unable to close socket to " + target + ". Reason: " + e.getMessage()); + } + } + } + return response; + } + + public static String httpGETContent(String connString, int secondsTimeout) { + OkHttpClient client = new OkHttpClient.Builder() + .readTimeout(secondsTimeout, TimeUnit.SECONDS) + .writeTimeout(secondsTimeout, TimeUnit.SECONDS) + .build(); + Request request = new Request.Builder() + .url(connString) + .get() + .build(); + try { + Response response = client.newCall(request).execute(); + if ("OK".equals(response.message())) { + String body = response.body().string(); + if (body.length() > 0) { + return body; + } else { + LOGGER.warn("Got an empty reply"); + return null; + } + } else { + LOGGER.warn("response: " + response.message()); + } + } catch (Exception e) { + LOGGER.warn("e1: " + e.getMessage()); + } + return null; + } + +} diff --git a/src/main/java/crypto/forestfish/utils/URLUtils.java b/src/main/java/crypto/forestfish/utils/URLUtils.java new file mode 100644 index 0000000..f1dc8ad --- /dev/null +++ b/src/main/java/crypto/forestfish/utils/URLUtils.java @@ -0,0 +1,45 @@ +package crypto.forestfish.utils; + +import org.jsoup.Jsoup; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class URLUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(URLUtils.class); + + public static String extractURLHostnameFromURL(final String url) { + try { + String urlProcess = url; + String[] urlArray = url.split(":\\/\\/"); + if (urlArray.length >= 2) { + urlProcess = urlArray[1].toLowerCase(); + } + urlProcess = urlProcess.split(":")[0].split("/")[0]; + if (urlProcess.endsWith(".")) { + return StringsUtils.removeLastDot(urlProcess); + } else { + return urlProcess; + } + } catch (Exception e) { + LOGGER.error("Unable to extract hostname from url: " + url); + return ""; + } + } + + public static String makeSafe(String text) { + String s = text + .replaceFirst("http", "hxxp") + .replaceFirst("HTTPS", "hxxps") + .replaceFirst("HTTP", "hxxp") + .replace("\n", "") + .replace("\r", ""); + s = html2text(s); + return s; + } + + public static String html2text(String html) { + return Jsoup.parse(html).text(); + } + +} diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..d2d0d41 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,17 @@ + + + + + + + true + + UTF-8 + %date{ISO8601} component_class=%-5logger{0} thread=%thread log_level="%level" %msg%n + + + + + + + diff --git a/src/test/java/crypto/forestfish/avm/AVMNodeInteractTest.java b/src/test/java/crypto/forestfish/avm/AVMNodeInteractTest.java new file mode 100644 index 0000000..33b14e3 --- /dev/null +++ b/src/test/java/crypto/forestfish/avm/AVMNodeInteractTest.java @@ -0,0 +1,57 @@ +package crypto.forestfish.avm; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import crypto.forestfish.enums.avm.AVMChain; +import crypto.forestfish.objects.avm.connector.AVMBlockChainConnector; +import crypto.forestfish.utils.AVMUtils; + +public class AVMNodeInteractTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(AVMNodeInteractTest.class); + + @Test + public void testNodeInteract_MAINNET() { + + AVMBlockChainConnector connector = new AVMBlockChainConnector(AVMChain.MAINNET, true); + Long lastRound = AVMUtils.getLastRound(connector); + + assertTrue("Ensure sane lastRound", lastRound > 1L); + LOGGER.info("lastRound: " + lastRound); + } + + @Test + public void testNodeInteract_TESTNET() { + + AVMBlockChainConnector connector = new AVMBlockChainConnector(AVMChain.TESTNET, true); + Long lastRound = AVMUtils.getLastRound(connector); + + assertTrue("Ensure sane lastRound", lastRound > 1L); + LOGGER.info("lastRound: " + lastRound); + } + + @Test + public void testNodeInteract_BETANET() { + + AVMBlockChainConnector connector = new AVMBlockChainConnector(AVMChain.BETANET, true); + Long lastRound = AVMUtils.getLastRound(connector); + + assertTrue("Ensure sane lastRound", lastRound > 1L); + LOGGER.info("lastRound: " + lastRound); + } + + @Test + public void testNodeInteract_VOI_TESTNET() { + + AVMBlockChainConnector connector = new AVMBlockChainConnector(AVMChain.VOI_TESTNET, true); + Long lastRound = AVMUtils.getLastRound(connector); + + assertTrue("Ensure sane lastRound", lastRound > 1L); + LOGGER.info("lastRound: " + lastRound); + } + +} diff --git a/src/test/java/crypto/forestfish/avm/AVMUtilsTest.java b/src/test/java/crypto/forestfish/avm/AVMUtilsTest.java new file mode 100644 index 0000000..1650608 --- /dev/null +++ b/src/test/java/crypto/forestfish/avm/AVMUtilsTest.java @@ -0,0 +1,29 @@ +package crypto.forestfish.avm; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.algorand.algosdk.account.Account; + +import crypto.forestfish.utils.AVMUtils; + +public class AVMUtilsTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(AVMUtilsTest.class); + + @Test + public void testRandomAccountCreation() { + + Account acc1 = AVMUtils.createNewRandomAccount(); + + LOGGER.info("Generated account with address: " + acc1.getAddress()); + assertEquals("Ensure proper Algorand address generated", 58, acc1.getAddress().toString().length()); + + LOGGER.info("Mnemonic: " + acc1.toMnemonic()); + assertEquals("Ensure proper Algorand mnemonic generated", 25, acc1.toMnemonic().split(" ").length); + } + +} diff --git a/src/test/java/crypto/forestfish/evm/EVMContractUtilsTest.java b/src/test/java/crypto/forestfish/evm/EVMContractUtilsTest.java new file mode 100644 index 0000000..07155d3 --- /dev/null +++ b/src/test/java/crypto/forestfish/evm/EVMContractUtilsTest.java @@ -0,0 +1,219 @@ +package crypto.forestfish.evm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.util.HashMap; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.esaulpaugh.headlong.abi.Function; +import com.esaulpaugh.headlong.abi.Tuple; + +import crypto.forestfish.enums.evm.EVMChain; +import crypto.forestfish.objects.embedded.evm.ABI; +import crypto.forestfish.objects.evm.connector.EVMBlockChainConnector; +import crypto.forestfish.objects.evm.model.erc721.ERC721ContractInfo; +import crypto.forestfish.objects.evm.model.solidity.ABIFunctionEntry; +import crypto.forestfish.utils.CryptUtils; +import crypto.forestfish.utils.EVMContractUtils; +import crypto.forestfish.utils.EVMUtils; +import crypto.forestfish.utils.FilesUtils; +import crypto.forestfish.utils.JSONUtils; +import crypto.forestfish.utils.StringsUtils; + +public class EVMContractUtilsTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(EVMContractUtilsTest.class); + + @Test + public void testEncodeABI() { + // https://github.com/esaulpaugh/headlong/blob/master/README.md + Function f = new Function("baz(uint32,bool)"); // canonicalizes and parses any signature + Tuple args = Tuple.of(69L, true); // 0x45 + // Two equivalent styles: + ByteBuffer one = f.encodeCall(args); + ByteBuffer two = f.encodeCallWithArgs(69L, true); + System.out.println(Function.formatCall(one.array())); // a multi-line hex representation + System.out.println(f.decodeCall(two).equals(args)); + String hexStr = CryptUtils.encodeHexString(one.array()); + assertEquals("Ensure proper hexstr arguments to baz()", "cdcd77c000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001", hexStr); + } + + @Test + public void testEncodeABI2() { + // https://github.com/esaulpaugh/headlong/blob/master/README.md + Function f = new Function("baz(uint256,bool)"); // canonicalizes and parses any signature + Tuple args = Tuple.of(new BigInteger("1"), true); // 0x45 + ByteBuffer one = f.encodeCall(args); + System.out.println(Function.formatCall(one.array())); // a multi-line hex representation + String hexStr = CryptUtils.encodeHexString(one.array()); + assertEquals("Ensure proper hexstr arguments to baz()", "72ed38b600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001", hexStr); + } + + @Test + public void testEncodeABI3() { + Function func = new Function("baz(uint256[])"); + BigInteger[] bigints = new BigInteger[] { BigInteger.valueOf(7), BigInteger.valueOf(8), BigInteger.valueOf(9) }; + Tuple args = Tuple.singleton(bigints); + ByteBuffer bb = func.encodeCall(args); + System.out.println(Function.formatCall(bb.array())); + String hexStr = CryptUtils.encodeHexString(bb.array()); + assertEquals("Ensure proper hexstr arguments to baz()", "3838d31c00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009", hexStr); + } + + @Test + public void testEncodeAavegotchiDiamondABI() { + String funcName = "interact"; + String abiJSON = FilesUtils.readAllFromFileWithPath("abi/abiAavegotchiDiamond.json"); + String funcJSON = JSONUtils.getFunctionJSONUsingABI(abiJSON, funcName); + if ("".equals(funcJSON)) LOGGER.error("Unable to find function " + funcName + "in ABI JSON"); + System.out.println("ABI JSON for function " + funcName + "(): " + funcJSON); + Function interact_func = Function.fromJson(funcJSON); + BigInteger[] bigints = new BigInteger[] { BigInteger.valueOf(7), BigInteger.valueOf(8), BigInteger.valueOf(9) }; + Tuple args = Tuple.singleton(bigints); + ByteBuffer bb = interact_func.encodeCall(args); + System.out.println(Function.formatCall(bb.array())); + String hexStr = CryptUtils.encodeHexString(bb.array()); + assertEquals("Ensure proper hexstr arguments to interact()", "22c6751900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009", hexStr); + } + + @Test + public void testEncodeAavegotchiDiamondABIEmbedded() { + String funcName = "interact"; + String abiJSON = ABI.abiAavegotchiDiamond; + String funcJSON = JSONUtils.getFunctionJSONUsingABI(abiJSON, funcName); + if ("".equals(funcJSON)) LOGGER.error("Unable to find function " + funcName + "in ABI JSON"); + System.out.println("ABI JSON for function " + funcName + "(): " + funcJSON); + Function interact_func = Function.fromJson(funcJSON); + BigInteger[] bigints = new BigInteger[] { BigInteger.valueOf(7), BigInteger.valueOf(8), BigInteger.valueOf(9) }; + Tuple args = Tuple.singleton(bigints); + ByteBuffer bb = interact_func.encodeCall(args); + System.out.println(Function.formatCall(bb.array())); + String hexStr = CryptUtils.encodeHexString(bb.array()); + assertEquals("Ensure proper hexstr arguments to interact()", "22c6751900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009", hexStr); + } + + @Test + public void testgetABIFunctionsAavegotchiDiamond() { + String abiJSON = ABI.abiAavegotchiDiamond; + int function_count = 0; + HashMap abiFunctions = JSONUtils.getFunctionNamesOfABIJSON(abiJSON); + for (String function: abiFunctions.keySet()) { + System.out.println("function #" + function_count + ": " + function); + function_count++; + } + assertEquals("Ensure AavegotchiDiamond exposes 141 functions", 141, function_count); + } + + @Test + public void testgetABIFunctionsERC721Enumerable() { + String abiJSON = ABI.abiERC721Enumerable; + int function_count = 0; + HashMap abiFunctions = JSONUtils.getFunctionNamesOfABIJSON(abiJSON); + for (String function: abiFunctions.keySet()) { + System.out.println("function #" + function_count + ": " + function); + function_count++; + } + assertEquals("Ensure ERC721Enumerable exposes 12 functions", 12, function_count); + } + + @Test + public void testgetABIFunctionsERC721Contract() { + String abiJSON = ABI.abiERC721Metadata; + int function_count = 0; + HashMap abiFunctions = JSONUtils.getFunctionNamesOfABIJSON(abiJSON); + for (String function: abiFunctions.keySet()) { + System.out.println("function #" + function_count + ": " + function); + function_count++; + } + assertEquals("Ensure ERC721Metadata exposes 12 functions", 12, function_count); + } + + @Test + public void testgetABIFunctionsERC721_GMI_Polygon() { + + EVMBlockChainConnector connector = new EVMBlockChainConnector(EVMChain.POLYGON); + BigInteger latestBlockNR = EVMUtils.getLatestBlockNumber(connector); + assertTrue("Ensure sane ETH blocknr", latestBlockNR.longValue() > 1L); + LOGGER.info("latestBlockNR: " + latestBlockNR); + + String erc721_contract_address = "0x3F0E22B827e51Ff567D7388c2B598e2EAbfa74BE"; // GMI ERC721 on polygon + ERC721ContractInfo erc721_contractinfo = EVMContractUtils.getERC721ContractInfo(connector, erc721_contract_address); + + // debug + EVMContractUtils.printAllFunctionsOfABI(ABI.abiERC721Token); + + assertNotEquals("Ensure is valid smart contract contract", null, erc721_contractinfo); + assertEquals("Ensure ERC721 contract symbol matches", "GMI420", erc721_contractinfo.getSymbol()); + assertEquals("Ensure ERC721 contract name matches", "GMI NFT Vol.1", erc721_contractinfo.getName()); + assertEquals("Ensure ERC721 contract totalSupply can be obtained", "844", erc721_contractinfo.getTotalSupply()); + assertEquals("Ensure ERC721 contract baseURI can be obtained", "https://arweave.net/PhszgqVxdwWryyA6Jl9kZPps41sHtmQzxaxG_GLqRyg", erc721_contractinfo.getBaseuri()); + assertEquals("Ensure ERC721 contract owner can be obtained", "0x7E0512CA22A1876f0Aa38aD451C7aB3924335a1b", erc721_contractinfo.getOwner()); + } + + @Test + public void testgetABIFunctionsERC721Receiver() { + String abiJSON = ABI.abiERC721Receiver; + int function_count = 0; + HashMap abiFunctions = JSONUtils.getFunctionNamesOfABIJSON(abiJSON); + for (String function: abiFunctions.keySet()) { + System.out.println("function #" + function_count + ": " + function); + function_count++; + } + assertEquals("Ensure ERC721Metadata exposes 1 function", 1, function_count); + } + + @Test + public void testgetABIFunctionsERC721Token() { + String abiJSON = ABI.abiERC721Token; + int function_count = 0; + HashMap abiFunctions = JSONUtils.getFunctionNamesOfABIJSON(abiJSON); + for (String function: abiFunctions.keySet()) { + System.out.println("function #" + function_count + ": " + function); + function_count++; + } + assertEquals("Ensure ERC721Token exposes 15 functions", 15, function_count); + } + + @Test + public void testgetABIFunctionsERC1155() { + String abiJSON = ABI.abiERC1155; + int function_count = 0; + HashMap abiFunctions = JSONUtils.getFunctionNamesOfABIJSON(abiJSON); + for (String function: abiFunctions.keySet()) { + System.out.println("function #" + function_count + ": " + function); + function_count++; + } + assertEquals("Ensure ERC1155Token exposes 8 function", 8, function_count); + } + + @Test + public void testgetABIFunctionsERC1155Detailed() { + String abiJSON = ABI.abiERC1155; + int function_count = 0; + HashMap abiFunctions = JSONUtils.getFunctionsOfABIJSON(abiJSON); + for (ABIFunctionEntry function: abiFunctions.keySet()) { + System.out.println(StringsUtils.cutAndPadStringToN("function #" + function_count + ": " + function.getName(), 40) + " " + function.getInputs()); + function_count++; + } + assertEquals("Ensure ERC1155Token exposes 8 function", 8, function_count); + } + + @Test + public void testgetABIFunctionsERC721Basic() { + String abiJSON = ABI.abiERC721Basic; + int function_count = 0; + HashMap abiFunctions = JSONUtils.getFunctionNamesOfABIJSON(abiJSON); + for (String function: abiFunctions.keySet()) { + System.out.println("function #" + function_count + ": " + function); + function_count++; + } + assertEquals("Ensure ERC721Basic exposes 9 functions", 9, function_count); + } + +} diff --git a/src/test/java/crypto/forestfish/evm/EVMRPCInteractTest.java b/src/test/java/crypto/forestfish/evm/EVMRPCInteractTest.java new file mode 100644 index 0000000..28316da --- /dev/null +++ b/src/test/java/crypto/forestfish/evm/EVMRPCInteractTest.java @@ -0,0 +1,56 @@ +package crypto.forestfish.evm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.RoundingMode; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import crypto.forestfish.enums.evm.EVMChain; +import crypto.forestfish.objects.evm.connector.EVMBlockChainConnector; +import crypto.forestfish.utils.EVMUtils; + +public class EVMRPCInteractTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(EVMRPCInteractTest.class); + + @Test + public void testRPCInteract_ETH() { + + EVMBlockChainConnector connector = new EVMBlockChainConnector(EVMChain.ETHEREUM); + BigInteger latestBlockNR = EVMUtils.getLatestBlockNumber(connector); + assertTrue("Ensure sane ETH blocknr", latestBlockNR.longValue() > 1L); + LOGGER.info("latestBlockNR: " + latestBlockNR); + + BigInteger chainID = EVMUtils.getChainId(connector); + assertEquals("Ensure correct ETH chain id", chainID.longValue(), 1L); + LOGGER.info("chainID: " + chainID); + + BigDecimal networkGasPriceInGwei = EVMUtils.getCurrentNetworkGasPriceInGWEI(connector); + assertTrue("Ensure correct ETH chain id", networkGasPriceInGwei.doubleValue()>1); + LOGGER.info("networkGasPriceInGwei: " + networkGasPriceInGwei.setScale(0, RoundingMode.HALF_UP)); + } + + @Test + public void testRPCInteract_POLYGON() { + + EVMBlockChainConnector connector = new EVMBlockChainConnector(EVMChain.POLYGON); + BigInteger latestBlockNR = EVMUtils.getLatestBlockNumber(connector); + assertTrue("Ensure sane ETH blocknr", latestBlockNR.longValue() > 1L); + LOGGER.info("latestBlockNR: " + latestBlockNR); + + BigInteger chainID = EVMUtils.getChainId(connector); + assertEquals("Ensure correct ETH chain id", chainID.longValue(), 137L); + LOGGER.info("chainID: " + chainID); + + BigDecimal networkGasPriceInGwei = EVMUtils.getCurrentNetworkGasPriceInGWEI(connector); + assertTrue("Ensure correct ETH chain id", networkGasPriceInGwei.doubleValue()>1); + LOGGER.info("networkGasPriceInGwei: " + networkGasPriceInGwei.setScale(0, RoundingMode.HALF_UP)); + } + +} diff --git a/src/test/java/crypto/forestfish/evm/EVMUtilsTest.java b/src/test/java/crypto/forestfish/evm/EVMUtilsTest.java new file mode 100644 index 0000000..2539e36 --- /dev/null +++ b/src/test/java/crypto/forestfish/evm/EVMUtilsTest.java @@ -0,0 +1,169 @@ +package crypto.forestfish.evm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.web3j.crypto.Credentials; + +import com.esaulpaugh.headlong.abi.Function; +import com.esaulpaugh.headlong.abi.Tuple; + +import crypto.forestfish.enums.evm.EVMChain; +import crypto.forestfish.enums.evm.PolygonERC20Token; +import crypto.forestfish.objects.evm.SimpleWallet; +import crypto.forestfish.objects.evm.connector.EVMBlockChainConnector; +import crypto.forestfish.utils.CryptUtils; +import crypto.forestfish.utils.EVMUtils; + +public class EVMUtilsTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(EVMUtilsTest.class); + + @Test + public void signAndVerify() { + + // https://hukenneth.medium.com/ethereum-using-web3-js-for-message-signing-7e2935b2958c + // see clients/web3j/sign.js for web3j example + String message = "Hello, I am Kenneth!"; + String privateKey1 = "0xb5b1870957d373ef0eeffecc6e4812c0fd08f554b37b233526acc331bf1544f7"; + Credentials credentials = Credentials.create(privateKey1); + assertEquals("Ensure correct ETH address", "0x12890d2cce102216644c59dae5baed380d84830c", credentials.getAddress()); + System.out.println("address: " + credentials.getAddress()); + String signature = EVMUtils.sign(credentials, message); + assertEquals("Ensure correct signature", "0xd1741c3b54e1c95f00f6c85e1922de23ce4bd61b5e48b990bd3d21f3492a9f1d0x04fa324d0a13787dff529ce9a58587ea965e18b08864a23025c39748cb8fb5911c", signature); + System.out.println("signature: " + signature); + boolean verified = EVMUtils.verify(signature, message, credentials.getAddress()); + System.out.println("verified: " + verified); + assertEquals("Ensure we can verify the signed message", true, verified); + } + + @Test + public void testMnemonics() { + + SimpleWallet swallet0 = CryptUtils.generateLowEntropyMnemonic_16_0(); + assertEquals("Ensure generated mnemonic is correct", "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", swallet0.getMnemonic()); + assertEquals("Ensure generated private key #0 is correct", "0x1ab42cc412b618bdea3a599e3c9bae199ebf030895b039e9db1e30dafb12b727", swallet0.getPrivkey0()); + assertEquals("Ensure generated address #0 is correct", "0x9858effd232b4033e47d90003d41ec34ecaeda94", swallet0.getCred0().getAddress()); + + SimpleWallet swallet1 = CryptUtils.generateLowEntropyMnemonic_32_0(); + assertEquals("Ensure generated mnemonic is correct", "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", swallet1.getMnemonic()); + assertEquals("Ensure generated private key #0 is correct", "0x1053fae1b3ac64f178bcc21026fd06a3f4544ec2f35338b001f02d1d8efa3d5f", swallet1.getPrivkey0()); + assertEquals("Ensure generated address #0 is correct", "0xf278cf59f82edcf871d630f28ecc8056f25c1cdb", swallet1.getCred0().getAddress()); + + SimpleWallet swallet2 = CryptUtils.generateLowEntropyMnemonic_16_1(); + assertEquals("Ensure generated mnemonic is correct", "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", swallet2.getMnemonic()); + assertEquals("Ensure generated private key #0 is correct", "0x7af65ba4dd53f23495dcb04995e96f47c243217fc279f10795871b725cd009ae", swallet2.getPrivkey0()); + assertEquals("Ensure generated address #0 is correct", "0xfc2077ca7f403cbeca41b1b0f62d91b5ea631b5e", swallet2.getCred0().getAddress()); + + // https://bitcoin.stackexchange.com/questions/59904/does-bip39-mnemonic-construction-avoid-repeating-words + SimpleWallet swallet3 = CryptUtils.generateLowEntropyMnemonic_32_1(); + assertEquals("Ensure generated mnemonic is correct", "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", swallet3.getMnemonic()); + assertEquals("Ensure generated private key #0 is correct", "0x105434ca932be16664cb5e44e5b006728577dd757440d068e6d15ef52c15a82f", swallet3.getPrivkey0()); + assertEquals("Ensure generated address #0 is correct", "0x1959f5f4979c5cd87d5cb75c678c770515cb5e0e", swallet3.getCred0().getAddress()); + + } + + @Test + public void testValidEthereumAddressWithChecksum() { + assertFalse("Ensure invalid address returns false", EVMUtils.isValidEthereumAddressWithChecksum("0x9858effd232b")); + assertFalse("Ensure invalid address returns false", EVMUtils.isValidEthereumAddressWithChecksum("42")); + assertTrue("Ensure valid address returns true", EVMUtils.isValidEthereumAddressWithChecksum("0xb67dce2D6d0b76e2D46F5B5394180ae4E55a836B")); + } + + @Test + public void testValidEthereumPrivateKey() { + assertFalse("Ensure invalid as privatekey", EVMUtils.isValidPrivateKey("pepe")); + assertTrue("Ensure valid as private key (Hardhat account #0)", EVMUtils.isValidPrivateKey("0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80")); + } + + @Test + public void testValidMnemonic() { + assertFalse("Ensure invalid as mnemonic", EVMUtils.isValidMnemonic("pepe")); + assertFalse("Ensure invalid as mnemonic", EVMUtils.isValidMnemonic("pepe zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo")); + assertTrue("Ensure valid as mnemonic (Hardhat node)", EVMUtils.isValidMnemonic("test test test test test test test test test test test junk")); + } + + @Test + public void testEncodeABI() { + // https://github.com/esaulpaugh/headlong/blob/master/README.md + Function f = new Function("baz(uint32,bool)"); // canonicalizes and parses any signature + Tuple args = Tuple.of(69L, true); // 0x45 + // Two equivalent styles: + ByteBuffer one = f.encodeCall(args); + ByteBuffer two = f.encodeCallWithArgs(69L, true); + System.out.println(Function.formatCall(one.array())); // a multi-line hex representation + System.out.println(f.decodeCall(two).equals(args)); + String hexStr = CryptUtils.encodeHexString(one.array()); + assertEquals("Ensure proper hexstr arguments to baz()", "cdcd77c000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001", hexStr); + } + + @Test + public void testEncodeABI2() { + // https://github.com/esaulpaugh/headlong/blob/master/README.md + Function f = new Function("baz(uint256,bool)"); // canonicalizes and parses any signature + Tuple args = Tuple.of(new BigInteger("1"), true); // 0x45 + ByteBuffer one = f.encodeCall(args); + System.out.println(Function.formatCall(one.array())); // a multi-line hex representation + String hexStr = CryptUtils.encodeHexString(one.array()); + assertEquals("Ensure proper hexstr arguments to baz()", "72ed38b600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001", hexStr); + } + + @Test + public void testEncodeABI3() { + Function func = new Function("baz(uint256[])"); + BigInteger[] bigints = new BigInteger[] { BigInteger.valueOf(7), BigInteger.valueOf(8), BigInteger.valueOf(9) }; + Tuple args = Tuple.singleton(bigints); + ByteBuffer bb = func.encodeCall(args); + System.out.println(Function.formatCall(bb.array())); + String hexStr = CryptUtils.encodeHexString(bb.array()); + assertEquals("Ensure proper hexstr arguments to baz()", "3838d31c00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009", hexStr); + } + + @Test + public void connectToPolygonBlockChain() { + + // Instantiate an node optimized connector to the Polygon network + EVMBlockChainConnector polygonConnector = new EVMBlockChainConnector(EVMChain.POLYGON, true); + + // Latest block number should be larger than 1 + BigInteger blockNR = EVMUtils.getLatestBlockNumber(polygonConnector); + assertTrue("Ensure we get a sane block nr response", 1 == blockNR.compareTo(new BigInteger("1"))); + LOGGER.info("Latest block number: " + blockNR); + + // Gas price + BigDecimal gasprice = EVMUtils.getCurrentNetworkGasPriceInGWEI(polygonConnector); + assertTrue("Ensure we get a sane gasprice back (more than 1 GWEI)", gasprice.compareTo(new BigDecimal("1")) > 0); + LOGGER.info("Gas price in GWEI: " + gasprice); + } + + @Test + public void connectToPolygonBlockChainCheckIfAddressIsContract() { + + // Instantiate an node optimized connector to the Polygon network + EVMBlockChainConnector polygonConnector = new EVMBlockChainConnector(EVMChain.POLYGON, true); + + Boolean hardhat_default_account_is_contract = EVMUtils.isContractAddress(polygonConnector, "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"); + assertFalse("Hardhat default account is not a contract but a EOA", hardhat_default_account_is_contract); + + Boolean ghst_contract_address_is_contract = EVMUtils.isContractAddress(polygonConnector, polygonConnector.getChaininfo().getTokenIndex().getTokens().get(PolygonERC20Token.GHST.toString()).getContractAddress()); + assertTrue("Aavegotchi GHST ERC20 contract is a contract", ghst_contract_address_is_contract); + + } + + @Test + public void createCredentialsAndCheckPublicAddress() { + String privateKey1 = "0xb5b1870957d373ef0eeffecc6e4812c0fd08f554b37b233526acc331bf1544f7"; + // https://hukenneth.medium.com/ethereum-using-web3-js-for-message-signing-7e2935b2958c + + Credentials credentials = Credentials.create(privateKey1); + assertEquals("Ensure correct ETH address", "0x12890d2cce102216644c59dae5baed380d84830c", credentials.getAddress()); + } + +} diff --git a/src/test/java/crypto/forestfish/utils/AVMUtilsTest.java b/src/test/java/crypto/forestfish/utils/AVMUtilsTest.java new file mode 100644 index 0000000..2f70e05 --- /dev/null +++ b/src/test/java/crypto/forestfish/utils/AVMUtilsTest.java @@ -0,0 +1,209 @@ +package crypto.forestfish.utils; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AVMUtilsTest { + + @SuppressWarnings("unused") + private static final Logger LOGGER = LoggerFactory.getLogger(CryptUtils.class); + + @Test + public void testCIDv0EncodeToReserveAddress_TESTNET_FROMARCSPEC() { + + /** + * ENCODE (testnet) + * - CID version 0/base58 + * - Encode from CID QmQZyq4b89RfaUw8GESPd2re4hJqB8bnm4kVHNtyQrHnnK -> reserve address EEQYWGGBHRDAMTEVDPVOSDVX3HJQIG6K6IVNR3RXHYOHV64ZWAEISS4CTI + * - with template-ipfs://{ipfscid:0:dag-pb:reserve:sha2-256} + * - https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0019.md + * - https://testnet.algoexplorer.io/asset/66753108 + * - https://cid.ipfs.tech/#QmQZyq4b89RfaUw8GESPd2re4hJqB8bnm4kVHNtyQrHnnK + * - verify with https://hex2algo.vercel.app/ + */ + String cid_str = "QmQZyq4b89RfaUw8GESPd2re4hJqB8bnm4kVHNtyQrHnnK"; + String target_reserve_addr = "EEQYWGGBHRDAMTEVDPVOSDVX3HJQIG6K6IVNR3RXHYOHV64ZWAEISS4CTI"; + + String derived_reserve_addr = AVMUtils.arc19EncodeCIDv0ToAlgorandAddress(cid_str); + assertEquals("Ensure proper encoding of IPFS CID v0 address to reserve address", target_reserve_addr, derived_reserve_addr); + + } + + @Test + public void testDecodeReserveAddressToCIDv0_TESTNET_FROM_ARCSPEC() { + + /** + * DECODE (testnet) + * - CID version 0/base58 + * - Decode from reserve address EEQYWGGBHRDAMTEVDPVOSDVX3HJQIG6K6IVNR3RXHYOHV64ZWAEISS4CTI --> CID QmQZyq4b89RfaUw8GESPd2re4hJqB8bnm4kVHNtyQrHnnK + * - with template-ipfs://{ipfscid:0:dag-pb:reserve:sha2-256} + * - https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0019.md + * - https://testnet.algoexplorer.io/asset/66753108 + * - https://cid.ipfs.tech/#QmQZyq4b89RfaUw8GESPd2re4hJqB8bnm4kVHNtyQrHnnK + * - verify with https://hex2algo.vercel.app/ + * + * Metadata at ipfs://QmQZyq4b89RfaUw8GESPd2re4hJqB8bnm4kVHNtyQrHnnK + { + "name": "MIRROR INSIDE", + "decimals": 0, + "description": "They are here to show me who I am. ", + "image": "ipfs://QmfM89SDKizrDec6JoohuoZVBJGBUDCMRumJRHD5Q99Ffk", + "image_integrity": "sha256-v0ZAr+nh9AzTleNtKXlVlc0ysYUriITpkiNfNB3rwAs=", + "image_mimetype": ".jpg", + "unitName": "MRR", + "assetName": "MIRROR INSIDE", + "properties": { + "creator": { + "name": "nsmshms", + "description": "", + "address": "DXA7CQ64VD324G6F7UYZFFRYTVBOMEPTVS5SWMTS3XU4KMS6WN7GTKWDIY" + }, + "royalties": [{ + "name": "creator", + "addr": "DXA7CQ64VD324G6F7UYZFFRYTVBOMEPTVS5SWMTS3XU4KMS6WN7GTKWDIY", + "share": 5 + } + ], + "keyWords": [], + "publisher": "dartroom.xyz", + "itemListElement": 1, + "numberOfItems": 1, + "arc69": { + "standard": "arc69", + "attributes": [] + } + } + } + * + */ + String reserve_addr = "EEQYWGGBHRDAMTEVDPVOSDVX3HJQIG6K6IVNR3RXHYOHV64ZWAEISS4CTI"; + String target_cid_str = "QmQZyq4b89RfaUw8GESPd2re4hJqB8bnm4kVHNtyQrHnnK"; + + String derived_cid = AVMUtils.arc19DecodeAlgorandAddressToCIDv0(reserve_addr); + assertEquals("Ensure proper decoding of ARC19 reserve address to IPFS CID v0 address", derived_cid, target_cid_str); + + } + + @Test + public void testCIDv0EncodeToReserveAddress_AlgoAstros_MAINNET() { + + /** + * ENCODE (mainnet) + * - CID version 0/base58 + * - Encode from CID QmPntG5UdzPifpDaxMAwi1Fdh4e9Nr6jeeHApLSsrV7LJo -> reserve address FH7B2P3Y2CHSRPPKX33TWDZEEBQXM2O26P7D7P33DU3JOXCMVDIKRPBIHA + * - with template-ipfs://{ipfscid:0:dag-pb:reserve:sha2-256} + * - https://algoexplorer.io/asset/708106509 + * - https://www.reddit.com/r/HEADLINECrypto/comments/u7dxrf/using_arc19_to_make_upgradable_nfts/ + * - https://cid.ipfs.tech/#QmPntG5UdzPifpDaxMAwi1Fdh4e9Nr6jeeHApLSsrV7LJo + * - verify with https://hex2algo.vercel.app/ + */ + String cid_str = "QmRAaAXa6cG4G9AaS3shPgrq6DgSAntYN1mCg1ZANKVQCw"; + String target_reserve_addr = "FH7B2P3Y2CHSRPPKX33TWDZEEBQXM2O26P7D7P33DU3JOXCMVDIKRPBIHA"; + + String derived_reserve_addr = AVMUtils.arc19EncodeCIDv0ToAlgorandAddress(cid_str); + assertEquals("Ensure proper encoding of IPFS CID v0 address to reserve address", target_reserve_addr, derived_reserve_addr); + + } + + @Test + public void testDecodeReserveAddressToCIDv0_AlgoAstros_MAINNET() { + + /** + * DECODE (mainnet) + * - CID version 0/base58 + * - Decode from reserve address FH7B2P3Y2CHSRPPKX33TWDZEEBQXM2O26P7D7P33DU3JOXCMVDIKRPBIHA --> CID QmRAaAXa6cG4G9AaS3shPgrq6DgSAntYN1mCg1ZANKVQCw + * - with template-ipfs://{ipfscid:0:dag-pb:reserve:sha2-256} + * - https://algoexplorer.io/asset/708106509 + * - https://www.reddit.com/r/HEADLINECrypto/comments/u7dxrf/using_arc19_to_make_upgradable_nfts/ + * - https://cid.ipfs.tech/#QmRAaAXa6cG4G9AaS3shPgrq6DgSAntYN1mCg1ZANKVQCw + * - verify with https://hex2algo.vercel.app/ + * + Metadata available on QmRAaAXa6cG4G9AaS3shPgrq6DgSAntYN1mCg1ZANKVQCw: + { + "name": "Astro #220", + "description": "Algo Astros, An NFT Collection from the HEADLINE Team.", + "image": "ipfs://QmPntG5UdzPifpDaxMAwi1Fdh4e9Nr6jeeHApLSsrV7LJo", + "decimals": 0, + "unitName": "ASTRO220", + "image_integrity": "(sha256-18C15D17D33E6AA1C8579F740F9684C069F56C5F8750745C157F79FA528AC997", + "image_mimetype": "image/jpeg", + "properties": { + "Logo": "NFDomains", + "Background": "Code" + } + } + + * + */ + String reserve_addr = "FH7B2P3Y2CHSRPPKX33TWDZEEBQXM2O26P7D7P33DU3JOXCMVDIKRPBIHA"; + String target_cid_str = "QmRAaAXa6cG4G9AaS3shPgrq6DgSAntYN1mCg1ZANKVQCw"; + + String derived_cid = AVMUtils.arc19DecodeAlgorandAddressToCIDv0(reserve_addr); + assertEquals("Ensure proper decoding of ARC19 reserve address to IPFS CID v0 address", derived_cid, target_cid_str); + + } + + @Test + public void testCIDv1EncodeToReserveAddress_Example_MAINNET() { + + /** + * ENCODE + * - CID version 1/base32 + * - Encode from CID bafybeidhlz7iznf5rpxwj5xfukppvkizxf4yp3cnpipjcmvbjkg7rwwwau -> reserve address 6562RSECCFMAUO5MNFCMED4ZKWY7KUB2LTH2SIIFYNZ6BUQTYZ4BQHLQBU + * - with template-ipfs://{ipfscid:1:raw:reserve:sha2-256} + * - https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0019.md + * - https://algoexplorer.io/asset/865610737 + * - https://cid.ipfs.tech/#bafybeidhlz7iznf5rpxwj5xfukppvkizxf4yp3cnpipjcmvbjkg7rwwwau + * - verify with https://hex2algo.vercel.app/ + */ + String cid_str = "bafybeidhlz7iznf5rpxwj5xfukppvkizxf4yp3cnpipjcmvbjkg7rwwwau"; // image ipfs cid here is not metadata!!!!!!!!!!!!! FIX FIND THE metadata json cid and insert here + String target_reserve_addr = "M5PH5DFUXWF66ZHW4WRJ56VJDG4XTB7MJV5B5EJSUFFI36G22YC57SXYKA"; // !! update to actual 6562RSECCFMAUO5MNFCMED4ZKWY7KUB2LTH2SIIFYNZ6BUQTYZ4BQHLQBU + + String derived_reserve_addr = AVMUtils.encodeCIDv1ToARC19AlgorandAddress(cid_str); + assertEquals("Ensure proper encoding of IPFS CIDS v1 address to reserve address", target_reserve_addr, derived_reserve_addr); + + } + + @Test + public void testDecodeReserveAddressToCIDv1_Example_MAINNET() { + + /** + * DECODE (mainnet) + * - CID version 1/base32 + * - Decode from reserve address 6562RSECCFMAUO5MNFCMED4ZKWY7KUB2LTH2SIIFYNZ6BUQTYZ4BQHLQBU -> CID v1 .. + * - with template-ipfs://{ipfscid:1:raw:reserve:sha2-256} + * - https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0019.md + * - https://algoexplorer.io/asset/865610737 + * - https://cid.ipfs.tech/#... + * - verify with https://hex2algo.vercel.app/ + * + Metadata available on CIDv1 bafkreihxpwumraqrlafdxldjitba7gkvwh2vaos4z6uscbodopqnee6gpa: + { + "assetName": "Anon 220", + "unitName": "S1ANON", + "description": "", + "image": "ipfs://bafybeidhlz7iznf5rpxwj5xfukppvkizxf4yp3cnpipjcmvbjkg7rwwwau", + "external_url": "", + "properties": { + "background color": "grey", + "background style": "solid", + "mask color": "grey", + "skin tone": "dark" + }, + "royalty": 0.05, + "register": "Minted by KinnDAO" + } + + */ + String reserve_addr = "6562RSECCFMAUO5MNFCMED4ZKWY7KUB2LTH2SIIFYNZ6BUQTYZ4BQHLQBU"; + String target_cid_str = "bafkreihxpwumraqrlafdxldjitba7gkvwh2vaos4z6uscbodopqnee6gpa"; + + String derived_cid = AVMUtils.arc19DecodeAlgorandAddressToCIDv1(reserve_addr); + assertEquals("Ensure proper decoding of ARC19 reserve address to IPFS CID v1 address", derived_cid, target_cid_str); + + } + +} diff --git a/src/test/java/crypto/forestfish/utils/CryptUtilsTest.java b/src/test/java/crypto/forestfish/utils/CryptUtilsTest.java new file mode 100644 index 0000000..55c7127 --- /dev/null +++ b/src/test/java/crypto/forestfish/utils/CryptUtilsTest.java @@ -0,0 +1,18 @@ +package crypto.forestfish.utils; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CryptUtilsTest { + + @SuppressWarnings("unused") + private static final Logger LOGGER = LoggerFactory.getLogger(CryptUtils.class); + + @Test + public void testGenerateToken() { + String token = CryptUtils.generateSafe288BITToken(); + System.out.println("generated token: " + token); + } + +} diff --git a/src/test/java/crypto/forestfish/utils/GenerateIndexes.java b/src/test/java/crypto/forestfish/utils/GenerateIndexes.java new file mode 100644 index 0000000..e44df5f --- /dev/null +++ b/src/test/java/crypto/forestfish/utils/GenerateIndexes.java @@ -0,0 +1,128 @@ +package crypto.forestfish.utils; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import crypto.forestfish.objects.embedded.evm.BlockchainDetailsEVM; +import crypto.forestfish.objects.evm.model.erc20.ERC20TokenIndex; +import crypto.forestfish.objects.evm.model.nft.EVMNFTIndex; + +public class GenerateIndexes { + + @SuppressWarnings("unused") + private static final Logger LOGGER = LoggerFactory.getLogger(GenerateIndexes.class); + + @Test + public void generateEVMChainIndexJSON() { + String json = BlockchainDetailsEVM.generateEVMChainIndexJSON(); + assertTrue("Ensure welformed result JSON", json.length() > 100); + FilesUtils.writeToFileUNIXNoException(JSONUtils.prettyPrint(json), "evmchainindex.json"); + } + + @Test + public void generateEthereumTokenIndexJSON() { + ERC20TokenIndex idx = BlockchainDetailsEVM.generateEthereumTokenIndex(); + String json = BlockchainDetailsEVM.generateTokenIndexJSON(idx); + assertTrue("Ensure welformed result JSON", json.length() > 100); + FilesUtils.writeToFileUNIXNoException(JSONUtils.prettyPrint(json), "ethereumtokenindex.json"); + } + + @Test + public void generateEthereumNFTTokenIndexJSON() { + EVMNFTIndex idx = BlockchainDetailsEVM.generateEthereumNFTIndex(); + String json = BlockchainDetailsEVM.generateNFTIndexJSON(idx); + assertTrue("Ensure welformed result JSON", json.length() > 100); + FilesUtils.writeToFileUNIXNoException(JSONUtils.prettyPrint(json), "ethereumnfttokenindex.json"); + } + + @Test + public void generateBSCNFTTokenIndexJSON() { + EVMNFTIndex idx = BlockchainDetailsEVM.generateBSCNFTIndex(); + String json = BlockchainDetailsEVM.generateNFTIndexJSON(idx); + assertTrue("Ensure welformed result JSON", json.length() > 100); + FilesUtils.writeToFileUNIXNoException(JSONUtils.prettyPrint(json), "bscnfttokenindex.json"); + } + + @Test + public void generateBitkubNFTTokenIndexJSON() { + EVMNFTIndex idx = BlockchainDetailsEVM.generateBitkubNFTIndex(); + String json = BlockchainDetailsEVM.generateNFTIndexJSON(idx); + assertTrue("Ensure welformed result JSON", json.length() > 100); + FilesUtils.writeToFileUNIXNoException(JSONUtils.prettyPrint(json), "bitkubnfttokenindex.json"); + } + + @Test + public void generatePolygonNFTTokenIndexJSON() { + EVMNFTIndex idx = BlockchainDetailsEVM.generatePolygonNFTIndex(); + String json = BlockchainDetailsEVM.generateNFTIndexJSON(idx); + assertTrue("Ensure welformed result JSON", json.length() > 100); + FilesUtils.writeToFileUNIXNoException(JSONUtils.prettyPrint(json), "polygonnfttokenindex.json"); + } + + @Test + public void generatePolygonTokenIndexJSON() { + ERC20TokenIndex idx = BlockchainDetailsEVM.generatePolygonTokenIndex(); + String json = BlockchainDetailsEVM.generateTokenIndexJSON(idx); + assertTrue("Ensure welformed result JSON", json.length() > 100); + FilesUtils.writeToFileUNIXNoException(JSONUtils.prettyPrint(json), "polygontokenindex.json"); + } + + @Test + public void generateMumbaiTokenIndexJSON() { + ERC20TokenIndex idx = BlockchainDetailsEVM.generateMumbaiTokenIndex(); + String json = BlockchainDetailsEVM.generateTokenIndexJSON(idx); + assertTrue("Ensure welformed result JSON", json.length() > 100); + FilesUtils.writeToFileUNIXNoException(JSONUtils.prettyPrint(json), "mumbaitokenindex.json"); + } + + @Test + public void generateGoerliTokenIndexJSON() { + ERC20TokenIndex idx = BlockchainDetailsEVM.generateGoerliTokenIndex(); + String json = BlockchainDetailsEVM.generateTokenIndexJSON(idx); + assertTrue("Ensure welformed result JSON", json.length() > 100); + FilesUtils.writeToFileUNIXNoException(JSONUtils.prettyPrint(json), "goerlitokenindex.json"); + } + + @Test + public void generateCeloTokenIndexJSON() { + ERC20TokenIndex idx = BlockchainDetailsEVM.generateCeloTokenIndex(); + String json = BlockchainDetailsEVM.generateTokenIndexJSON(idx); + assertTrue("Ensure welformed result JSON", json.length() > 100); + FilesUtils.writeToFileUNIXNoException(JSONUtils.prettyPrint(json), "celotokenindex.json"); + } + + @Test + public void generateBSCTokenIndexJSON() { + ERC20TokenIndex idx = BlockchainDetailsEVM.generateBSCTokenIndex(); + String json = BlockchainDetailsEVM.generateTokenIndexJSON(idx); + assertTrue("Ensure welformed result JSON", json.length() > 100); + FilesUtils.writeToFileUNIXNoException(JSONUtils.prettyPrint(json), "bsctokenindex.json"); + } + + @Test + public void generateBitkubTokenIndexJSON() { + ERC20TokenIndex idx = BlockchainDetailsEVM.generateBitkubTokenIndex(); + String json = BlockchainDetailsEVM.generateTokenIndexJSON(idx); + assertTrue("Ensure welformed result JSON", json.length() > 100); + FilesUtils.writeToFileUNIXNoException(JSONUtils.prettyPrint(json), "bitkubtokenindex.json"); + } + + @Test + public void generateFantomTokenIndexJSON() { + ERC20TokenIndex idx = BlockchainDetailsEVM.generateFantomTokenIndex(); + String json = BlockchainDetailsEVM.generateTokenIndexJSON(idx); + assertTrue("Ensure welformed result JSON", json.length() > 100); + FilesUtils.writeToFileUNIXNoException(JSONUtils.prettyPrint(json), "fantomtokenindex.json"); + } + + @Test + public void generateAvaxTokenIndexJSON() { + ERC20TokenIndex idx = BlockchainDetailsEVM.generateAvaxTokenIndex(); + String json = BlockchainDetailsEVM.generateTokenIndexJSON(idx); + assertTrue("Ensure welformed result JSON", json.length() > 100); + FilesUtils.writeToFileUNIXNoException(JSONUtils.prettyPrint(json), "avaxtokenindex.json"); + } +} diff --git a/src/test/java/crypto/forestfish/utils/IPFSUtilsTest.java b/src/test/java/crypto/forestfish/utils/IPFSUtilsTest.java new file mode 100644 index 0000000..771f69c --- /dev/null +++ b/src/test/java/crypto/forestfish/utils/IPFSUtilsTest.java @@ -0,0 +1,25 @@ +package crypto.forestfish.utils; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class IPFSUtilsTest { + + @SuppressWarnings("unused") + private static final Logger LOGGER = LoggerFactory.getLogger(IPFSUtilsTest.class); + + @Test + public void testIPFSCIDV0() { + // https://ipfs-search.readthedocs.io/en/latest/ipfs_datatypes.html + assertTrue("Make sure the IPFS CIDV0 is valid", IPFSUtils.isValidCIDV0("QmWyDJmrr6cRwEpTF2VGhWDi4uytrDHT8S5BptVdkbhjpv")); + } + + @Test + public void testIPFSCIDV1() { + // https://ipfs-search.readthedocs.io/en/latest/ipfs_datatypes.html + assertTrue("Make sure the IPFS CIDV1 is valid", IPFSUtils.isValidCIDV1("bafkreihqmkkhyq35uwiis5ed5mtudmv5abzdzzgop2urwp44uxutczahv4")); + } +} diff --git a/src/test/java/crypto/forestfish/utils/JWTUtilsTest.java b/src/test/java/crypto/forestfish/utils/JWTUtilsTest.java new file mode 100644 index 0000000..2d72092 --- /dev/null +++ b/src/test/java/crypto/forestfish/utils/JWTUtilsTest.java @@ -0,0 +1,53 @@ +package crypto.forestfish.utils; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import crypto.forestfish.objects.jwt.JWTSignedDecodeResult; +import crypto.forestfish.objects.jwt.JWTUnsignedDecodeResult; + +public class JWTUtilsTest { + + @SuppressWarnings("unused") + private static final Logger LOGGER = LoggerFactory.getLogger(JWTUtilsTest.class); + + @Test + public void decodeKnownJWTString() { + + JWTUnsignedDecodeResult jwtResult1 = JWTUtils.decodeJWT("foo"); + assertTrue("Make sure the JWT is flagged as invalid", jwtResult1.isInvalid_jwt()); + + // https://jwt.io/ + String jwtString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; + + JWTUnsignedDecodeResult jwtResult2 = JWTUtils.decodeJWT(jwtString); + assertFalse("Make sure the JWT is valid", jwtResult2.isInvalid_jwt()); + assertEquals("Make sure alg is parsed properly", "HS256", jwtResult2.getAlg()); + assertEquals("Make sure typ is parsed properly", "JWT", jwtResult2.getTyp()); + assertEquals("Make sure payload is parsed properly", "{\"sub\":\"1234567890\",\"name\":\"John Doe\",\"iat\":1516239022}", jwtResult2.getPayloadJSON()); + } + + @Ignore + @Test + public void signatureVerifyUsingJWKS() { + + String jwtString = "jwt_string_goes_here"; + String b2ctenant = "tenant_goes_here"; + String b2cflow = "flowname_goes_here"; + + JWTSignedDecodeResult jwt_decoded_result = JWTUtils.decodeAndVerifyJWTUsingAzureB2C(jwtString, b2ctenant, b2cflow); + if (null != jwt_decoded_result) { + System.out.println("sig valid: " + jwt_decoded_result.isSignature_valid()); + } else { + System.out.println("Failed to validate"); + } + + } + +} diff --git a/src/test/java/crypto/forestfish/utils/NumUtilsTest.java b/src/test/java/crypto/forestfish/utils/NumUtilsTest.java new file mode 100644 index 0000000..ce047fb --- /dev/null +++ b/src/test/java/crypto/forestfish/utils/NumUtilsTest.java @@ -0,0 +1,19 @@ +package crypto.forestfish.utils; + +import static org.junit.Assert.assertEquals; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NumUtilsTest { + + @SuppressWarnings("unused") + private static final Logger LOGGER = LoggerFactory.getLogger(NumUtilsTest.class); + + @Test + public void testNearestMultipleOf10() { + assertEquals("Nearest multiple of 10 for 4722 is 4720", 4720, NumUtils.getNearestMultipleOf10(4722)); + assertEquals("Nearest multiple of 10 for 2 is 0", 0, NumUtils.getNearestMultipleOf10(2)); + assertEquals("Nearest multiple of 10 for 8 is 10", 10, NumUtils.getNearestMultipleOf10(8)); + } +}