diff --git a/README.md b/README.md
index d3c6189..2f81b97 100644
--- a/README.md
+++ b/README.md
@@ -17,22 +17,28 @@
## 🤖 | Features:
- **Auto registration**
-- **Auto bind referral**
-- **Auto bind twitter**
-- **Auto collect all possible rewards (boxes, energy)**
-- **Auto spin turntable**
-- **Auto inject**
-- **Auto bridge from SEPOLIA to MINT (testnet)**
-- **Auto completing tasks**
-
-
-## 📝 | Description:
-```Auto bridge from SEPOLIA to MINT (testnet)```
-```- The script will bridge a random amount of ETH from SEPOLIA to MINT (testnet).```
-
-```Auto completing tasks```
-```- The script will complete all twitter tasks and testnet```
-
+- **Bind referral**
+- **Bind twitter**
+- **Collect all possible rewards (boxes, energy)**
+- **Spin turntable**
+- **Inject**
+- **Completing tasks**
+- **Bridge from ARB to MINT via CometBridge**
+- **Fix sign**
+- **Export Trees IDs**
+- **Mint the following NFTs:**
+
+ - Green ID
+ - Commemorative NFT
+ - Make NFT Great Again
+ - Flag NFT
+ - Shop NFT
+ - Air3 NFT
+ - SuperMint NFT
+ - Owlto SummerFest NFT
+ - Omnihub SummerFest NFT
+ - Vip3 NFT
+ - Summer NFT
@@ -50,18 +56,22 @@
## ⚙️ Config (config > settings.yaml)
-| Name | Description |
-|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| referral_code | Your referral code |
-| eth_rpc_url | ETH RPC URL (if not have, leave the default value) |
-| sepolia_rpc_url | SEPOLIA RPC URL (if not have, leave the default value) |
-| threads | Number of accounts that will work simultaneously |
-| min_delay_before_start | min delay before start accounts actions (in seconds) |
-| max_delay_before_start | max delay before start accounts actions (in seconds) |
-| min_amount_to_bridge | min amount of ETH to bridge from SEPOLIA to MINT |
-| max_amount_to_bridge | max amount of ETH to bridge from SEPOLIA to MINT |
+| Name | Description |
+|----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| referral_code | Your referral code |
+| mint_rpc_url | MINT RPC URL (if not have, leave the default value) |
+| arb_rpc_url | ARB RPC URL (if not have, leave the default value) |
+| threads | Number of accounts that will work simultaneously |
+| min_delay_before_start | min delay before start accounts actions (in seconds) |
+| max_delay_before_start | max delay before start accounts actions (in seconds) |
| spin_turntable_by_percentage_of_energy | percentage of balance that will be spent on spins (for example, if you have 500 energy daily and you bet 60%, the script will make 1 spin on your account) |
-| shuffle_accounts | shuffle accounts before start |
+| shuffle_accounts | shuffle accounts before start |
+| mint_random_all_nfts | mint random NFTs in list |
+delay_between_mint_min | min delay between mint NFTs (in seconds) |
+| delay_between_mint_max | max delay between mint NFTs (in seconds) |
+| comet_bridge_wallet | main wallet (pr or mnemonic) for bridge from ARB to MINT multi wallets |
+| comet_bridge_amount_min | min amount for bridge from ARB to MINT |
+| comet_bridge_amount_max | max amount for bridge from ARB to MINT |
## ⚙️ Accounts format (config > accounts.txt)
diff --git a/abi/cometa.json b/abi/cometa.json
new file mode 100644
index 0000000..fe3cfb9
--- /dev/null
+++ b/abi/cometa.json
@@ -0,0 +1 @@
+[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AmountMustEqualValue","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"Initialized","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidArgs","type":"error"},{"inputs":[],"name":"InvalidProvider","type":"error"},{"inputs":[],"name":"InvalidRecipientAddress","type":"error"},{"inputs":[],"name":"InvalidValue","type":"error"},{"inputs":[],"name":"OnlyEnabled","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ParamsError","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"Bridged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isEnabled","type":"bool"}],"name":"EnableChanged","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":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"Released","type":"event"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address payable","name":"provider","type":"address"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isEnabled","type":"bool"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"address payable[]","name":"recipients","type":"address[]"},{"internalType":"bytes[]","name":"metadatas","type":"bytes[]"}],"name":"multiRelease","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"release","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isEnabled","type":"bool"}],"name":"setIsEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawEther","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"}]
\ No newline at end of file
diff --git a/abi/commemorative_nft.json b/abi/commemorative_nft.json
new file mode 100644
index 0000000..f6049f2
--- /dev/null
+++ b/abi/commemorative_nft.json
@@ -0,0 +1,1141 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "_nftName",
+ "type": "string"
+ },
+ {
+ "internalType": "string",
+ "name": "_nftToken",
+ "type": "string"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_mintPrice",
+ "type": "uint256"
+ },
+ {
+ "internalType": "string",
+ "name": "_newBaseURI",
+ "type": "string"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_mintStartDate",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_mintEndDate",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_maxSupply",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_maxPerWallet",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "inputs": [],
+ "name": "ApprovalCallerNotOwnerNorApproved",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "ApprovalQueryForNonexistentToken",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "BalanceQueryForZeroAddress",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "MintERC2309QuantityExceedsLimit",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "MintToZeroAddress",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "MintZeroQuantity",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "OwnerQueryForNonexistentToken",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "OwnershipNotInitializedForExtraData",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "ReentrancyGuardReentrantCall",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferCallerNotOwnerNorApproved",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferFromIncorrectOwner",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferToNonERC721ReceiverImplementer",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferToZeroAddress",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "URIQueryForNonexistentToken",
+ "type": "error"
+ },
+ {
+ "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": "uint256",
+ "name": "fromTokenId",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "toTokenId",
+ "type": "uint256"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ }
+ ],
+ "name": "ConsecutiveTransfer",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "minter",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "ref",
+ "type": "address"
+ }
+ ],
+ "name": "FundsDistributed",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "minter",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "Mint",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "minter",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "ref",
+ "type": "address"
+ }
+ ],
+ "name": "MintWithRef",
+ "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": "OWNER",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "_addressData",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "WalletMinted",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "WithdrawStatus",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "_payoutAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "_payoutPercent",
+ "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": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ }
+ ],
+ "name": "balanceOf",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkEndless",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkMaxPerWallet",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkOnlyCorePayoutPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkTotalPayoutPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkUnlimitedSupply",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "coreTeam",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintAmount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "address",
+ "name": "_mintTo",
+ "type": "address"
+ }
+ ],
+ "name": "devMint",
+ "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": "maxPerWallet",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "maxSupply",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintAmount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "address",
+ "name": "_ref",
+ "type": "address"
+ }
+ ],
+ "name": "mint",
+ "outputs": [],
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintAmount",
+ "type": "uint256"
+ }
+ ],
+ "name": "mint",
+ "outputs": [],
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintEndDate",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintPause",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintPrice",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintStartDate",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "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": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutCoreTeamAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutCoreTeamPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutFinalAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutFinalPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "payoutOwnerAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "payoutOwnerPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "payoutRefPercent",
+ "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": "safeTransferFrom",
+ "outputs": [],
+ "stateMutability": "payable",
+ "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": "payable",
+ "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": "_newBaseURI",
+ "type": "string"
+ }
+ ],
+ "name": "setBaseURI",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_address",
+ "type": "address"
+ }
+ ],
+ "name": "setCoreTeam",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_maxperwallet",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMaxPerWallet",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_maxSupply",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMaxSupply",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintPrice",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMintPrice",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintEndDate",
+ "type": "uint256"
+ }
+ ],
+ "name": "setNewEndDate",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintStartDate",
+ "type": "uint256"
+ }
+ ],
+ "name": "setNewStartDate",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bool",
+ "name": "_pauseStatus",
+ "type": "bool"
+ }
+ ],
+ "name": "setPause",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address[]",
+ "name": "_address",
+ "type": "address[]"
+ },
+ {
+ "internalType": "uint256[]",
+ "name": "_percent",
+ "type": "uint256[]"
+ }
+ ],
+ "name": "setPayoutCoreTeam",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_ownerAddress",
+ "type": "address"
+ }
+ ],
+ "name": "setPayoutOwnerAddress",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_percent",
+ "type": "uint256"
+ }
+ ],
+ "name": "setPayoutOwnerPercent",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_percent",
+ "type": "uint256"
+ }
+ ],
+ "name": "setPayoutRefPercent",
+ "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": [],
+ "name": "tokenMinted",
+ "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": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "withdrawAll",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "stateMutability": "payable",
+ "type": "receive"
+ }
+]
\ No newline at end of file
diff --git a/abi/green_id.json b/abi/green_id.json
new file mode 100644
index 0000000..44a6e8d
--- /dev/null
+++ b/abi/green_id.json
@@ -0,0 +1,775 @@
+[
+ {
+ "inputs": [],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "target",
+ "type": "address"
+ }
+ ],
+ "name": "AddressEmptyCode",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "implementation",
+ "type": "address"
+ }
+ ],
+ "name": "ERC1967InvalidImplementation",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "ERC1967NonPayable",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "sender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ },
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ }
+ ],
+ "name": "ERC721IncorrectOwner",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "operator",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "ERC721InsufficientApproval",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "approver",
+ "type": "address"
+ }
+ ],
+ "name": "ERC721InvalidApprover",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "operator",
+ "type": "address"
+ }
+ ],
+ "name": "ERC721InvalidOperator",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ }
+ ],
+ "name": "ERC721InvalidOwner",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "receiver",
+ "type": "address"
+ }
+ ],
+ "name": "ERC721InvalidReceiver",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "sender",
+ "type": "address"
+ }
+ ],
+ "name": "ERC721InvalidSender",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "ERC721NonexistentToken",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "FailedInnerCall",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "InvalidInitialization",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "NotInitializing",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ }
+ ],
+ "name": "OwnableInvalidOwner",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "OwnableUnauthorizedAccount",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "UUPSUnauthorizedCallContext",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32",
+ "name": "slot",
+ "type": "bytes32"
+ }
+ ],
+ "name": "UUPSUnsupportedProxiableUUID",
+ "type": "error"
+ },
+ {
+ "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": false,
+ "internalType": "uint64",
+ "name": "version",
+ "type": "uint64"
+ }
+ ],
+ "name": "Initialized",
+ "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": false,
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "TokenClaimed",
+ "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"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "implementation",
+ "type": "address"
+ }
+ ],
+ "name": "Upgraded",
+ "type": "event"
+ },
+ {
+ "inputs": [],
+ "name": "UPGRADE_INTERFACE_VERSION",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "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": [
+ {
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "claim",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "claimedTokens",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "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": "initialOwner",
+ "type": "address"
+ }
+ ],
+ "name": "initialize",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "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": [
+ {
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "mint",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ {
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "internalType": "struct GreenID.MintParam[]",
+ "name": "params",
+ "type": "tuple[]"
+ }
+ ],
+ "name": "mintBatch",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "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": "proxiableUUID",
+ "outputs": [
+ {
+ "internalType": "bytes32",
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "renounceOwnership",
+ "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": [
+ {
+ "internalType": "address",
+ "name": "operator",
+ "type": "address"
+ },
+ {
+ "internalType": "bool",
+ "name": "approved",
+ "type": "bool"
+ }
+ ],
+ "name": "setApprovalForAll",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "uri",
+ "type": "string"
+ }
+ ],
+ "name": "setDefaultURI",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "uri",
+ "type": "string"
+ }
+ ],
+ "name": "setDynamicURI",
+ "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": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "tokenURI",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "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": [
+ {
+ "internalType": "address",
+ "name": "newImplementation",
+ "type": "address"
+ },
+ {
+ "internalType": "bytes",
+ "name": "data",
+ "type": "bytes"
+ }
+ ],
+ "name": "upgradeToAndCall",
+ "outputs": [],
+ "stateMutability": "payable",
+ "type": "function"
+ }
+]
\ No newline at end of file
diff --git a/abi/make_nft_great_again.json b/abi/make_nft_great_again.json
new file mode 100644
index 0000000..ce0454d
--- /dev/null
+++ b/abi/make_nft_great_again.json
@@ -0,0 +1,752 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_totalsupply",
+ "type": "uint256"
+ },
+ {
+ "internalType": "string",
+ "name": "_name",
+ "type": "string"
+ },
+ {
+ "internalType": "string",
+ "name": "_symbol",
+ "type": "string"
+ },
+ {
+ "internalType": "string",
+ "name": "__base_uri",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "sender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ },
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ }
+ ],
+ "name": "ERC721IncorrectOwner",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "operator",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "ERC721InsufficientApproval",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "approver",
+ "type": "address"
+ }
+ ],
+ "name": "ERC721InvalidApprover",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "operator",
+ "type": "address"
+ }
+ ],
+ "name": "ERC721InvalidOperator",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ }
+ ],
+ "name": "ERC721InvalidOwner",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "receiver",
+ "type": "address"
+ }
+ ],
+ "name": "ERC721InvalidReceiver",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "sender",
+ "type": "address"
+ }
+ ],
+ "name": "ERC721InvalidSender",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "ERC721NonexistentToken",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "ExceedingTotalSupply",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "HasClaimed",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "InvalidMerkleRoot",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "InvalidProof",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "IsStop",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ }
+ ],
+ "name": "OwnableInvalidOwner",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "OwnableUnauthorizedAccount",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "ZeroRoot",
+ "type": "error"
+ },
+ {
+ "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": false,
+ "internalType": "uint256",
+ "name": "_fromTokenId",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "_toTokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "BatchMetadataUpdate",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "_tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "MetadataUpdate",
+ "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": "_baseUri",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "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": "bytes32[]",
+ "name": "proofs",
+ "type": "bytes32[]"
+ }
+ ],
+ "name": "awardItem",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ }
+ ],
+ "name": "balanceOf",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "getApproved",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getAvailableCount",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "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": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "isClaimed",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "isStop",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "merkleRoot",
+ "outputs": [
+ {
+ "internalType": "bytes32",
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "name",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "nextTokenId",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "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": [
+ {
+ "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": "string",
+ "name": "baseUri",
+ "type": "string"
+ }
+ ],
+ "name": "setBaseURI",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bool",
+ "name": "_isStop",
+ "type": "bool"
+ }
+ ],
+ "name": "setStop",
+ "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": "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": [
+ {
+ "internalType": "bytes32",
+ "name": "_tree",
+ "type": "bytes32"
+ }
+ ],
+ "name": "updateTree",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ }
+]
\ No newline at end of file
diff --git a/abi/mint_air3.json b/abi/mint_air3.json
new file mode 100644
index 0000000..5861071
--- /dev/null
+++ b/abi/mint_air3.json
@@ -0,0 +1,1079 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "_nftName",
+ "type": "string"
+ },
+ {
+ "internalType": "string",
+ "name": "_nftToken",
+ "type": "string"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_mintPrice",
+ "type": "uint256"
+ },
+ {
+ "internalType": "string",
+ "name": "_newBaseURI",
+ "type": "string"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_mintStartDate",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_mintEndDate",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_maxSupply",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_maxPerWallet",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "inputs": [],
+ "name": "ApprovalCallerNotOwnerNorApproved",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "ApprovalQueryForNonexistentToken",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "BalanceQueryForZeroAddress",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "MintERC2309QuantityExceedsLimit",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "MintToZeroAddress",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "MintZeroQuantity",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "OwnerQueryForNonexistentToken",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "OwnershipNotInitializedForExtraData",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferCallerNotOwnerNorApproved",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferFromIncorrectOwner",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferToNonERC721ReceiverImplementer",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferToZeroAddress",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "URIQueryForNonexistentToken",
+ "type": "error"
+ },
+ {
+ "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": "uint256",
+ "name": "fromTokenId",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "toTokenId",
+ "type": "uint256"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ }
+ ],
+ "name": "ConsecutiveTransfer",
+ "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": "OWNER",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "_addressData",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "WalletMinted",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "WithdrawStatus",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "_payoutAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "_payoutPercent",
+ "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": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ }
+ ],
+ "name": "balanceOf",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkEndless",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkMaxPerWallet",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkOnlyCorePayoutPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkTotalPayoutPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkUnlimitedSupply",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "coreTeam",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintAmount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "address",
+ "name": "_mintTo",
+ "type": "address"
+ }
+ ],
+ "name": "devMint",
+ "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": "maxPerWallet",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "maxSupply",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintAmount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "address",
+ "name": "_ref",
+ "type": "address"
+ }
+ ],
+ "name": "mint",
+ "outputs": [],
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintAmount",
+ "type": "uint256"
+ }
+ ],
+ "name": "mint",
+ "outputs": [],
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintEndDate",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintPause",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintPrice",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintStartDate",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "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": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutCoreTeamAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutCoreTeamPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutFinalAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutFinalPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "payoutOwnerAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "payoutOwnerPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "payoutRefPercent",
+ "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": "safeTransferFrom",
+ "outputs": [],
+ "stateMutability": "payable",
+ "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": "payable",
+ "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": "_newBaseURI",
+ "type": "string"
+ }
+ ],
+ "name": "setBaseURI",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_address",
+ "type": "address"
+ }
+ ],
+ "name": "setCoreTeam",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_maxperwallet",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMaxPerWallet",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_maxSupply",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMaxSupply",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintPrice",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMintPrice",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintEndDate",
+ "type": "uint256"
+ }
+ ],
+ "name": "setNewEndDate",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintStartDate",
+ "type": "uint256"
+ }
+ ],
+ "name": "setNewStartDate",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bool",
+ "name": "_pauseStatus",
+ "type": "bool"
+ }
+ ],
+ "name": "setPause",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address[]",
+ "name": "_address",
+ "type": "address[]"
+ },
+ {
+ "internalType": "uint256[]",
+ "name": "_percent",
+ "type": "uint256[]"
+ }
+ ],
+ "name": "setPayoutCoreTeam",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_ownerAddress",
+ "type": "address"
+ }
+ ],
+ "name": "setPayoutOwnerAddress",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_percent",
+ "type": "uint256"
+ }
+ ],
+ "name": "setPayoutOwnerPercent",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_percent",
+ "type": "uint256"
+ }
+ ],
+ "name": "setPayoutRefPercent",
+ "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": [],
+ "name": "tokenMinted",
+ "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": "_minter",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "_ref",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_cost",
+ "type": "uint256"
+ }
+ ],
+ "name": "transferETH",
+ "outputs": [],
+ "stateMutability": "payable",
+ "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": "payable",
+ "type": "function"
+ }
+]
\ No newline at end of file
diff --git a/abi/mint_flag.json b/abi/mint_flag.json
new file mode 100644
index 0000000..f6049f2
--- /dev/null
+++ b/abi/mint_flag.json
@@ -0,0 +1,1141 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "_nftName",
+ "type": "string"
+ },
+ {
+ "internalType": "string",
+ "name": "_nftToken",
+ "type": "string"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_mintPrice",
+ "type": "uint256"
+ },
+ {
+ "internalType": "string",
+ "name": "_newBaseURI",
+ "type": "string"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_mintStartDate",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_mintEndDate",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_maxSupply",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_maxPerWallet",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "inputs": [],
+ "name": "ApprovalCallerNotOwnerNorApproved",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "ApprovalQueryForNonexistentToken",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "BalanceQueryForZeroAddress",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "MintERC2309QuantityExceedsLimit",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "MintToZeroAddress",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "MintZeroQuantity",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "OwnerQueryForNonexistentToken",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "OwnershipNotInitializedForExtraData",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "ReentrancyGuardReentrantCall",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferCallerNotOwnerNorApproved",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferFromIncorrectOwner",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferToNonERC721ReceiverImplementer",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferToZeroAddress",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "URIQueryForNonexistentToken",
+ "type": "error"
+ },
+ {
+ "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": "uint256",
+ "name": "fromTokenId",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "toTokenId",
+ "type": "uint256"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ }
+ ],
+ "name": "ConsecutiveTransfer",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "minter",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "ref",
+ "type": "address"
+ }
+ ],
+ "name": "FundsDistributed",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "minter",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "Mint",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "minter",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "ref",
+ "type": "address"
+ }
+ ],
+ "name": "MintWithRef",
+ "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": "OWNER",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "_addressData",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "WalletMinted",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "WithdrawStatus",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "_payoutAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "_payoutPercent",
+ "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": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ }
+ ],
+ "name": "balanceOf",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkEndless",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkMaxPerWallet",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkOnlyCorePayoutPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkTotalPayoutPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkUnlimitedSupply",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "coreTeam",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintAmount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "address",
+ "name": "_mintTo",
+ "type": "address"
+ }
+ ],
+ "name": "devMint",
+ "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": "maxPerWallet",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "maxSupply",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintAmount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "address",
+ "name": "_ref",
+ "type": "address"
+ }
+ ],
+ "name": "mint",
+ "outputs": [],
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintAmount",
+ "type": "uint256"
+ }
+ ],
+ "name": "mint",
+ "outputs": [],
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintEndDate",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintPause",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintPrice",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintStartDate",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "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": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutCoreTeamAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutCoreTeamPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutFinalAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutFinalPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "payoutOwnerAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "payoutOwnerPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "payoutRefPercent",
+ "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": "safeTransferFrom",
+ "outputs": [],
+ "stateMutability": "payable",
+ "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": "payable",
+ "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": "_newBaseURI",
+ "type": "string"
+ }
+ ],
+ "name": "setBaseURI",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_address",
+ "type": "address"
+ }
+ ],
+ "name": "setCoreTeam",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_maxperwallet",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMaxPerWallet",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_maxSupply",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMaxSupply",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintPrice",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMintPrice",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintEndDate",
+ "type": "uint256"
+ }
+ ],
+ "name": "setNewEndDate",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintStartDate",
+ "type": "uint256"
+ }
+ ],
+ "name": "setNewStartDate",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bool",
+ "name": "_pauseStatus",
+ "type": "bool"
+ }
+ ],
+ "name": "setPause",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address[]",
+ "name": "_address",
+ "type": "address[]"
+ },
+ {
+ "internalType": "uint256[]",
+ "name": "_percent",
+ "type": "uint256[]"
+ }
+ ],
+ "name": "setPayoutCoreTeam",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_ownerAddress",
+ "type": "address"
+ }
+ ],
+ "name": "setPayoutOwnerAddress",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_percent",
+ "type": "uint256"
+ }
+ ],
+ "name": "setPayoutOwnerPercent",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_percent",
+ "type": "uint256"
+ }
+ ],
+ "name": "setPayoutRefPercent",
+ "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": [],
+ "name": "tokenMinted",
+ "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": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "withdrawAll",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "stateMutability": "payable",
+ "type": "receive"
+ }
+]
\ No newline at end of file
diff --git a/abi/mint_shop.json b/abi/mint_shop.json
new file mode 100644
index 0000000..5861071
--- /dev/null
+++ b/abi/mint_shop.json
@@ -0,0 +1,1079 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "_nftName",
+ "type": "string"
+ },
+ {
+ "internalType": "string",
+ "name": "_nftToken",
+ "type": "string"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_mintPrice",
+ "type": "uint256"
+ },
+ {
+ "internalType": "string",
+ "name": "_newBaseURI",
+ "type": "string"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_mintStartDate",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_mintEndDate",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_maxSupply",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_maxPerWallet",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "inputs": [],
+ "name": "ApprovalCallerNotOwnerNorApproved",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "ApprovalQueryForNonexistentToken",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "BalanceQueryForZeroAddress",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "MintERC2309QuantityExceedsLimit",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "MintToZeroAddress",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "MintZeroQuantity",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "OwnerQueryForNonexistentToken",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "OwnershipNotInitializedForExtraData",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferCallerNotOwnerNorApproved",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferFromIncorrectOwner",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferToNonERC721ReceiverImplementer",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferToZeroAddress",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "URIQueryForNonexistentToken",
+ "type": "error"
+ },
+ {
+ "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": "uint256",
+ "name": "fromTokenId",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "toTokenId",
+ "type": "uint256"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ }
+ ],
+ "name": "ConsecutiveTransfer",
+ "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": "OWNER",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "_addressData",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "WalletMinted",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "WithdrawStatus",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "_payoutAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "_payoutPercent",
+ "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": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ }
+ ],
+ "name": "balanceOf",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkEndless",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkMaxPerWallet",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkOnlyCorePayoutPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkTotalPayoutPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkUnlimitedSupply",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "coreTeam",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintAmount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "address",
+ "name": "_mintTo",
+ "type": "address"
+ }
+ ],
+ "name": "devMint",
+ "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": "maxPerWallet",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "maxSupply",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintAmount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "address",
+ "name": "_ref",
+ "type": "address"
+ }
+ ],
+ "name": "mint",
+ "outputs": [],
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintAmount",
+ "type": "uint256"
+ }
+ ],
+ "name": "mint",
+ "outputs": [],
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintEndDate",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintPause",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintPrice",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintStartDate",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "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": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutCoreTeamAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutCoreTeamPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutFinalAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutFinalPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "payoutOwnerAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "payoutOwnerPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "payoutRefPercent",
+ "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": "safeTransferFrom",
+ "outputs": [],
+ "stateMutability": "payable",
+ "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": "payable",
+ "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": "_newBaseURI",
+ "type": "string"
+ }
+ ],
+ "name": "setBaseURI",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_address",
+ "type": "address"
+ }
+ ],
+ "name": "setCoreTeam",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_maxperwallet",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMaxPerWallet",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_maxSupply",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMaxSupply",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintPrice",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMintPrice",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintEndDate",
+ "type": "uint256"
+ }
+ ],
+ "name": "setNewEndDate",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintStartDate",
+ "type": "uint256"
+ }
+ ],
+ "name": "setNewStartDate",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bool",
+ "name": "_pauseStatus",
+ "type": "bool"
+ }
+ ],
+ "name": "setPause",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address[]",
+ "name": "_address",
+ "type": "address[]"
+ },
+ {
+ "internalType": "uint256[]",
+ "name": "_percent",
+ "type": "uint256[]"
+ }
+ ],
+ "name": "setPayoutCoreTeam",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_ownerAddress",
+ "type": "address"
+ }
+ ],
+ "name": "setPayoutOwnerAddress",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_percent",
+ "type": "uint256"
+ }
+ ],
+ "name": "setPayoutOwnerPercent",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_percent",
+ "type": "uint256"
+ }
+ ],
+ "name": "setPayoutRefPercent",
+ "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": [],
+ "name": "tokenMinted",
+ "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": "_minter",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "_ref",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_cost",
+ "type": "uint256"
+ }
+ ],
+ "name": "transferETH",
+ "outputs": [],
+ "stateMutability": "payable",
+ "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": "payable",
+ "type": "function"
+ }
+]
\ No newline at end of file
diff --git a/abi/mint_supermint.json b/abi/mint_supermint.json
new file mode 100644
index 0000000..5861071
--- /dev/null
+++ b/abi/mint_supermint.json
@@ -0,0 +1,1079 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "_nftName",
+ "type": "string"
+ },
+ {
+ "internalType": "string",
+ "name": "_nftToken",
+ "type": "string"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_mintPrice",
+ "type": "uint256"
+ },
+ {
+ "internalType": "string",
+ "name": "_newBaseURI",
+ "type": "string"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_mintStartDate",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_mintEndDate",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_maxSupply",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_maxPerWallet",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "inputs": [],
+ "name": "ApprovalCallerNotOwnerNorApproved",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "ApprovalQueryForNonexistentToken",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "BalanceQueryForZeroAddress",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "MintERC2309QuantityExceedsLimit",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "MintToZeroAddress",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "MintZeroQuantity",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "OwnerQueryForNonexistentToken",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "OwnershipNotInitializedForExtraData",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferCallerNotOwnerNorApproved",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferFromIncorrectOwner",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferToNonERC721ReceiverImplementer",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "TransferToZeroAddress",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "URIQueryForNonexistentToken",
+ "type": "error"
+ },
+ {
+ "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": "uint256",
+ "name": "fromTokenId",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "toTokenId",
+ "type": "uint256"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ }
+ ],
+ "name": "ConsecutiveTransfer",
+ "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": "OWNER",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "_addressData",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "WalletMinted",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "WithdrawStatus",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "_payoutAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "_payoutPercent",
+ "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": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ }
+ ],
+ "name": "balanceOf",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkEndless",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkMaxPerWallet",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkOnlyCorePayoutPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkTotalPayoutPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "checkUnlimitedSupply",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "coreTeam",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintAmount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "address",
+ "name": "_mintTo",
+ "type": "address"
+ }
+ ],
+ "name": "devMint",
+ "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": "maxPerWallet",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "maxSupply",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintAmount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "address",
+ "name": "_ref",
+ "type": "address"
+ }
+ ],
+ "name": "mint",
+ "outputs": [],
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintAmount",
+ "type": "uint256"
+ }
+ ],
+ "name": "mint",
+ "outputs": [],
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintEndDate",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintPause",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintPrice",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintStartDate",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "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": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutCoreTeamAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutCoreTeamPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutFinalAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "payoutFinalPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "payoutOwnerAddress",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "payoutOwnerPercent",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "payoutRefPercent",
+ "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": "safeTransferFrom",
+ "outputs": [],
+ "stateMutability": "payable",
+ "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": "payable",
+ "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": "_newBaseURI",
+ "type": "string"
+ }
+ ],
+ "name": "setBaseURI",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_address",
+ "type": "address"
+ }
+ ],
+ "name": "setCoreTeam",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_maxperwallet",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMaxPerWallet",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_maxSupply",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMaxSupply",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintPrice",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMintPrice",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintEndDate",
+ "type": "uint256"
+ }
+ ],
+ "name": "setNewEndDate",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintStartDate",
+ "type": "uint256"
+ }
+ ],
+ "name": "setNewStartDate",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bool",
+ "name": "_pauseStatus",
+ "type": "bool"
+ }
+ ],
+ "name": "setPause",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address[]",
+ "name": "_address",
+ "type": "address[]"
+ },
+ {
+ "internalType": "uint256[]",
+ "name": "_percent",
+ "type": "uint256[]"
+ }
+ ],
+ "name": "setPayoutCoreTeam",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_ownerAddress",
+ "type": "address"
+ }
+ ],
+ "name": "setPayoutOwnerAddress",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_percent",
+ "type": "uint256"
+ }
+ ],
+ "name": "setPayoutOwnerPercent",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_percent",
+ "type": "uint256"
+ }
+ ],
+ "name": "setPayoutRefPercent",
+ "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": [],
+ "name": "tokenMinted",
+ "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": "_minter",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "_ref",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_cost",
+ "type": "uint256"
+ }
+ ],
+ "name": "transferETH",
+ "outputs": [],
+ "stateMutability": "payable",
+ "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": "payable",
+ "type": "function"
+ }
+]
\ No newline at end of file
diff --git a/abi/omnihub.json b/abi/omnihub.json
new file mode 100644
index 0000000..0537010
--- /dev/null
+++ b/abi/omnihub.json
@@ -0,0 +1,250 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_deployProtocolFee",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_mintProtocolFee",
+ "type": "uint256"
+ },
+ {
+ "internalType": "string",
+ "name": "_contractBaseURI",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ }
+ ],
+ "name": "OwnableInvalidOwner",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "OwnableUnauthorizedAccount",
+ "type": "error"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "deployedContractAddress",
+ "type": "address"
+ }
+ ],
+ "name": "ContractDeployed",
+ "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"
+ },
+ {
+ "stateMutability": "payable",
+ "type": "fallback"
+ },
+ {
+ "inputs": [],
+ "name": "contractBaseURI",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "_name",
+ "type": "string"
+ },
+ {
+ "internalType": "string",
+ "name": "_symbol",
+ "type": "string"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_price",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_supply",
+ "type": "uint256"
+ }
+ ],
+ "name": "deploy",
+ "outputs": [
+ {
+ "internalType": "contract ERC721OmniHubContract",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "deployProtocolFee",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "mintProtocolFee",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "renounceOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "_contractBaseURI",
+ "type": "string"
+ }
+ ],
+ "name": "setContractBaseURI",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_deployProtocolFee",
+ "type": "uint256"
+ }
+ ],
+ "name": "setDeployProtocolFee",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_mintProtocolFee",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMintProtocolFee",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "transferOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "version",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "withdraw",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "stateMutability": "payable",
+ "type": "receive"
+ }
+]
\ No newline at end of file
diff --git a/abi/summer_nft.json b/abi/summer_nft.json
new file mode 100644
index 0000000..e54c346
--- /dev/null
+++ b/abi/summer_nft.json
@@ -0,0 +1,54 @@
+[
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "recipient",
+ "type": "address"
+ },
+ {
+ "name": "amount",
+ "type": "uint256"
+ },
+ {
+ "name": "currency",
+ "type": "address"
+ },
+ {
+ "name": "value",
+ "type": "uint256"
+ },
+ {
+ "components": [
+ {
+ "name": "proof",
+ "type": "bytes32[]"
+ },
+ {
+ "name": "maxAmount",
+ "type": "uint256"
+ },
+ {
+ "name": "minValue",
+ "type": "uint256"
+ },
+ {
+ "name": "currency",
+ "type": "address"
+ }
+ ],
+ "name": "details",
+ "type": "tuple"
+ },
+ {
+ "name": "extraData",
+ "type": "bytes"
+ }
+ ],
+ "name": "claim",
+ "outputs": [],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
+ }
+]
diff --git a/abi/vip3_nft.json b/abi/vip3_nft.json
new file mode 100644
index 0000000..8c199c1
--- /dev/null
+++ b/abi/vip3_nft.json
@@ -0,0 +1,862 @@
+[
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ },
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "level",
+ "type": "uint256"
+ }
+ ],
+ "name": "Attest",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "Burn",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "uint8",
+ "name": "version",
+ "type": "uint8"
+ }
+ ],
+ "name": "Initialized",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "Paused",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "Revoke",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "bytes32",
+ "name": "role",
+ "type": "bytes32"
+ },
+ {
+ "indexed": true,
+ "internalType": "bytes32",
+ "name": "previousAdminRole",
+ "type": "bytes32"
+ },
+ {
+ "indexed": true,
+ "internalType": "bytes32",
+ "name": "newAdminRole",
+ "type": "bytes32"
+ }
+ ],
+ "name": "RoleAdminChanged",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "bytes32",
+ "name": "role",
+ "type": "bytes32"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "sender",
+ "type": "address"
+ }
+ ],
+ "name": "RoleGranted",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "bytes32",
+ "name": "role",
+ "type": "bytes32"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "sender",
+ "type": "address"
+ }
+ ],
+ "name": "RoleRevoked",
+ "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"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "Unpaused",
+ "type": "event"
+ },
+ {
+ "inputs": [],
+ "name": "BURN_METHOD",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "DEFAULT_ADMIN_ROLE",
+ "outputs": [
+ {
+ "internalType": "bytes32",
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "GoldLevel",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "MINT_METHOD",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "PROVENANCE",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "ROLE_ADMIN",
+ "outputs": [
+ {
+ "internalType": "bytes32",
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "ROLE_SUPER_ADMIN",
+ "outputs": [
+ {
+ "internalType": "bytes32",
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "_tokenIdCounter",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "_value",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "_tokenLevelMap",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_to",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_level",
+ "type": "uint256"
+ }
+ ],
+ "name": "attest",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "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": "baseTokenURI",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address[]",
+ "name": "addrs",
+ "type": "address[]"
+ },
+ {
+ "internalType": "uint256",
+ "name": "level",
+ "type": "uint256"
+ }
+ ],
+ "name": "batchAttest",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address[]",
+ "name": "addrs",
+ "type": "address[]"
+ }
+ ],
+ "name": "batchRevoke",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_tokenId",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "deadline",
+ "type": "uint256"
+ },
+ {
+ "internalType": "bytes",
+ "name": "signature",
+ "type": "bytes"
+ }
+ ],
+ "name": "burn",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ }
+ ],
+ "name": "getLevel",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32",
+ "name": "role",
+ "type": "bytes32"
+ }
+ ],
+ "name": "getRoleAdmin",
+ "outputs": [
+ {
+ "internalType": "bytes32",
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32",
+ "name": "role",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "grantRole",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32",
+ "name": "role",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "hasRole",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "_name",
+ "type": "string"
+ },
+ {
+ "internalType": "string",
+ "name": "_symbol",
+ "type": "string"
+ },
+ {
+ "internalType": "string",
+ "name": "_baseTokenURI",
+ "type": "string"
+ }
+ ],
+ "name": "initialize",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_to",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "deadline",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "level",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ },
+ {
+ "internalType": "bytes",
+ "name": "signature",
+ "type": "bytes"
+ }
+ ],
+ "name": "mint",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "payable",
+ "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": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "pause",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "paused",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32",
+ "name": "role",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "renounceRole",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ }
+ ],
+ "name": "revoke",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32",
+ "name": "role",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "revokeRole",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "uri",
+ "type": "string"
+ }
+ ],
+ "name": "setBaseTokenURI",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "_name",
+ "type": "string"
+ }
+ ],
+ "name": "setName",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "_symbol",
+ "type": "string"
+ }
+ ],
+ "name": "setSymbol",
+ "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": "address",
+ "name": "from",
+ "type": "address"
+ }
+ ],
+ "name": "tokenIdOf",
+ "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": [],
+ "name": "unpause",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "deadline",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "level",
+ "type": "uint256"
+ },
+ {
+ "internalType": "bytes",
+ "name": "signature",
+ "type": "bytes"
+ }
+ ],
+ "name": "updateLevel",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "level",
+ "type": "uint256"
+ }
+ ],
+ "name": "updateLevelByAdmin",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "withdraw",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ }
+]
\ No newline at end of file
diff --git a/config/__init__.py b/config/__init__.py
deleted file mode 100644
index 8476494..0000000
--- a/config/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from .load_config import load_config
diff --git a/config/accounts.txt b/config/accounts.txt
index bf871f9..4fd849a 100644
--- a/config/accounts.txt
+++ b/config/accounts.txt
@@ -1,4 +1 @@
-auth_token|mnemonic/pk|proxy
-auth_token|mnemonic/pk|proxy
-auth_token|mnemonic/pk|proxy
-auth_token|mnemonic/pk|proxy
\ No newline at end of file
+auth_token|pk_or_mnemonic|ip:port:user:pass
\ No newline at end of file
diff --git a/config/settings.yaml b/config/settings.yaml
index 450fd18..d1d2d18 100644
--- a/config/settings.yaml
+++ b/config/settings.yaml
@@ -1,15 +1,32 @@
+# MAIN SETTINGS #
referral_code: C4ACD869 # Referral code (If you don't have one, pls, use mine)
-
-eth_rpc_url: https://eth.llamarpc.com # RPC URL (Ethereum)
-sepolia_rpc_url: https://ethereum-sepolia-rpc.publicnode.com # RPC URL (Sepolia)
-
threads: 3
-min_delay_before_start: 30 # seconds
-max_delay_before_start: 60 # seconds
+mint_rpc_url: https://rpc.mintchain.io
+arb_rpc_url: https://arbitrum.llamarpc.com
-min_amount_to_bridge: 0.00001 # ETH
-max_amount_to_bridge: 0.0003 # ETH
+min_delay_before_start: 60 # seconds
+max_delay_before_start: 120 # seconds
-spin_turntable_by_percentage_of_energy: 60 # 0-100
+spin_turntable_by_percentage_of_energy: 0 # 0-100
shuffle_accounts: True # True/False
+# MAIN SETTINGS #
+#
+#
+#
+## MINT NFTs ##
+# available: mint_comm_nft, mint_make_nft_great_again, mint_flag, mint_shop, mint_air3, mint_supermint, mint_owlto_summer_nft, mint_omnihub_summer_nft, mint_summer_nft, mint_vip3_nft, mint_green_id
+mint_random_all_nfts: ["mint_make_nft_great_again", "mint_flag", "mint_shop", "mint_air3", "mint_supermint", "mint_owlto_summer_nft", "mint_omnihub_summer_nft", "mint_summer_nft", "mint_vip3_nft", "mint_green_id", "mint_comm_nft"]
+delay_between_mint_min: 10 # seconds
+delay_between_mint_max: 20 # seconds
+## MINT NFTs ##
+#
+#
+#
+#
+## COMET BRIDGE ##
+comet_bridge_wallet: "" # pk or mnemonic from which script will send ETH to bridge to your multiwallet
+comet_bridge_amount_min: 0.00115 # ETH
+comet_bridge_amount_max: 0.0012 # ETH
+## COMET BRIDGE ##
+
diff --git a/console/images/console.png b/console/images/console.png
index f391945..9edc6db 100644
Binary files a/console/images/console.png and b/console/images/console.png differ
diff --git a/console/main.py b/console/main.py
index e28c170..8ca5a57 100644
--- a/console/main.py
+++ b/console/main.py
@@ -13,18 +13,52 @@
class Console:
- MODULES = ("Test the Mint Testnet Bridge", "Complete Tasks", "Claim Daily Rewards and Inject", "Exit")
+ MODULES = (
+ "Complete Tasks",
+ "Mint Random All NFTs",
+ "Claim Daily Rewards and Inject",
+ "Bridge ETH to MINT (via Comet)",
+ "Only Claim Daily Rewards",
+ "Export Trees IDs",
+ "Fix sign",
+ "Mint Green ID",
+ "Mint Commemorative NFT",
+ "Mint OmniHub Collection",
+ "Mint Make NFT Great Again",
+ "Mint Flag NFT",
+ "Mint Shop NFT",
+ "Mint Air3 NFT",
+ "Mint SuperMint NFT",
+ "Mint Owlto SummerFest NFT",
+ "Mint Omnihub SummerFest NFT",
+ "Mint Vip3 NFT",
+ "Exit",
+ )
MODULES_DATA = {
- "Test the Mint Testnet Bridge": "bridge",
"Complete Tasks": "tasks",
"Claim Daily Rewards and Inject": "rewards",
+ "Mint Random All NFTs": "mint_random_all_nfts",
+ "Bridge ETH to MINT (via Comet)": "comet_bridge",
+ "Export Trees IDs": "export_trees_ids",
+ "Only Claim Daily Rewards": "only_rewards",
+ "Fix sign": "fix_sign",
+ "Mint Commemorative NFT": "mint_comm_nft",
+ "Mint Make NFT Great Again": "mint_make_nft_great_again",
+ "Mint Flag NFT": "mint_flag",
+ "Mint Shop NFT": "mint_shop",
+ "Mint Air3 NFT": "mint_air3",
+ "Mint SuperMint NFT": "mint_supermint",
+ "Mint Owlto SummerFest NFT": "mint_owlto_summer_nft",
+ "Mint Omnihub SummerFest NFT": "mint_omnihub_summer_nft",
+ "Mint Vip3 NFT": "mint_vip3_nft",
+ "Mint Green ID": "mint_green_id",
}
@staticmethod
def show_dev_info():
os.system("cls")
tprint("JamBit")
- print("\033[36m" + "VERSION: " + "\033[34m" + "2.0" + "\033[34m")
+ print("\033[36m" + "VERSION: " + "\033[34m" + "3.0" + "\033[34m")
print(
"\033[36m" + "Channel: " + "\033[34m" + "https://t.me/JamBitPY" + "\033[34m"
)
@@ -64,7 +98,9 @@ def get_module(self):
def build(self) -> None:
os.system("cls")
self.show_dev_info()
- info_log(f"\n- accounts: {len(config.accounts)}\n- referral_code: {config.referral_code}\n- threads: {config.threads}\n")
+ info_log(
+ f"\n- accounts: {len(config.accounts)}\n- referral_code: {config.referral_code}\n- threads: {config.threads}\n"
+ )
module = self.get_module()
if module == "Exit":
diff --git a/core/api.py b/core/api.py
new file mode 100644
index 0000000..08c4fad
--- /dev/null
+++ b/core/api.py
@@ -0,0 +1,574 @@
+import asyncio
+import random
+
+import httpx
+import pyuseragents
+import names
+
+from typing import Literal, List
+from noble_tls import Session, Client
+from Jam_Twitter_API.account_async import TwitterAccountAsync
+
+from models import *
+from loader import config as configuration
+
+from .wallet import Wallet
+from .modules import *
+from .exceptions.base import APIError
+
+
+class MintChainAPI(Wallet):
+ API_URL = "https://www.mintchain.io/api"
+
+ def __init__(self, account_data: Account):
+ super().__init__(
+ mnemonic=account_data.pk_or_mnemonic, rpc_url=configuration.mint_rpc_url
+ )
+ self.account = account_data
+ self.session = self.setup_session()
+ self.twitter_account: TwitterAccountAsync = None # type: ignore
+
+ @property
+ def jwt_token(self) -> str:
+ return self.session.headers["authorization"].replace("Bearer ", "")
+
+ @property
+ async def energy_balance(self) -> int:
+ return (await self.user_info()).energy
+
+ @property
+ async def tree_size(self) -> int:
+ return (await self.user_info()).tree
+
+ @property
+ async def rank(self) -> int:
+ return (await self.rank_info()).rank
+
+ def setup_session(self) -> Session:
+ session = Session(client=Client.CHROME_120)
+ session.random_tls_extension_order = True
+
+ session.timeout_seconds = 15
+ session.headers = {
+ "accept": "application/json, text/plain, */*",
+ "accept-language": "en-US,en;q=0.9,ru;q=0.8",
+ "referer": "https://www.mintchain.io",
+ "user-agent": pyuseragents.random(),
+ }
+ session.proxies = {
+ "http": self.account.proxy,
+ "https": self.account.proxy,
+ }
+ return session
+
+ async def send_request(
+ self,
+ request_type: Literal["POST", "GET"] = "POST",
+ method: str = None,
+ json_data: dict = None,
+ params: dict = None,
+ url: str = None,
+ headers: dict = None,
+ verify: bool = True,
+ ):
+ def _verify_response(_response: dict) -> dict:
+ if "code" in _response:
+ if _response["code"] not in (10000, 200):
+ raise APIError(
+ f"{_response.get('msg')} | Method: {method} | URL: {url}"
+ )
+
+ return _response
+
+ if request_type == "POST":
+ if not url:
+ response = await self.session.post(
+ f"{self.API_URL}{method}",
+ json=json_data,
+ params=params,
+ headers=headers,
+ )
+
+ else:
+ response = await self.session.post(
+ url, json=json_data, params=params, headers=headers
+ )
+
+ else:
+ if not url:
+ response = await self.session.get(
+ f"{self.API_URL}{method}", params=params, headers=headers
+ )
+
+ else:
+ response = await self.session.get(url, params=params, headers=headers)
+
+ response.raise_for_status()
+ if verify:
+ return _verify_response(response.json())
+ else:
+ return response.json()
+
+ async def is_daily_reward_claimed(self) -> bool:
+ response = await self.send_request(
+ request_type="GET", method="/tree/energy-list"
+ )
+ return response["result"][-1]["freeze"]
+
+ async def green_id(self) -> dict:
+ response = await self.send_request(request_type="GET", method="/tree/green-id")
+ return response
+
+ async def get_energy_list(self, user_id: str = None) -> EnergyListData:
+ if not user_id:
+ response = await self.send_request(
+ request_type="GET", method="/tree/energy-list"
+ )
+ else:
+ response = await self.send_request(
+ request_type="GET",
+ method="/tree/steal/energy-list",
+ params={"id": user_id},
+ )
+
+ if (
+ response
+ and response.get("msg", "")
+ == "You are too late, the energy has already been collected by its owner."
+ ):
+ return EnergyListData(result=[])
+
+ return EnergyListData(**response)
+
+ async def get_task_list(self) -> TaskListData:
+ response = await self.send_request(
+ request_type="GET", method=f"/tree/task-list?address={self.keypair.address}"
+ )
+ return TaskListData(**response)
+
+ async def complete_tasks(self):
+ task_list = await self.get_task_list()
+ for task in task_list.result:
+ if task.spec not in ("discord-follow", "stake"):
+ if task.claimed:
+ logger.debug(
+ f"Account: {self.account.auth_token} | Task already completed: {task.name}"
+ )
+ continue
+
+ try:
+ if task.spec in ("twitter-post", "twitter-follow"):
+ if not self.twitter_account:
+ self.load_twitter_account()
+
+ if task.spec == "twitter-follow":
+ user_id = self.twitter_account.get_user_id(
+ "Mint_Blockchain"
+ )
+ self.twitter_account.follow(user_id)
+ await self.submit_task_id(task.id)
+
+ else:
+ tweet_text = "I'm collecting @Mint_Blockchain's ME $MINT in the #MintForest🌳!\n\nMint is the L2 for NFT industry, powered by @nftscan_com and @Optimism.\n\nJoin Mint Forest here: https://mintchain.io/mint-forest\n\n#MintBlockchain #L2forNFT"
+
+ data = self.twitter_account.tweet(tweet_text)
+ tweet_url = f'https://x.com/JammerCrypto/status/{data["data"]["create_tweet"]["tweet_results"]["result"]["rest_id"]}'
+ await self.submit_task_id(task.id, twitter_post=tweet_url)
+
+ else:
+ await self.submit_task_id(task.id)
+
+ logger.debug(
+ f"Account: {self.account.auth_token} | Task completed: {task.name} | Reward: {task.amount} energy"
+ )
+ await asyncio.sleep(3)
+
+ except APIError as error:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to complete task: {task.name} | {error}"
+ )
+ await asyncio.sleep(3)
+
+ async def claim_daily_rewards(self) -> None:
+ energy_list = await self.get_energy_list()
+ for energy in energy_list.result:
+ json_data = {
+ "uid": energy.uid,
+ "amount": energy.amount,
+ "includes": energy.includes,
+ "type": energy.type,
+ "id": energy.id,
+ }
+
+ if energy.type == "daily":
+ if energy.freeze:
+ logger.debug(
+ f"Account: {self.account.auth_token} | Daily reward already claimed"
+ )
+ continue
+ else:
+ json_data["freeze"] = energy.freeze
+
+ await self.send_request(method="/tree/claim", json_data=json_data)
+ logger.debug(
+ f"Account: {self.account.auth_token} | Claimed {energy.amount} energy | Type: {energy.type}"
+ )
+ await asyncio.sleep(1)
+
+ await self.claim_boxes()
+
+ async def bind_invite_code(self) -> ResponseData:
+ jwt_token = self.jwt_token
+
+ session = Session(client=Client.CHROME_120)
+ session.headers = {
+ "accept": "application/json, text/plain, */*",
+ "accept-language": "sk-SK,sk;q=0.9,en-US;q=0.8,en;q=0.7",
+ "authorization": "Bearer",
+ "referer": "https://www.mintchain.io/mint-forest",
+ "user-agent": self.session.headers["user-agent"],
+ }
+
+ json_data = {
+ "code": str(configuration.referral_code),
+ "jwtToken": jwt_token,
+ }
+
+ response = await session.get(
+ "https://www.mintchain.io/api/tree/invitation", params=json_data
+ )
+ return ResponseData(**response.json())
+
+ async def load_twitter_account(self) -> None:
+ self.twitter_account = await TwitterAccountAsync.run(
+ auth_token=self.account.auth_token,
+ setup_session=True,
+ proxy=self.account.proxy,
+ )
+
+ async def connect_twitter(self) -> dict:
+ params = {
+ "code_challenge": "mintchain",
+ "code_challenge_method": "plain",
+ "client_id": "enpfUjhndkdrdHhld29aTW96eGM6MTpjaQ",
+ "redirect_uri": "https://www.mintchain.io/mint-forest",
+ "response_type": "code",
+ "scope": "tweet.read users.read follows.read offline.access",
+ "state": "mintchain",
+ }
+
+ if not self.twitter_account:
+ await self.load_twitter_account()
+
+ approved_code = await self.twitter_account.bind_account_v2(params)
+
+ params = {
+ "code": approved_code,
+ "jwtToken": self.jwt_token,
+ "address": self.keypair.address,
+ }
+ response = await self.send_request(
+ url="https://www.mintchain.io/api/twitter/verify", params=params
+ )
+ return response
+
+ async def rank_info(self) -> RankData:
+ response = await self.send_request(request_type="GET", method="/tree/me-rank")
+ return RankData(**response["result"])
+
+ async def user_info(self, tree_id: str = None) -> UserInfo:
+ if not tree_id:
+ response = await self.send_request(
+ request_type="GET", method="/tree/user-info"
+ )
+ else:
+ response = await self.send_request(
+ request_type="GET", method="/tree/user-info", params={"treeid": tree_id}
+ )
+
+ return UserInfo(**response["result"])
+
+ async def assets(self) -> List[AssetData]:
+ response = await self.send_request(request_type="GET", method="/tree/asset")
+ return [AssetData(**data) for data in response["result"]]
+
+ async def open_box(self, box_id: int) -> OpenBoxData:
+ json_data = {
+ "boxId": box_id,
+ }
+
+ response = await self.send_request(method="/tree/open-box", json_data=json_data)
+ return OpenBoxData(**response["result"])
+
+ async def claim_boxes(self):
+ assets = await self.assets()
+ for asset in assets:
+ if not asset.createdAt:
+ try:
+ opened_box_data = await self.open_box(asset.id)
+ logger.debug(
+ f"Account: {self.account.auth_token} | Box opened | Reward: {opened_box_data.energy} energy"
+ )
+ except APIError as error:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to open box: {asset.type} | {error}"
+ )
+
+ await asyncio.sleep(1)
+
+ async def spin_turntable(self) -> TurntableData:
+ response = await self.send_request(
+ request_type="GET", method="/tree/turntable/open"
+ )
+ return TurntableData(**response["result"])
+
+ async def steal_claim(self, user_id: str) -> None:
+ json_data = {
+ "id": user_id,
+ }
+
+ await self.send_request(
+ request_type="GET", method="/tree/steal/claim", params=json_data
+ )
+
+ async def inject(self, amount: int = None) -> InjectData:
+ if not amount:
+ amount = await self.energy_balance
+
+ if amount <= 0:
+ return InjectData(code=0, result=False, msg="Energy balance is 0")
+
+ json_data = {
+ "address": self.keypair.address,
+ "energy": amount,
+ }
+
+ response = await self.send_request(method="/tree/inject", json_data=json_data)
+ return InjectData(**response)
+
+ async def fix_sign(self) -> None:
+ await self.send_request(request_type="GET", method="/tree/fix-sign")
+
+ async def submit_task_id(self, task_id: int, twitter_post: str = None) -> None:
+ json_data = {
+ "id": task_id,
+ }
+
+ if twitter_post:
+ json_data["twitterurl"] = twitter_post
+
+ await self.send_request(method="/tree/task-submit", json_data=json_data)
+
+ async def get_make_nft_great_again_proofs(self) -> list[str]:
+ params = {
+ "user": self.keypair.address,
+ }
+
+ headers = {
+ "accept": "application/json, text/plain, */*",
+ "accept-language": "en-US,en;q=0.9,ru;q=0.8",
+ "priority": "u=1, i",
+ "referer": "https://mn-ga.com/?allow=true",
+ "user-agent": self.session.headers["user-agent"],
+ }
+
+ async with httpx.AsyncClient(headers=headers) as client:
+ response = await client.get(
+ "https://mn-ga.com/api/reward/nft-proof", params=params
+ )
+ response = response.json()
+ return response["msg"]["proof"]
+
+ async def mint_commemorative_nft(self) -> tuple[bool | Any, str]:
+ try:
+ transaction = await self.build_commemorative_nft_transaction()
+ status, tx_hash = await self.send_and_verify_transaction(transaction)
+ return status, tx_hash
+
+ except Exception as error:
+ raise Exception(f"Failed to mint commemorative NFT: {error}")
+
+ async def mint_flag_nft(self) -> tuple[bool | Any, str]:
+ try:
+ transaction = await self.build_mint_flag_transaction()
+ status, tx_hash = await self.send_and_verify_transaction(transaction)
+ return status, tx_hash
+
+ except Exception as error:
+ raise Exception(f"Failed to mint Flag NFT: {error}")
+
+ async def mint_shop_nft(self) -> tuple[bool | Any, str]:
+ try:
+ transaction = await self.build_mint_shop_transaction()
+ status, tx_hash = await self.send_and_verify_transaction(transaction)
+ return status, tx_hash
+
+ except Exception as error:
+ raise Exception(f"Failed to mint Shop NFT: {error}")
+
+ async def mint_air3_nft(self) -> tuple[bool | Any, str]:
+ try:
+ transaction = await self.build_mint_air3_transaction()
+ status, tx_hash = await self.send_and_verify_transaction(transaction)
+ return status, tx_hash
+
+ except Exception as error:
+ raise Exception(f"Failed to mint Air3 NFT: {error}")
+
+ async def mint_green_id_nft(self, tree_id: int) -> tuple[bool | Any, str]:
+ try:
+ transaction = await self.build_green_id_nft_transaction(tree_id)
+ status, tx_hash = await self.send_and_verify_transaction(transaction)
+ return status, tx_hash
+
+ except Exception as error:
+ raise Exception(f"Failed to mint Green ID NFT: {error}")
+
+ async def mint_vip3_nft(self) -> tuple[bool | Any, str]:
+ try:
+ client = Vip3API(self.account)
+ await client.login()
+ mint_data = await client.get_mint_data()
+ transaction = await self.build_vip3_nft_transaction(mint_data)
+
+ status, tx_hash = await self.send_and_verify_transaction(transaction)
+ return status, tx_hash
+
+ except Exception as error:
+ raise Exception(f"Failed to mint VIP3 NFT: {error}")
+
+ async def mint_supermint_nft(self) -> tuple[bool | Any, str]:
+ try:
+ transaction = await self.build_mint_supermint_transaction()
+ status, tx_hash = await self.send_and_verify_transaction(transaction)
+ return status, tx_hash
+
+ except Exception as error:
+ raise Exception(f"Failed to mint SuperMint NFT: {error}")
+
+ async def mint_summer_nft(self) -> tuple[bool | Any, str]:
+ try:
+ transaction = await self.build_summer_nft_transaction()
+ status, tx_hash = await self.send_and_verify_transaction(transaction)
+ return status, tx_hash
+
+ except Exception as error:
+ raise Exception(f"Failed to mint Summer NFT: {error}")
+
+ async def mint_make_nft_great_again(self) -> tuple[bool | Any, str]:
+ try:
+ proofs = await self.get_make_nft_great_again_proofs()
+ transaction = await self.build_make_nft_great_again_transaction(
+ proofs=proofs
+ )
+
+ status, tx_hash = await self.send_and_verify_transaction(transaction)
+ return status, tx_hash
+
+ except Exception as error:
+ raise Exception(f"Failed to mint Make NFT Great Again: {error}")
+
+ async def mint_createx_collection(self) -> tuple[bool | Any, str]:
+ try:
+ name = f"{names.get_first_name()} {names.get_last_name()}"
+ symbol = random.choice(
+ [f"{name[:3].upper()}", f"{name[:4].upper()}", f"{name[:5].upper()}"]
+ )
+ description = f"Collection of {name} NFTs"
+ price = random.uniform(0.00001, 0.05)
+ royalty_fee = random.randint(1, 50)
+
+ client = CreateXAPI(
+ mnemonic=self.account.pk_or_mnemonic, rpc_url=configuration.mint_rpc_url
+ )
+ await client.login()
+ collection_id = await client.create_collection(
+ name=name,
+ symbol=symbol,
+ description=description,
+ price=str(price),
+ royalty_fee=str(royalty_fee),
+ )
+ await client.create_query_collection(collection_id=collection_id)
+ trx_data = await client.deploy(collection_id=collection_id)
+
+ transaction = await self.build_createx_collection_transaction(trx_data)
+ status, tx_hash = await self.send_and_verify_transaction(transaction)
+ return status, tx_hash
+
+ except Exception as error:
+ raise Exception(f"Failed to mint OmniHub collection: {error}")
+
+ async def mint_owlto_summer_fest_nft(self) -> tuple[bool | Any, str]:
+ try:
+ transaction = await self.build_owlto_summer_fest_nft_transaction()
+ status, tx_hash = await self.send_and_verify_transaction(transaction)
+ return status, tx_hash
+
+ except Exception as error:
+ raise Exception(f"Failed to mint Owlto Summer Fest NFT: {error}")
+
+ async def mint_omnihub_summer_fest_nft(self) -> tuple[bool | Any, str]:
+ try:
+ transaction = await self.build_omnihub_summer_fest_nft_transaction()
+ status, tx_hash = await self.send_and_verify_transaction(transaction)
+ return status, tx_hash
+
+ except Exception as error:
+ raise Exception(f"Failed to mint OmniHub Summer Fest NFT: {error}")
+
+ async def verify_wallet(self) -> ResponseData:
+ json_data = {
+ "jwtToken": self.jwt_token,
+ }
+
+ response = await self.send_request(method="/wallet/verify", json_data=json_data)
+ return ResponseData(**response)
+
+ async def join_airdrop(self) -> dict:
+ messages = self.sign_mint_message("airdrop")
+
+ params = {
+ "wallet_address": self.keypair.address,
+ "signature": messages.signed_message,
+ "message": messages.message,
+ "invite_code": "",
+ }
+
+ return await self.send_request(
+ request_type="GET",
+ url="https://mpapi.mintchain.io/api/user/sign",
+ params=params,
+ )
+
+ async def login(self):
+ messages = self.sign_mint_message("forest")
+
+ json_data = {
+ "address": self.keypair.address,
+ "signature": messages.signed_message,
+ "message": messages.message,
+ }
+
+ response = await self.send_request(method="/tree/login", json_data=json_data)
+ data = LoginWalletData(**response["result"])
+ self.session.headers["authorization"] = f"Bearer {data.access_token}"
+
+ if data.user.status == "pending":
+ await self.verify_wallet()
+
+ if not data.user.twitter:
+ await self.connect_twitter()
+ logger.debug(
+ f"Account: {self.account.auth_token} | Twitter account connected"
+ )
+
+ if not data.user.inviteId:
+ await self.bind_invite_code()
+ logger.debug(f"Account: {self.account.auth_token} | Referral code bound")
+
+ await self.green_id()
+ await self.assets()
+ await self.rank_info()
+ await self.user_info()
+ await self.get_energy_list()
diff --git a/core/bot.py b/core/bot.py
new file mode 100644
index 0000000..0c4c9d3
--- /dev/null
+++ b/core/bot.py
@@ -0,0 +1,549 @@
+import asyncio
+import random
+from typing import Any
+
+from models import Account
+from loguru import logger
+from loader import config
+
+from .api import MintChainAPI
+from .exceptions.base import APIError
+from .modules import CometBridge
+
+
+class Bot(MintChainAPI):
+ def __init__(self, account: Account):
+ super().__init__(account_data=account)
+
+ async def safe_operation(
+ self,
+ operation: callable,
+ success_message: str,
+ error_message: str,
+ retries: int = 0,
+ delay: int = 3,
+ argument: Any = None,
+ ) -> bool:
+ for _ in range(retries):
+ try:
+ await operation() if argument is None else await operation(argument)
+ logger.success(
+ f"Account: {self.account.auth_token} | {success_message}"
+ )
+ return True
+
+ except APIError as error:
+ logger.error(
+ f"Account: {self.account.auth_token} | {error_message}: {error}"
+ )
+ return False
+ except Exception as error:
+ logger.error(
+ f"Account: {self.account.auth_token} | {error_message}: {error} | {'Retrying..' if retries > 0 else ''}"
+ )
+ await asyncio.sleep(delay)
+ continue
+
+ return False
+
+ async def process_login(self) -> bool:
+ logger.info(f"Account: {self.account.auth_token} | Logging in..")
+ return await self.safe_operation(
+ operation=self.login,
+ success_message="Logged in",
+ error_message="Failed to login",
+ retries=3,
+ )
+
+ async def process_fix_sign(self) -> bool:
+ return await self.safe_operation(
+ operation=self.fix_sign,
+ success_message="Fixed sign",
+ error_message="Failed to fix sign",
+ retries=2,
+ )
+
+ async def process_claim_daily_reward(self) -> bool:
+ return await self.safe_operation(
+ operation=self.claim_daily_rewards,
+ success_message="Finished claiming daily rewards",
+ error_message="Failed to claim daily rewards",
+ delay=10,
+ retries=3,
+ )
+
+ async def process_inject(self) -> bool:
+ return await self.safe_operation(
+ operation=self.inject,
+ success_message="Finished injecting energy",
+ error_message="Failed to inject energy",
+ retries=3,
+ )
+
+ async def process_spin_turntable(self) -> bool:
+ if config.spin_turntable_by_percentage_of_energy > 0:
+ try:
+ balance = await self.energy_balance
+ if balance < 300:
+ logger.warning(
+ f"Account: {self.account.auth_token} | Not enough energy to spin turntable"
+ )
+ return True
+
+ amount = int(
+ balance * (config.spin_turntable_by_percentage_of_energy / 100)
+ )
+ number_of_spins = int(amount // 300)
+ if number_of_spins > 5:
+ number_of_spins = 5
+
+ for _ in range(number_of_spins):
+ reward = await self.spin_turntable()
+ logger.success(
+ f"Account: {self.account.auth_token} | Opened turntable | Reward: {reward.energy} energy"
+ )
+ await asyncio.sleep(3)
+
+ except Exception as error:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to spin turntable: {error}"
+ )
+
+ return True
+
+ async def process_show_user_info(self) -> None:
+ try:
+ info = await self.tree_size
+ logger.success(
+ f"Account: {self.account.auth_token} | Total injected energy: {info} | Daily actions done.."
+ )
+
+ except Exception as error:
+ logger.warning(
+ f"Account: {self.account.auth_token} | Failed to get user info: {error} | Daily actions done.."
+ )
+
+ async def process_mint_comm_nft(self) -> None:
+ try:
+ await self.check_balance()
+
+ try:
+ await self.join_airdrop()
+ except Exception as error:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to join airdrop: {error}"
+ )
+
+ logger.info(
+ f"Account: {self.account.auth_token} | Minting commemorative NFT.."
+ )
+ status, transaction_hash = await self.mint_commemorative_nft()
+
+ if status:
+ logger.success(
+ f"Account: {self.account.auth_token} | Minted commemorative NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+ else:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to mint commemorative NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+
+ except Exception as error:
+ logger.error(f"Account: {self.account.auth_token} | {error}")
+
+ async def process_mint_make_nft_great_again(self) -> None:
+ try:
+ await self.check_balance()
+ logger.info(f"Account: {self.account.auth_token} | Minting MNGA NFT..")
+ status, transaction_hash = await self.mint_make_nft_great_again()
+
+ if status:
+ logger.success(
+ f"Account: {self.account.auth_token} | Minted MNGA NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+ else:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to mint MNGA NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+
+ except Exception as error:
+ logger.error(f"Account: {self.account.auth_token} | {error}")
+
+ async def process_mint_flag_nft(self) -> None:
+ try:
+ await self.check_balance()
+ logger.info(f"Account: {self.account.auth_token} | Minting Flag NFT..")
+ status, transaction_hash = await self.mint_flag_nft()
+
+ if status:
+ logger.success(
+ f"Account: {self.account.auth_token} | Minted Flag NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+ else:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to mint Flag NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+
+ except Exception as error:
+ logger.error(f"Account: {self.account.auth_token} | {error}")
+
+ async def process_mint_supermint_nft(self) -> None:
+ try:
+ await self.check_balance()
+ logger.info(f"Account: {self.account.auth_token} | Minting SuperMint NFT..")
+ status, transaction_hash = await self.mint_supermint_nft()
+
+ if status:
+ logger.success(
+ f"Account: {self.account.auth_token} | Minted SuperMint NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+ else:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to mint SuperMint NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+
+ except Exception as error:
+ logger.error(f"Account: {self.account.auth_token} | {error}")
+
+ async def process_mint_air3_nft(self) -> None:
+ try:
+ await self.check_balance()
+ logger.info(f"Account: {self.account.auth_token} | Minting Air3 NFT..")
+ status, transaction_hash = await self.mint_air3_nft()
+
+ if status:
+ logger.success(
+ f"Account: {self.account.auth_token} | Minted Air3 NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+ else:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to mint Air3 NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+
+ except Exception as error:
+ logger.error(f"Account: {self.account.auth_token} | {error}")
+
+ async def process_mint_shop_nft(self) -> None:
+ try:
+ await self.check_balance()
+ logger.info(f"Account: {self.account.auth_token} | Minting Shop NFT..")
+ status, transaction_hash = await self.mint_shop_nft()
+
+ if status:
+ logger.success(
+ f"Account: {self.account.auth_token} | Minted Shop NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+ else:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to mint Shop NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+
+ except Exception as error:
+ logger.error(f"Account: {self.account.auth_token} | {error}")
+
+ async def process_join_airdrop(self) -> None:
+ try:
+ await self.join_airdrop()
+
+ except APIError as error:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to join airdrop: {error}"
+ )
+ return
+
+ except Exception as error:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to join airdrop: {error}"
+ )
+
+ async def process_mint_vip3_nft(self) -> None:
+ try:
+ await self.check_balance()
+
+ try:
+ await self.join_airdrop()
+ except Exception as error:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to join airdrop: {error}"
+ )
+
+ logger.info(f"Account: {self.account.auth_token} | Minting VIP3 NFT..")
+ status, transaction_hash = await self.mint_vip3_nft()
+
+ if status:
+ logger.success(
+ f"Account: {self.account.auth_token} | Minted VIP3 NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+ else:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to mint VIP3 NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+
+ except Exception as error:
+ logger.error(f"Account: {self.account.auth_token} | {error}")
+
+ async def process_mint_green_id(self) -> None:
+ try:
+ await self.check_balance()
+ logger.info(f"Account: {self.account.auth_token} | Minting Green ID..")
+
+ tree_id = await self.process_get_tree_id()
+ if not tree_id:
+ return
+
+ status, transaction_hash = await self.mint_green_id_nft(int(tree_id))
+
+ if status:
+ logger.success(
+ f"Account: {self.account.auth_token} | Minted Green ID | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+ else:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to mint Green ID | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+
+ except Exception as error:
+ logger.error(f"Account: {self.account.auth_token} | {error}")
+
+ # async def process_mint_omnihub_collection(self) -> None:
+ # try:
+ # if await self.human_balance() < 0.0001:
+ # raise Exception("Insufficient balance to mint OmniHub collection | Required: 0.0001 ETH")
+ #
+ # logger.info(f"Account: {self.account.auth_token} | Minting OmniHub collection")
+ # status, transaction_hash = await self.mint_omnihub_collection()
+ #
+ # if status:
+ # logger.success(
+ # f"Account: {self.account.auth_token} | Minted OmniHub collection | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ # )
+ # else:
+ # logger.error(
+ # f"Account: {self.account.auth_token} | Failed to mint OmniHub collection | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ # )
+ #
+ # except Exception as error:
+ # logger.error(
+ # f"Account: {self.account.auth_token} | {error}"
+ # )
+
+ async def process_mint_summer_nft(self) -> None:
+ try:
+ if await self.human_balance() < 0.0001:
+ raise Exception(
+ "Insufficient balance to mint Summer NFT | Required: 0.0001 ETH"
+ )
+
+ logger.info(f"Account: {self.account.auth_token} | Minting Summer NFT..")
+ status, transaction_hash = await self.mint_summer_nft()
+
+ if status:
+ logger.success(
+ f"Account: {self.account.auth_token} | Minted Summer NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+ else:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to mint Summer NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+
+ except Exception as error:
+ logger.error(f"Account: {self.account.auth_token} | {error}")
+
+ async def process_mint_owlto_summer_fest_nft(self) -> None:
+ try:
+ if await self.human_balance() < 0.0001:
+ raise Exception(
+ "Insufficient balance to mint Owlto Summer Fest NFT | Required: 0.0001 ETH"
+ )
+
+ logger.info(
+ f"Account: {self.account.auth_token} | Minting Owlto Summer Fest NFT.."
+ )
+ status, transaction_hash = await self.mint_owlto_summer_fest_nft()
+
+ if status:
+ logger.success(
+ f"Account: {self.account.auth_token} | Minted Owlto Summer Fest NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+ else:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to mint Owlto Summer Fest NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+
+ except Exception as error:
+ logger.error(f"Account: {self.account.auth_token} | {error}")
+
+ async def process_mint_omnihub_summer_nft(self) -> None:
+ try:
+ if await self.human_balance() < 0.0001:
+ raise Exception(
+ "Insufficient balance to mint OmniHub Summer NFT | Required: 0.0001 ETH"
+ )
+
+ logger.info(
+ f"Account: {self.account.auth_token} | Minting OmniHub Summer NFT.."
+ )
+ status, transaction_hash = await self.mint_omnihub_summer_fest_nft()
+
+ if status:
+ logger.success(
+ f"Account: {self.account.auth_token} | Minted OmniHub Summer NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+ else:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to mint OmniHub Summer NFT | Transaction: https://explorer.mintchain.io/tx/{transaction_hash}"
+ )
+
+ except Exception as error:
+ logger.error(f"Account: {self.account.auth_token} | {error}")
+
+ async def process_comet_bridge(self) -> None:
+ try:
+ amount_to_bridge = random.uniform(
+ config.comet_bridge_amount_min, config.comet_bridge_amount_max
+ )
+ client = CometBridge(
+ amount_to_bridge=amount_to_bridge,
+ to_address=self.keypair.address,
+ mnemonic=config.comet_bridge_wallet,
+ rpc_url=config.arb_rpc_url,
+ )
+
+ logger.info(
+ f"Account: {self.account.auth_token} | Bridging {amount_to_bridge} ETH to MINT (via Comet)"
+ )
+ transaction = await client.build_bridge_transaction()
+ status, tx_hash = await client.send_and_verify_transaction(transaction)
+
+ if status:
+ logger.success(
+ f"Account: {self.account.auth_token} | Bridged {amount_to_bridge} ETH to MINT | Transaction: https://arbiscan.io/tx/{tx_hash}"
+ )
+
+ else:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to bridge {amount_to_bridge} ETH to MINT | Transaction: https://arbiscan.io/tx/{tx_hash}"
+ )
+
+ except Exception as error:
+ logger.error(
+ f"Account: {self.account.auth_token} | Error while bridging: {error}"
+ )
+
+ async def process_complete_tasks(self):
+ return await self.safe_operation(
+ operation=self.complete_tasks,
+ success_message="Finished completing tasks",
+ error_message="Failed to complete tasks",
+ delay=10,
+ retries=3,
+ )
+
+ async def process_get_tree_id(self) -> bool | str:
+ for _ in range(2):
+ try:
+ if not await self.process_login():
+ return False
+
+ user_info = await self.user_info()
+ return str(user_info.treeId)
+
+ except Exception as error:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to get tree id: {error} | Retrying.."
+ )
+ await asyncio.sleep(1)
+
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to get tree id after 2 retries | Skipping.."
+ )
+ return False
+
+ async def process_mint_random_all_nfts(self) -> None:
+ operations_dict = {
+ "mint_comm_nft": self.process_mint_comm_nft,
+ "mint_make_nft_great_again": self.process_mint_make_nft_great_again,
+ "mint_flag": self.process_mint_flag_nft,
+ "mint_shop": self.process_mint_shop_nft,
+ "mint_air3": self.process_mint_air3_nft,
+ "mint_supermint": self.process_mint_supermint_nft,
+ "mint_summer_nft": self.process_mint_summer_nft,
+ "mint_owlto_summer_nft": self.process_mint_owlto_summer_fest_nft,
+ "mint_omnihub_summer_nft": self.process_mint_omnihub_summer_nft,
+ "mint_vip3_nft": self.process_mint_vip3_nft,
+ "mint_green_id": self.process_mint_green_id,
+ }
+
+ mint_modules = config.mint_random_all_nfts
+ random.shuffle(mint_modules)
+
+ for module in mint_modules:
+ operation = operations_dict.get(module)
+ if operation:
+ try:
+ await operation()
+ except Exception as error:
+ logger.error(
+ f"Account: {self.account.auth_token} | Failed to process {module}: {error}"
+ )
+ finally:
+ delay = random.randint(
+ config.delay_between_mint_min, config.delay_between_mint_max
+ )
+ logger.debug(
+ f"Account: {self.account.auth_token} | Sleeping for {delay} seconds.."
+ )
+ await asyncio.sleep(delay)
+
+ async def start(self):
+ random_delay = random.randint(
+ config.min_delay_before_start, config.max_delay_before_start
+ )
+ logger.info(
+ f"Account: {self.account.auth_token} | Work will start in {random_delay} seconds.."
+ )
+ await asyncio.sleep(random_delay)
+
+ operations_dict = {
+ "rewards": [
+ self.process_login,
+ self.process_claim_daily_reward,
+ self.process_spin_turntable,
+ self.process_inject,
+ self.process_show_user_info,
+ ],
+ "only_rewards": [
+ self.process_login,
+ self.process_claim_daily_reward,
+ self.process_show_user_info,
+ ],
+ "fix_sign": [self.process_login, self.process_show_user_info],
+ "mint_comm_nft": [self.process_mint_comm_nft],
+ "mint_make_nft_great_again": [self.process_mint_make_nft_great_again],
+ "mint_summer_nft": [self.process_mint_summer_nft],
+ "mint_flag": [self.process_mint_flag_nft],
+ "mint_shop": [self.process_mint_shop_nft],
+ "mint_air3": [self.process_mint_air3_nft],
+ "mint_supermint": [self.process_mint_supermint_nft],
+ "comet_bridge": [self.process_comet_bridge],
+ "mint_random_all_nfts": [self.process_mint_random_all_nfts],
+ "mint_owlto_summer_nft": [self.process_mint_owlto_summer_fest_nft],
+ "mint_omnihub_summer_nft": [self.process_mint_omnihub_summer_nft],
+ "mint_vip3_nft": [self.process_mint_vip3_nft],
+ "tasks": [self.process_login, self.process_complete_tasks],
+ "default": [self.process_login, self.process_complete_tasks],
+ }
+
+ operations = operations_dict.get(config.module, operations_dict["default"])
+
+ try:
+ for operation in operations:
+ if not await operation():
+ break
+
+ except Exception as error:
+ logger.error(
+ f"Account: {self.account.auth_token} | Unhandled error: {error}"
+ )
+ finally:
+ logger.success(f"Account: {self.account.auth_token} | Finished")
diff --git a/core/exceptions/base.py b/core/exceptions/base.py
new file mode 100644
index 0000000..62304da
--- /dev/null
+++ b/core/exceptions/base.py
@@ -0,0 +1,10 @@
+class APIError(Exception):
+ """Base class for API exceptions"""
+
+ pass
+
+
+class StealEnergyError(APIError):
+ """Raised when failed to steal energy"""
+
+ pass
diff --git a/core/modules/__init__.py b/core/modules/__init__.py
new file mode 100644
index 0000000..a41a251
--- /dev/null
+++ b/core/modules/__init__.py
@@ -0,0 +1,3 @@
+from .comet_bridge import CometBridge
+from .createx_api import CreateXAPI
+from .vip3_api import Vip3API
diff --git a/core/modules/comet_bridge.py b/core/modules/comet_bridge.py
new file mode 100644
index 0000000..3ecf1be
--- /dev/null
+++ b/core/modules/comet_bridge.py
@@ -0,0 +1,75 @@
+import json
+
+from pydantic import HttpUrl
+from web3 import AsyncWeb3
+
+from core.wallet import Wallet
+
+
+class CometBridge(Wallet):
+ def __init__(
+ self,
+ amount_to_bridge: float,
+ to_address: str,
+ mnemonic: str,
+ rpc_url: HttpUrl | str,
+ ):
+ super().__init__(mnemonic, rpc_url)
+ self.amount_to_bridge = amount_to_bridge
+ self.to_address = to_address
+
+ @staticmethod
+ def pad_to_32(x) -> str:
+ return x.rjust(64, "0")
+
+ async def build_bridge_transaction(self):
+ function_signature = "0x78499054"
+ destination_gas_cost = AsyncWeb3.to_wei(0.0003, "ether")
+ amount = AsyncWeb3.to_wei(self.amount_to_bridge, "ether") + destination_gas_cost
+ token_address = "0x0000000000000000000000000000000000000000".lower()
+ provider_address = "0xb50ac92d6d8748ac42721c25a3e2c84637385a6b".lower()
+
+ metadata = {"targetChain": "185", "targetAddress": self.to_address}
+
+ encoded_metadata = (
+ f"data:,{json.dumps(metadata, separators=(',', ':'))}".encode("utf-8").hex()
+ )
+ transaction_data = (
+ function_signature
+ + self.pad_to_32(hex(amount)[2:])
+ + self.pad_to_32(token_address[2:])
+ + self.pad_to_32(provider_address[2:].lower())
+ + self.pad_to_32(
+ hex(32 * 4)[2:]
+ ) # Смещение для данных (4 параметра по 32 байта)
+ + self.pad_to_32(
+ hex(len(encoded_metadata) // 2)[2:]
+ ) # Длина metadata в байтах
+ + encoded_metadata
+ )
+ final_data = f"{transaction_data}0000000000000000"
+
+ gas_limit = await self.eth.estimate_gas(
+ {
+ "chainId": 42161,
+ "from": self.keypair.address,
+ "to": AsyncWeb3.to_checksum_address(
+ "0x0fbCf4a62036E96C4F6770B38a9B536Aa14d1846"
+ ),
+ "value": amount,
+ "data": final_data,
+ }
+ )
+
+ return {
+ "chainId": 42161,
+ "from": self.keypair.address,
+ "to": AsyncWeb3.to_checksum_address(
+ "0x0fbCf4a62036E96C4F6770B38a9B536Aa14d1846"
+ ),
+ "value": amount,
+ "gas": gas_limit,
+ "gasPrice": await self.eth.gas_price,
+ "nonce": await self.transactions_count(),
+ "data": final_data,
+ }
diff --git a/core/modules/createx_api.py b/core/modules/createx_api.py
new file mode 100644
index 0000000..e5207a0
--- /dev/null
+++ b/core/modules/createx_api.py
@@ -0,0 +1,239 @@
+import asyncio
+import json
+import time
+from datetime import datetime, timezone
+from typing import Literal
+
+import pyuseragents
+from eth_account.messages import encode_typed_data
+from noble_tls import Client, Session
+
+from loader import config
+from models import Account
+from core.exceptions.base import APIError
+from core.wallet import Wallet
+
+
+class CreateXAPI(Wallet):
+ API_URL = "https://createx.art/api"
+
+ def __init__(self, account_data: Account):
+ super().__init__(account_data.pk_or_mnemonic, config.mint_rpc_url)
+ self.account = account_data
+ self.session = self.setup_session()
+
+ def setup_session(self) -> Session:
+ session = Session(client=Client.CHROME_120)
+ session.random_tls_extension_order = True
+
+ session.timeout_seconds = 15
+ session.headers = {
+ "accept": "application/json, text/plain, */*",
+ "accept-language": "en-US,en;q=0.9,ru;q=0.8",
+ "priority": "u=1, i",
+ "referer": "https://createx.art/",
+ "user-agent": pyuseragents.random(),
+ }
+ session.proxies = {
+ "http": self.account.proxy,
+ "https": self.account.proxy,
+ }
+ return session
+
+ async def send_request(
+ self,
+ request_type: Literal["POST", "GET"] = "POST",
+ method: str = None,
+ json_data: dict = None,
+ params: dict = None,
+ url: str = None,
+ headers: dict = None,
+ verify: bool = True,
+ ):
+ def _verify_response(_response: dict) -> dict:
+ if "status" in _response:
+ if _response["status"] != 0:
+ raise APIError(f"{_response.get('msg')} | Method: {method}")
+
+ return _response
+
+ raise APIError(f"{_response} | Method: {method}")
+
+ if request_type == "POST":
+ if not url:
+ response = await self.session.post(
+ f"{self.API_URL}{method}",
+ json=json_data,
+ params=params,
+ headers=headers,
+ )
+
+ else:
+ response = await self.session.post(
+ url, json=json_data, params=params, headers=headers
+ )
+
+ else:
+ if not url:
+ response = await self.session.get(
+ f"{self.API_URL}{method}", params=params, headers=headers
+ )
+
+ else:
+ response = await self.session.get(url, params=params, headers=headers)
+
+ response.raise_for_status()
+ if verify:
+ return _verify_response(response.json())
+ else:
+ return response.json()
+
+ async def get_timestamp(self) -> tuple[int, str]:
+ response = await self.send_request(
+ request_type="GET",
+ method="/v1/creator/public/timestamp",
+ )
+
+ timestamp = response["data"]["timestamp_ms"]
+ timestamp_seconds = timestamp / 1000
+ dt = datetime.fromtimestamp(timestamp_seconds, tz=timezone.utc)
+ formatted_date = dt.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z"
+
+ return timestamp, formatted_date
+
+ async def get_login_data(self) -> tuple[str, str]:
+ timestamp, formatted_date = await self.get_timestamp()
+
+ message = {
+ "types": {
+ "Message": [
+ {"name": "Message", "type": "string"},
+ {"name": "URI", "type": "string"},
+ {"name": "Version", "type": "string"},
+ {"name": "ChainId", "type": "uint256"},
+ {"name": "Nonce", "type": "uint256"},
+ {"name": "issuedAt", "type": "string"},
+ ],
+ "EIP712Domain": [
+ {"name": "name", "type": "string"},
+ {"name": "version", "type": "string"},
+ {"name": "chainId", "type": "uint256"},
+ ],
+ },
+ "primaryType": "Message",
+ "domain": {"name": "", "version": "1", "chainId": "185"},
+ "message": {
+ "Message": "Sign in to the CreateX",
+ "URI": "https://createx.art",
+ "Version": "1",
+ "ChainId": "185",
+ "Nonce": timestamp,
+ "issuedAt": formatted_date,
+ },
+ }
+ signed_json = {
+ "domain": {"name": "", "version": "1", "chainId": 185},
+ "message": {
+ "Message": "Sign in to the CreateX",
+ "URI": "https://createx.art",
+ "Version": "1",
+ "ChainId": 185,
+ "Nonce": timestamp,
+ "issuedAt": formatted_date,
+ },
+ "primaryType": "Message",
+ "types": {
+ "EIP712Domain": [
+ {"name": "name", "type": "string"},
+ {"name": "version", "type": "string"},
+ {"name": "chainId", "type": "uint256"},
+ ],
+ "Message": [
+ {"name": "Message", "type": "string"},
+ {"name": "URI", "type": "string"},
+ {"name": "Version", "type": "string"},
+ {"name": "ChainId", "type": "uint256"},
+ {"name": "Nonce", "type": "uint256"},
+ {"name": "issuedAt", "type": "string"},
+ ],
+ },
+ }
+
+ encoded_message = encode_typed_data(full_message=message)
+ signed_message = self.keypair.sign_message(encoded_message)
+ return signed_message.signature.hex(), json.dumps(signed_json)
+
+ async def create_collection(
+ self, name: str, symbol: str, description: str, price: str, royalty_fee: str
+ ) -> str:
+ json_data = {
+ "chain": "MINTCHAIN",
+ "chain_name": "",
+ "is_single_create": True,
+ "nftUpload": True,
+ "collection_name": name,
+ "symbol": symbol,
+ "description": description,
+ "is_limit_count": False,
+ "mint_price": price,
+ "mint_start_time": int(time.time() * 1000),
+ "mint_end_time": 0,
+ "mint_qty_per_user": "1",
+ "royalty_fee": royalty_fee,
+ "royalty_fee_recipient": self.keypair.address,
+ "collection_id": False,
+ "is_image_update": False,
+ "media_file_count": 1,
+ "currency": "eth",
+ }
+
+ response = await self.send_request(
+ request_type="POST",
+ method="/v1/createx/create/collection",
+ json_data=json_data,
+ )
+ return response["data"]["collection_id"]
+
+ async def deploy(self, collection_id: str) -> str:
+ json_data = {
+ "chain": "MINTCHAIN",
+ "chain_name": "MINTCHAIN",
+ "collection_id": collection_id,
+ "is_sbt": 0,
+ }
+
+ response = await self.send_request(
+ request_type="POST",
+ method="/v1/createx/create/direct_deploy",
+ json_data=json_data,
+ )
+
+ return f"0x{response['data']['bin']}"
+
+ async def create_query_collection(self, collection_id: str) -> dict:
+ json_data = {
+ "chain": "MINTCHAIN",
+ "chain_name": "MINTCHAIN",
+ "collection_id": collection_id,
+ }
+
+ response = await self.send_request(
+ request_type="POST",
+ method="/v1/createx/create/query_collection",
+ json_data=json_data,
+ )
+ return response["data"]
+
+ async def login(self) -> dict:
+ signature, signed_json = await self.get_login_data()
+
+ response = await self.send_request(
+ method="/v1/creator/auth/login_with_type_data",
+ json_data={
+ "msg_signature": signature,
+ "msg_signer": self.keypair.address,
+ "signed_json": signed_json,
+ },
+ )
+
+ return response
diff --git a/core/modules/vip3_api.py b/core/modules/vip3_api.py
new file mode 100644
index 0000000..1251a23
--- /dev/null
+++ b/core/modules/vip3_api.py
@@ -0,0 +1,128 @@
+import asyncio
+import json
+import time
+from datetime import datetime, timezone
+from typing import Literal, Tuple, Any
+
+import pyuseragents
+from eth_account.messages import encode_typed_data, encode_defunct
+from noble_tls import Client, Session
+from pydantic import HttpUrl
+
+from loader import config
+from models import Account
+from core.exceptions.base import APIError
+from core.wallet import Wallet
+
+
+class Vip3API(Wallet):
+ API_URL = "https://dappapi.vip3.io/api"
+
+ def __init__(self, account_data: Account):
+ super().__init__(account_data.pk_or_mnemonic, config.mint_rpc_url)
+ self.account = account_data
+ self.session = self.setup_session()
+
+ def setup_session(self) -> Session:
+ session = Session(client=Client.CHROME_120)
+ session.random_tls_extension_order = True
+
+ session.timeout_seconds = 15
+ session.headers = {
+ "accept": "application/json, text/plain, */*",
+ "accept-language": "en-US,en;q=0.9,ru;q=0.8",
+ "content-type": "application/json",
+ "origin": "https://dapp.vip3.io",
+ "referer": "https://dapp.vip3.io/",
+ "user-agent": pyuseragents.random(),
+ }
+ session.proxies = {
+ "http": self.account.proxy,
+ "https": self.account.proxy,
+ }
+ return session
+
+ async def send_request(
+ self,
+ request_type: Literal["POST", "GET"] = "POST",
+ method: str = None,
+ json_data: dict = None,
+ params: dict = None,
+ url: str = None,
+ headers: dict = None,
+ verify: bool = True,
+ ):
+ def _verify_response(_response: dict) -> dict:
+ if "code" in _response:
+ if _response["code"] != 0:
+ raise APIError(f"{_response.get('msg')} | Method: {method}")
+
+ return _response
+
+ raise APIError(f"{_response} | Method: {method}")
+
+ if request_type == "POST":
+ if not url:
+ response = await self.session.post(
+ f"{self.API_URL}{method}",
+ json=json_data,
+ params=params,
+ headers=headers,
+ )
+
+ else:
+ response = await self.session.post(
+ url, json=json_data, params=params, headers=headers
+ )
+
+ else:
+ if not url:
+ response = await self.session.get(
+ f"{self.API_URL}{method}", params=params, headers=headers
+ )
+
+ else:
+ response = await self.session.get(url, params=params, headers=headers)
+
+ response.raise_for_status()
+ if verify:
+ return _verify_response(response.json())
+ else:
+ return response.json()
+
+ async def get_login_signature(self) -> tuple[str, Any]:
+ message = f'Welcome to VIP3!\n\nClick "Sign" to sign in and accept the VIP3 Terms of Use(https://vip3.gitbook.io/term-of-use/).\n\nThis request will not trigger a blockchain transaction or cost any gas fees.\n\nWallet address:\n{self.keypair.address}\n\nNonce: {int(time.time() * 1000)}'
+
+ encoded_message = encode_defunct(text=message)
+ signed_message = self.keypair.sign_message(encoded_message)
+ return message, signed_message.signature.hex()
+
+ async def get_mint_data(self) -> dict:
+ json_data = {
+ "lang": "en",
+ "chainId": 185,
+ }
+
+ response = await self.send_request(
+ method="/v1/sbt/mint",
+ json_data=json_data,
+ )
+ return response["data"]
+
+ async def login(self) -> None:
+ message, signature = await self.get_login_signature()
+
+ json_data = {
+ "address": self.keypair.address,
+ "sign": signature,
+ "raw": message,
+ }
+
+ response = await self.send_request(
+ method="/v1/auth",
+ json_data=json_data,
+ )
+
+ self.session.headers.update(
+ {"Authorization": f"Bearer {response['data']['token']}"}
+ )
diff --git a/core/wallet.py b/core/wallet.py
new file mode 100644
index 0000000..e756809
--- /dev/null
+++ b/core/wallet.py
@@ -0,0 +1,349 @@
+import random
+from typing import Any, Literal
+
+from eth_account import Account
+from eth_account.messages import encode_defunct
+from pydantic import HttpUrl
+from web3 import AsyncWeb3
+from web3.contract import AsyncContract
+from web3.eth import AsyncEth
+from web3.types import Nonce
+
+from models import (
+ LoginData,
+ CommemorativeNFTData,
+ OmnihubData,
+ MakeNFTGreatAgainData,
+ SummerNFTData,
+ MintFlagData,
+ MintShopData,
+ MintAir3Data,
+ MintSupermintData,
+ CometBridgeData,
+ Vip3MintData,
+ GreenIDData,
+)
+
+Account.enable_unaudited_hdwallet_features()
+
+
+class Wallet(AsyncWeb3, Account):
+ def __init__(self, mnemonic: str, rpc_url: HttpUrl | str):
+ super().__init__(
+ AsyncWeb3.AsyncHTTPProvider(str(rpc_url)),
+ modules={"eth": (AsyncEth,)},
+ middlewares=[],
+ )
+ self.keypair = (
+ self.from_mnemonic(mnemonic)
+ if len(mnemonic.split()) in (12, 24)
+ else self.from_key(mnemonic)
+ )
+
+ @property
+ def get_commemorative_nft_contract(self) -> AsyncContract:
+ return self.eth.contract(
+ address=AsyncWeb3.to_checksum_address(CommemorativeNFTData.address),
+ abi=CommemorativeNFTData.abi,
+ )
+
+ @property
+ def get_omnihub_contract(self) -> AsyncContract:
+ return self.eth.contract(
+ address=AsyncWeb3.to_checksum_address(OmnihubData.address),
+ abi=OmnihubData.abi,
+ )
+
+ @property
+ def get_make_nft_great_again_contract(self) -> AsyncContract:
+ return self.eth.contract(
+ address=AsyncWeb3.to_checksum_address(MakeNFTGreatAgainData.address),
+ abi=MakeNFTGreatAgainData.abi,
+ )
+
+ @property
+ def get_summer_nft_contract(self) -> AsyncContract:
+ return self.eth.contract(
+ address=AsyncWeb3.to_checksum_address(SummerNFTData.address),
+ abi=SummerNFTData.abi,
+ )
+
+ @property
+ def get_mint_flag_contract(self) -> AsyncContract:
+ return self.eth.contract(
+ address=AsyncWeb3.to_checksum_address(MintFlagData.address),
+ abi=MintFlagData.abi,
+ )
+
+ @property
+ def get_min_shop_contract(self) -> AsyncContract:
+ return self.eth.contract(
+ address=AsyncWeb3.to_checksum_address(MintShopData.address),
+ abi=MintShopData.abi,
+ )
+
+ @property
+ def get_mint_air3_contract(self) -> AsyncContract:
+ return self.eth.contract(
+ address=AsyncWeb3.to_checksum_address(MintAir3Data.address),
+ abi=MintAir3Data.abi,
+ )
+
+ @property
+ def get_mint_supermint_contract(self) -> AsyncContract:
+ return self.eth.contract(
+ address=AsyncWeb3.to_checksum_address(MintSupermintData.address),
+ abi=MintSupermintData.abi,
+ )
+
+ @property
+ def get_comet_bridge_contract(self) -> AsyncContract:
+ return self.eth.contract(
+ address=AsyncWeb3.to_checksum_address(CometBridgeData.address),
+ abi=CometBridgeData.abi,
+ )
+
+ @property
+ def get_vip3_contract(self) -> AsyncContract:
+ return self.eth.contract(
+ address=AsyncWeb3.to_checksum_address(Vip3MintData.address),
+ abi=Vip3MintData.abi,
+ )
+
+ @property
+ def get_green_contract(self) -> AsyncContract:
+ return self.eth.contract(
+ address=AsyncWeb3.to_checksum_address(GreenIDData.address),
+ abi=GreenIDData.abi,
+ )
+
+ async def transactions_count(self) -> Nonce:
+ return await self.eth.get_transaction_count(self.keypair.address)
+
+ async def check_balance(self) -> None:
+ balance = await self.eth.get_balance(self.keypair.address)
+
+ if balance <= 0:
+ raise Exception(f"ETH balance is empty")
+
+ async def human_balance(self) -> float | int:
+ balance = await self.eth.get_balance(self.keypair.address)
+ return AsyncWeb3.from_wei(balance, "ether")
+
+ async def build_make_nft_great_again_transaction(self, proofs: list[str]):
+ contract = self.get_make_nft_great_again_contract
+ transaction = contract.functions.awardItem(proofs)
+
+ return await transaction.build_transaction(
+ {
+ "gasPrice": await self.eth.gas_price,
+ "nonce": await self.transactions_count(),
+ "gas": int(
+ await transaction.estimate_gas({"from": self.keypair.address}) * 1.2
+ ),
+ }
+ )
+
+ async def build_green_id_nft_transaction(self, mint_id: int):
+ contract = self.get_green_contract
+ transaction = contract.functions.claim(mint_id)
+
+ return await transaction.build_transaction(
+ {
+ "gasPrice": await self.eth.gas_price,
+ "nonce": await self.transactions_count(),
+ "gas": int(
+ await transaction.estimate_gas({"from": self.keypair.address}) * 1.2
+ ),
+ }
+ )
+
+ async def build_mint_air3_transaction(self):
+ contract = self.get_mint_air3_contract
+ transaction = contract.functions.mint(1)
+
+ return await transaction.build_transaction(
+ {
+ "gasPrice": await self.eth.gas_price,
+ "nonce": await self.transactions_count(),
+ "gas": int(
+ await transaction.estimate_gas({"from": self.keypair.address}) * 1.2
+ ),
+ }
+ )
+
+ async def build_mint_supermint_transaction(self):
+ contract = self.get_mint_supermint_contract
+ transaction = contract.functions.mint(1)
+
+ return await transaction.build_transaction(
+ {
+ "gasPrice": await self.eth.gas_price,
+ "nonce": await self.transactions_count(),
+ "gas": int(
+ await transaction.estimate_gas({"from": self.keypair.address}) * 1.2
+ ),
+ }
+ )
+
+ async def build_mint_shop_transaction(self):
+ contract = self.get_min_shop_contract
+ transaction = contract.functions.mint(1)
+
+ return await transaction.build_transaction(
+ {
+ "gasPrice": await self.eth.gas_price,
+ "nonce": await self.transactions_count(),
+ "gas": int(
+ await transaction.estimate_gas({"from": self.keypair.address}) * 1.2
+ ),
+ }
+ )
+
+ async def build_mint_flag_transaction(self):
+ contract = self.get_mint_flag_contract
+ transaction = contract.functions.mint(1)
+
+ return await transaction.build_transaction(
+ {
+ "gasPrice": await self.eth.gas_price,
+ "nonce": await self.transactions_count(),
+ "gas": int(
+ await transaction.estimate_gas({"from": self.keypair.address}) * 1.2
+ ),
+ }
+ )
+
+ async def build_summer_nft_transaction(self):
+ contract = self.get_summer_nft_contract
+ transaction = contract.functions.claim(
+ self.keypair.address,
+ 1,
+ AsyncWeb3.to_checksum_address("0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"),
+ 0,
+ (
+ ["0x0000000000000000000000000000000000000000000000000000000000000000"],
+ 115792089237316195423570985008687907853269984665640564039457584007913129639935,
+ 0,
+ AsyncWeb3.to_checksum_address(
+ "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
+ ),
+ ),
+ b"",
+ )
+
+ return await transaction.build_transaction(
+ {
+ "gasPrice": await self.eth.gas_price,
+ "nonce": await self.transactions_count(),
+ "gas": int(
+ await transaction.estimate_gas({"from": self.keypair.address}) * 1.2
+ ),
+ }
+ )
+
+ async def build_vip3_nft_transaction(self, mint_data: dict):
+ contract = self.get_vip3_contract
+ transaction = contract.functions.mint(
+ self.keypair.address,
+ mint_data["data"]["deadline"],
+ mint_data["data"]["level"],
+ 0,
+ mint_data["data"]["signature"],
+ )
+
+ return await transaction.build_transaction(
+ {
+ "gasPrice": await self.eth.gas_price,
+ "nonce": await self.transactions_count(),
+ "gas": int(
+ await transaction.estimate_gas({"from": self.keypair.address}) * 1.2
+ ),
+ }
+ )
+
+ async def build_commemorative_nft_transaction(self):
+ contract = self.get_commemorative_nft_contract
+ transaction = contract.functions.mint(1)
+
+ return await transaction.build_transaction(
+ {
+ "gasPrice": await self.eth.gas_price,
+ "nonce": await self.transactions_count(),
+ "gas": int(
+ await transaction.estimate_gas({"from": self.keypair.address}) * 1.2
+ ),
+ }
+ )
+
+ async def build_createx_collection_transaction(self, data: str):
+ transaction = {
+ "from": self.keypair.address,
+ "data": data,
+ "nonce": await self.transactions_count(),
+ }
+
+ estimated_gas = await self.eth.estimate_gas(transaction)
+ transaction["gas"] = int(estimated_gas * 1.2)
+ transaction["gasPrice"] = await self.eth.gas_price
+
+ return transaction
+
+ async def build_owlto_summer_fest_nft_transaction(self):
+ transaction = {
+ "from": self.keypair.address,
+ "to": AsyncWeb3.to_checksum_address(
+ "0x0000C019d60b628F9Ba553092CdA375191319c5e"
+ ),
+ "value": AsyncWeb3.to_wei(0.0001, "ether"),
+ "data": "0x5e752eb40000000000000000000000000c1308dd0b5886b48cb14da2d6cf766cfc8be6ea0000000000000000000000000000000000000000000000000000000000000001",
+ "nonce": await self.transactions_count(),
+ }
+
+ estimated_gas = await self.eth.estimate_gas(transaction)
+ transaction["gas"] = int(estimated_gas * 1.2)
+ transaction["gasPrice"] = await self.eth.gas_price
+
+ return transaction
+
+ async def build_omnihub_summer_fest_nft_transaction(self):
+ transaction = {
+ "from": self.keypair.address,
+ "to": AsyncWeb3.to_checksum_address(
+ "0x0000C019d60b628F9Ba553092CdA375191319c5e"
+ ),
+ "value": AsyncWeb3.to_wei(0.0001, "ether"),
+ "data": "0x5e752eb400000000000000000000000050b42f700a5feba13ee6437c43fac4df33062f2b0000000000000000000000000000000000000000000000000000000000000001",
+ "nonce": await self.transactions_count(),
+ }
+
+ estimated_gas = await self.eth.estimate_gas(transaction)
+ transaction["gas"] = int(estimated_gas * 1.2)
+ transaction["gasPrice"] = await self.eth.gas_price
+
+ return transaction
+
+ @property
+ def get_forest_message(self) -> str:
+ message = f"You are participating in the Mint Forest event: \n {self.keypair.address}\n\nNonce: {str(random.randint(1000000, 9000000))}"
+ return message
+
+ @property
+ def get_airdrop_message(self) -> str:
+ message = f"You are participating in the Mint Airdrop event: \n {self.keypair.address}\n\nNonce: {str(random.randint(1000000, 9000000))}"
+ return message
+
+ def sign_mint_message(self, type_: Literal["airdrop", "forest"]) -> LoginData:
+ if type_ == "forest":
+ message = self.get_forest_message
+ else:
+ message = self.get_airdrop_message
+ encoded_message = encode_defunct(text=message)
+ signed_message = self.keypair.sign_message(encoded_message)
+ return LoginData(message=message, signed_message=signed_message.signature.hex())
+
+ async def send_and_verify_transaction(self, trx: Any) -> tuple[bool | Any, str]:
+ signed = self.keypair.sign_transaction(trx)
+ tx_hash = await self.eth.send_raw_transaction(signed.rawTransaction)
+ receipt = await self.eth.wait_for_transaction_receipt(tx_hash)
+ return receipt["status"] == 1, tx_hash.hex()
diff --git a/loader.py b/loader.py
index d528938..d116961 100644
--- a/loader.py
+++ b/loader.py
@@ -1,7 +1,7 @@
import asyncio
from models import Config
-from config import load_config
+from utils import load_config
config: Config = load_config()
semaphore = asyncio.Semaphore(config.threads)
diff --git a/models/account.py b/models/account.py
index 5d81b7d..a9b5ff1 100644
--- a/models/account.py
+++ b/models/account.py
@@ -7,7 +7,6 @@ class Account(BaseModel):
pk_or_mnemonic: str
proxy: str = None
-
@field_validator("proxy", mode="before")
def check_proxy(cls, value) -> str | None:
if not value:
diff --git a/models/api.py b/models/api.py
index 96a9d97..fb93a64 100644
--- a/models/api.py
+++ b/models/api.py
@@ -13,11 +13,11 @@ class RankData(BaseModel):
class AssetData(BaseModel):
- id: int
- uid: int
- reward: Any
+ id: int | None = None
+ uid: int | None = None
+ reward: Any | None = None
type: str = "energy"
- openAt: Any
+ openAt: Any | None = None
createdAt: str | None = None
@@ -42,18 +42,19 @@ class UserInfo(BaseModel):
id: int
treeId: int
address: str
- ens: Any
+ ens: Any | None = None
energy: int
tree: int
- inviteId: int
+ inviteId: int | None = None
type: str = "normal"
- stake_id: int
- nft_id: int
- nft_pass: int
+ stake_id: int | None = None
+ nft_id: int | None = None
+ nft_pass: int | None = None
signin: int
- code: Any
+ code: Any | None = None
createdAt: str
- invitePercent: int
+ invitePercent: int | None = None
+ stealCount: int | None = None
class ResponseData(BaseModel):
@@ -75,7 +76,6 @@ class User(BaseModel):
user: User
-
class EnergyListData(BaseModel):
class Energy(BaseModel):
uid: list[str]
@@ -84,6 +84,7 @@ class Energy(BaseModel):
type: str
id: str = None
freeze: bool = None
+ stealable: bool = None
@model_validator(mode="before")
@classmethod
diff --git a/models/config.py b/models/config.py
index 4def9ab..374dd2c 100644
--- a/models/config.py
+++ b/models/config.py
@@ -7,16 +7,21 @@ class Config(BaseModel):
accounts: list[Account]
referral_code: str | int
- eth_rpc_url: HttpUrl
- sepolia_rpc_url: HttpUrl
+ mint_rpc_url: HttpUrl
+ arb_rpc_url: HttpUrl
threads: PositiveInt
min_delay_before_start: PositiveInt
max_delay_before_start: PositiveInt
- min_amount_to_bridge: PositiveFloat
- max_amount_to_bridge: PositiveFloat
+ comet_bridge_wallet: str
+ comet_bridge_amount_min: PositiveFloat
+ comet_bridge_amount_max: PositiveFloat
+
+ mint_random_all_nfts: list[str]
+ delay_between_mint_min: PositiveInt
+ delay_between_mint_max: PositiveInt
spin_turntable_by_percentage_of_energy: int
module: str = ""
diff --git a/models/onchain.py b/models/onchain.py
index 681960b..0fc7b60 100644
--- a/models/onchain.py
+++ b/models/onchain.py
@@ -1,8 +1,73 @@
from dataclasses import dataclass
-
@dataclass
class BridgeData:
address: str = "0x57Fc396328b665f0f8bD235F0840fCeD43128c6b"
abi: list = open("./abi/bridge.json", "r").read()
+
+
+@dataclass
+class GreenIDData:
+ address: str = "0x776Fcec07e65dC03E35a9585f9194b8a9082CDdb"
+ abi: list = open("./abi/green_id.json", "r").read()
+
+
+@dataclass
+class CommemorativeNFTData:
+ address: str = "0xbc4b1cbbfF3Fe2C61Ad2Fd94b91126d5F7593D40"
+ abi: list = open("./abi/commemorative_nft.json", "r").read()
+
+
+@dataclass
+class OmnihubData:
+ address: str = "0xD473b08745288eF9b412a339ACCfaCce5Cebdd90"
+ abi: list = open("./abi/omnihub.json", "r").read()
+
+
+@dataclass
+class MakeNFTGreatAgainData:
+ address: str = "0x1a7464938aa694c5dB38Da52114C4fEdBc4EBF6A"
+ abi: list = open("./abi/make_nft_great_again.json", "r").read()
+
+
+@dataclass
+class SummerNFTData:
+ address: str = "0x98b322D37d54fac46f4980F4171bE2D0Ba8c54C2"
+ abi: list = open("./abi/summer_nft.json", "r").read()
+
+
+@dataclass
+class MintFlagData:
+ address: str = "0xa6660ba7F9a45e2707efC8dc574aF1DB4319Ee55"
+ abi: list = open("./abi/mint_flag.json", "r").read()
+
+
+@dataclass
+class MintShopData:
+ address: str = "0xBEEbbAEe8F085F506ce0eA3591f8FBb9C24Af356"
+ abi: list = open("./abi/mint_shop.json", "r").read()
+
+
+@dataclass
+class MintAir3Data:
+ address: str = "0x38f56A88a9eCD523086804f43Bdf881B8403107a"
+ abi: list = open("./abi/mint_air3.json", "r").read()
+
+
+@dataclass
+class MintSupermintData:
+ address: str = "0xDD351CDd289d9Bdf88D20EA3c9E316b99dF31412"
+ abi: list = open("./abi/mint_supermint.json", "r").read()
+
+
+@dataclass
+class CometBridgeData:
+ address: str = "0x0fbCf4a62036E96C4F6770B38a9B536Aa14d1846"
+ abi: list = open("./abi/cometa.json", "r").read()
+
+
+@dataclass
+class Vip3MintData:
+ address: str = "0xabe292b291A18699b09608de86888D77aD6BAf23"
+ abi: list = open("./abi/vip3_nft.json", "r").read()
diff --git a/requirements.txt b/requirements.txt
index 134e481..c90c1de 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,16 +1,14 @@
+httpx~=0.27.0
pyuseragents~=1.0.5
-retrying~=1.3.4
+names~=0.3.0
+noble_tls~=0.0.102
+Jam_Twitter_API~=0.6
loguru~=0.7.2
-web3~=6.15.1
-PyYAML~=6.0.1
pydantic~=2.6.4
+web3~=6.15.1
art~=6.1
-orjson~=3.9.15
-httpx~=0.27.0
-tqdm~=4.66.2
-noble_tls~=0.0.102
-eth_account
-curl_cffi~=0.6.2
+PyYAML~=6.0.1
urllib3~=2.2.1
inquirer~=3.2.4
-colorama~=0.4.6
\ No newline at end of file
+colorama~=0.4.6
+better_proxy
diff --git a/run.py b/run.py
index c16cce3..29bca5b 100644
--- a/run.py
+++ b/run.py
@@ -1,13 +1,16 @@
import asyncio
import sys
+from typing import Any
+
import urllib3
-from loguru import logger
+from loguru import logger
from loader import config, semaphore
-from src.bot import Bot
+from core.bot import Bot
from models import Account
from console import Console
+from utils import export_trees_ids
def setup():
@@ -27,15 +30,55 @@ async def run_safe(account: Account):
await Bot(account).start()
+async def run_get_tree_info_module(account: Account) -> tuple[Any, bool | str]:
+ async with semaphore:
+ client = Bot(account)
+ tree_id = await client.process_get_tree_id()
+ if tree_id:
+ logger.info(f"Account: {account.auth_token} | Tree ID: {tree_id}")
+ return client.keypair.address, tree_id
+
+
async def run():
while True:
Console().build()
- tasks = [
- asyncio.create_task(run_safe(account)) for account in config.accounts
- ]
- await asyncio.gather(*tasks)
- input("\nPress Enter to continue...")
+ if config.module in (
+ "bridge",
+ "rewards",
+ "tasks",
+ "fix_sign",
+ "mint_comm_nft",
+ "only_rewards",
+ "mint_omnihub",
+ "mint_make_nft_great_again",
+ "mint_summer_nft",
+ "mint_flag",
+ "mint_shop",
+ "mint_air3",
+ "mint_supermint",
+ "comet_bridge",
+ "mint_all_nfts",
+ "mint_owlto_summer_nft",
+ "mint_omnihub_summer_nft",
+ "mint_random_all_nfts",
+ "mint_vip3_nft",
+ "mint_green_id",
+ ):
+ tasks = [
+ asyncio.create_task(run_safe(account)) for account in config.accounts
+ ]
+ await asyncio.gather(*tasks)
+
+ elif config.module == "export_trees_ids":
+ tasks = [
+ asyncio.create_task(run_get_tree_info_module(account))
+ for account in config.accounts
+ ]
+ results = await asyncio.gather(*tasks)
+ export_trees_ids(results)
+
+ input("\n\nPress Enter to continue...")
if __name__ == "__main__":
diff --git a/src/api.py b/src/api.py
deleted file mode 100644
index 354c987..0000000
--- a/src/api.py
+++ /dev/null
@@ -1,334 +0,0 @@
-import asyncio
-import random
-import pyuseragents
-
-from typing import Literal, List
-from noble_tls import Session, Client
-
-from models import EnergyListData
-from twitter_api import Account as TwitterAccount
-from twitter_api.models import BindAccountParamsV2
-
-from models import *
-from loader import config as configuration
-
-from .wallet import Wallet
-from .exceptions.base import APIError
-from .bridge import Bridge
-
-
-class MintChainAPI(Wallet):
- API_URL = "https://www.mintchain.io/api"
-
- def __init__(self, account_data: Account):
- super().__init__(mnemonic=account_data.pk_or_mnemonic, rpc_url=configuration.eth_rpc_url)
- self.account = account_data
- self.session = self.setup_session()
- self.twitter_account: TwitterAccount = None # type: ignore
-
- @property
- def jwt_token(self) -> str:
- return self.session.headers["authorization"].replace("Bearer ", "")
-
- @property
- async def energy_balance(self) -> int:
- return (await self.user_info()).energy
-
- @property
- async def tree_size(self) -> int:
- return (await self.user_info()).tree
-
- @property
- async def rank(self) -> int:
- return (await self.rank_info()).rank
-
- def setup_session(self) -> Session:
- session = Session(client=Client.CHROME_120)
- session.random_tls_extension_order = True
-
- session.timeout_seconds = 15
- session.headers = {
- "authority": "www.mintchain.io",
- "accept": "application/json, text/plain, */*",
- "accept-language": "en-US,en;q=0.9,ru;q=0.8",
- "authorization": "Bearer",
- "content-type": "application/json",
- "origin": "https://www.mintchain.io",
- "referer": "https://www.mintchain.io",
- "user-agent": pyuseragents.random(),
- }
- session.proxies = {
- "http": self.account.proxy,
- "https": self.account.proxy,
- }
- return session
-
- async def send_request(
- self,
- request_type: Literal["POST", "GET"] = "POST",
- method: str = None,
- json_data: dict = None,
- params: dict = None,
- url: str = None,
- ):
- def _verify_response(_response: dict) -> dict:
- if "code" in _response:
- if _response["code"] != 10000:
- raise APIError(f"{_response.get('msg')} | Method: {method}")
-
- return _response
-
- raise APIError(f"{_response} | Method: {method}")
-
- if request_type == "POST":
- if not url:
- response = await self.session.post(
- f"{self.API_URL}{method}", json=json_data, params=params
- )
-
- else:
- response = await self.session.post(url, json=json_data, params=params)
-
- else:
- if not url:
- response = await self.session.get(
- f"{self.API_URL}{method}", params=params
- )
-
- else:
- response = await self.session.get(url, params=params)
-
- response.raise_for_status()
- return _verify_response(response.json())
-
- async def is_daily_reward_claimed(self) -> bool:
- response = await self.send_request(
- request_type="GET", method="/tree/energy-list"
- )
- return response["result"][-1]["freeze"]
-
-
- async def get_energy_list(self) -> EnergyListData:
- response = await self.send_request(request_type="GET", method="/tree/energy-list")
- return EnergyListData(**response)
-
- async def get_task_list(self) -> TaskListData:
- response = await self.send_request(request_type="GET", method=f"/tree/task-list?address={self.keypair.address}")
- return TaskListData(**response)
-
- async def complete_tasks(self):
- task_list = await self.get_task_list()
- for task in task_list.result:
- if task.spec not in ("discord-follow", "stake"):
- if task.claimed:
- logger.debug(f"Account: {self.account.auth_token} | Task already completed: {task.name}")
- continue
-
- try:
- if task.spec in ("twitter-post", "twitter-follow"):
- if not self.twitter_account:
- self.load_twitter_account()
-
- if task.spec == "twitter-follow":
- user_id = self.twitter_account.get_user_id("Mint_Blockchain")
- self.twitter_account.follow(user_id)
- await self.submit_task_id(task.id)
-
- else:
- tweet_text = "I'm collecting @Mint_Blockchain's ME $MINT in the #MintForest🌳!\n\nMint is the L2 for NFT industry, powered by @nftscan_com and @Optimism.\n\nJoin Mint Forest here: https://mintchain.io/mint-forest\n\n#MintBlockchain #L2forNFT"
-
- data = self.twitter_account.tweet(tweet_text)
- tweet_url = f'https://x.com/JammerCrypto/status/{data["data"]["create_tweet"]["tweet_results"]["result"]["rest_id"]}'
- await self.submit_task_id(task.id, twitter_post=tweet_url)
-
- else:
- await self.submit_task_id(task.id)
-
- logger.debug(f"Account: {self.account.auth_token} | Task completed: {task.name} | Reward: {task.amount} energy")
- await asyncio.sleep(3)
-
- except APIError as error:
- logger.error(f"Account: {self.account.auth_token} | Failed to complete task: {task.name} | {error}")
- await asyncio.sleep(3)
-
- async def claim_daily_rewards(self) -> None:
- energy_list = await self.get_energy_list()
- for energy in energy_list.result:
- json_data = {
- "uid": energy.uid,
- "amount": energy.amount,
- "includes": energy.includes,
- "type": energy.type,
- "id": energy.id,
- }
-
- if energy.type == "daily":
- if energy.freeze:
- logger.debug(f"Account: {self.account.auth_token} | Daily reward already claimed")
- continue
- else:
- json_data["freeze"] = energy.freeze
-
- await self.send_request(method="/tree/claim", json_data=json_data)
- logger.debug(f"Account: {self.account.auth_token} | Claimed {energy.amount} energy | Type: {energy.type}")
- await asyncio.sleep(1)
-
- await self.claim_boxes()
-
- async def bind_invite_code(self) -> ResponseData:
- jwt_token = self.jwt_token
-
- session = Session(client=Client.CHROME_120)
- session.headers = {
- "accept": "application/json, text/plain, */*",
- "accept-language": "sk-SK,sk;q=0.9,en-US;q=0.8,en;q=0.7",
- "authorization": "Bearer",
- "referer": "https://www.mintchain.io/mint-forest",
- "user-agent": self.session.headers["user-agent"],
- }
-
- json_data = {
- "code": str(configuration.referral_code),
- "jwtToken": jwt_token,
- }
-
- response = await session.get(
- "https://www.mintchain.io/api/tree/invitation", params=json_data
- )
- return ResponseData(**response.json())
-
- def load_twitter_account(self) -> None:
- self.twitter_account = TwitterAccount.run(
- auth_token=self.account.auth_token,
- setup_session=True,
- proxy=self.account.proxy,
- )
-
-
- async def connect_twitter(self) -> dict:
- params = {
- "code_challenge": "mintchain",
- "code_challenge_method": "plain",
- "client_id": "enpfUjhndkdrdHhld29aTW96eGM6MTpjaQ",
- "redirect_uri": "https://www.mintchain.io/mint-forest",
- "response_type": "code",
- "scope": "tweet.read users.read follows.read offline.access",
- "state": "mintchain",
- }
-
- if not self.twitter_account:
- self.load_twitter_account()
-
- bind_data = self.twitter_account.bind_account_v2(
- bind_params=BindAccountParamsV2(**params)
- )
-
- params = {
- "code": bind_data.code,
- "jwtToken": self.jwt_token,
- "address": self.keypair.address,
- }
- response = await self.send_request(
- url="https://www.mintchain.io/api/twitter/verify", params=params
- )
- return response
-
- async def rank_info(self) -> RankData:
- response = await self.send_request(request_type="GET", method="/tree/me-rank")
- return RankData(**response["result"])
-
- async def user_info(self) -> UserInfo:
- response = await self.send_request(request_type="GET", method="/tree/user-info")
- return UserInfo(**response["result"])
-
- async def assets(self) -> List[AssetData]:
- response = await self.send_request(request_type="GET", method="/tree/asset")
- return [AssetData(**data) for data in response["result"]]
-
- async def open_box(self, box_id: int) -> OpenBoxData:
- json_data = {
- "boxId": box_id,
- }
-
- response = await self.send_request(method="/tree/open-box", json_data=json_data)
- return OpenBoxData(**response["result"])
-
- async def claim_boxes(self):
- assets = await self.assets()
- for asset in assets:
- if not asset.createdAt:
- try:
- opened_box_data = await self.open_box(asset.id)
- logger.debug(f"Account: {self.account.auth_token} | Box opened | Reward: {opened_box_data.energy} energy")
- except APIError as error:
- logger.error(f"Account: {self.account.auth_token} | Failed to open box: {asset.type} | {error}")
-
- await asyncio.sleep(1)
-
- async def spin_turntable(self) -> TurntableData:
- response = await self.send_request(request_type="GET", method="/tree/turntable/open")
- return TurntableData(**response["result"])
-
- async def inject(self, amount: int = None) -> InjectData:
- if not amount:
- amount = await self.energy_balance
-
- if amount <= 0:
- return InjectData(code=0, result=False, msg="Energy balance is 0")
-
- json_data = {
- "address": self.keypair.address,
- "energy": amount,
- }
-
- response = await self.send_request(method="/tree/inject", json_data=json_data)
- return InjectData(**response)
-
-
- async def submit_task_id(self, task_id: int, twitter_post: str = None) -> None:
- json_data = {
- 'id': task_id,
- }
-
- if twitter_post:
- json_data["twitterurl"] = twitter_post
-
- await self.send_request(method="/tree/task-submit", json_data=json_data)
-
- async def testnet_bridge(self) -> None:
- amount_to_bridge = random.uniform(configuration.min_amount_to_bridge, configuration.max_amount_to_bridge)
- bridge = Bridge(amount=amount_to_bridge, mnemonic_or_pk=self.account.pk_or_mnemonic)
- bridge.send_transaction()
-
- async def verify_wallet(self) -> ResponseData:
- json_data = {
- "jwtToken": self.jwt_token,
- }
-
- response = await self.send_request(method="/wallet/verify", json_data=json_data)
- return ResponseData(**response)
-
- async def login(self):
- messages = self.sign_login_message()
- json_data = {
- "address": self.keypair.address,
- "signature": messages.signed_message,
- "message": messages.message,
- }
-
- response = await self.send_request(method="/tree/login", json_data=json_data)
- data = LoginWalletData(**response["result"])
- self.session.headers["authorization"] = f"Bearer {data.access_token}"
-
- if data.user.status == "pending":
- await self.verify_wallet()
-
- if not data.user.twitter:
- await self.connect_twitter()
- logger.debug(
- f"Account: {self.account.auth_token} | Twitter account connected"
- )
-
- if not data.user.inviteId:
- await self.bind_invite_code()
- logger.debug(f"Account: {self.account.auth_token} | Referral code bound")
diff --git a/src/bot.py b/src/bot.py
deleted file mode 100644
index 251a73d..0000000
--- a/src/bot.py
+++ /dev/null
@@ -1,166 +0,0 @@
-import asyncio
-import random
-from typing import Any
-
-from models import Account
-from loguru import logger
-from loader import config
-
-from .api import MintChainAPI
-
-
-class Bot(MintChainAPI):
- def __init__(self, account: Account):
- super().__init__(account_data=account)
-
- async def safe_operation(
- self,
- operation: callable,
- success_message: str,
- error_message: str,
- retries: int = 0,
- delay: int = 3,
- argument: Any = None,
- ) -> bool:
- for _ in range(retries):
- try:
- await operation() if argument is None else await operation(argument)
- logger.success(
- f"Account: {self.account.auth_token} | {success_message}"
- )
- return True
-
- except Exception as error:
- logger.error(
- f"Account: {self.account.auth_token} | {error_message}: {error} | {'Retrying..' if retries > 0 else ''}"
- )
- await asyncio.sleep(delay)
- continue
-
- return False
-
- async def process_login(self) -> bool:
- return await self.safe_operation(
- operation=self.login,
- success_message="Logged in",
- error_message="Failed to login",
- retries=3,
- )
-
- async def process_claim_daily_reward(self) -> bool:
- return await self.safe_operation(
- operation=self.claim_daily_rewards,
- success_message="Finished claiming daily rewards",
- error_message="Failed to claim daily rewards",
- delay=10,
- retries=3,
- )
-
- async def process_inject(self) -> bool:
- return await self.safe_operation(
- operation=self.inject,
- success_message="Finished injecting energy",
- error_message="Failed to inject energy",
- retries=3,
- )
-
- async def process_spin_turntable(self) -> bool:
- if config.spin_turntable_by_percentage_of_energy > 0:
- try:
- balance = await self.energy_balance
- if balance < 300:
- logger.warning(
- f"Account: {self.account.auth_token} | Not enough energy to spin turntable"
- )
- return True
-
- amount = int(balance * (config.spin_turntable_by_percentage_of_energy / 100))
- number_of_spins = int(amount // 300)
- if number_of_spins > 5:
- number_of_spins = 5
-
- for _ in range(number_of_spins):
- reward = await self.spin_turntable()
- logger.success(f"Account: {self.account.auth_token} | Opened turntable | Reward: {reward.energy} energy")
- await asyncio.sleep(3)
-
- except Exception as error:
- logger.error(
- f"Account: {self.account.auth_token} | Failed to spin turntable: {error}"
- )
-
- return True
-
-
- async def process_show_user_info(self) -> None:
- try:
- info = await self.tree_size
- logger.success(
- f"Account: {self.account.auth_token} | Total injected energy: {info} | Daily actions done.."
- )
-
- except Exception as error:
- logger.warning(
- f"Account: {self.account.auth_token} | Failed to get user info: {error} | Daily actions done.."
- )
-
- async def process_testnet_bridge(self) -> bool:
- return await self.safe_operation(
- operation=self.testnet_bridge,
- success_message="Testnet bridge completed",
- error_message="Failed to complete testnet bridge",
- delay=30,
- retries=3,
- )
-
- async def process_complete_tasks(self):
- return await self.safe_operation(
- operation=self.complete_tasks,
- success_message="Finished completing tasks",
- error_message="Failed to complete tasks",
- delay=10,
- retries=3,
- )
-
- async def start(self):
- random_delay = random.randint(config.min_delay_before_start, config.max_delay_before_start)
- logger.info(
- f"Account: {self.account.auth_token} | Work will start in {random_delay} seconds.."
- )
- await asyncio.sleep(random_delay)
-
- try:
- if config.module == "rewards":
- operations = [
- self.process_login,
- self.process_claim_daily_reward,
- self.process_spin_turntable,
- self.process_inject,
- self.process_show_user_info,
- ]
-
- elif config.module == "bridge":
- operations = [
- self.process_login,
- self.process_testnet_bridge,
- ]
-
- else:
- operations = [
- self.process_login,
- self.process_complete_tasks,
- ]
-
- for operation in operations:
- if not await operation():
- break
-
- except Exception as error:
- logger.error(
- f"Account: {self.account.auth_token} | Unhandled error: {error}"
- )
-
- finally:
- logger.success(
- f"Account: {self.account.auth_token} | Finished"
- )
diff --git a/src/bridge.py b/src/bridge.py
deleted file mode 100644
index 7646e9f..0000000
--- a/src/bridge.py
+++ /dev/null
@@ -1,72 +0,0 @@
-import re
-
-from web3 import Web3, Account
-from web3.exceptions import TransactionIndexingInProgress, TransactionNotFound, TimeExhausted
-
-from models import BridgeData
-from loguru import logger
-from loader import config as cfg
-
-
-class Bridge(Web3, Account):
- def __init__(self, amount: float, mnemonic_or_pk: str):
- super().__init__(Web3.HTTPProvider(cfg.sepolia_rpc_url))
-
- self.amount = amount
- self.nonce = None
- self.keypair = self.from_mnemonic(mnemonic_or_pk) if len(mnemonic_or_pk.split()) in (12, 24) else self.from_key(mnemonic_or_pk)
- self.contract = self.eth.contract(address=Web3.to_checksum_address(BridgeData.address), abi=BridgeData.abi)
-
- @property
- def address(self):
- return self.keypair.address
-
- def build_transaction(self):
- transaction = self.contract.functions.bridgeETHTo(
- self.address,
- 200000,
- b"0x7375706572627269646765"
- )
-
- return transaction.build_transaction({
- "value": Web3.to_wei(self.amount, "ether"),
- "gasPrice": self.eth.gas_price,
- "nonce": self.eth.get_transaction_count(self.address) if not self.nonce else self.nonce,
- "gas": int(
- transaction.estimate_gas({"from": self.address}) * 1.2
- ),
- })
-
- def check_balance(self) -> None:
- balance = self.eth.get_balance(self.address)
- human_balance = self.from_wei(balance, "ether")
-
- if human_balance < self.amount:
- raise Exception(f"Insufficient balance: {human_balance} | Required: {self.amount} ETH")
-
-
- def send_transaction(self) -> bool:
- try:
- self.check_balance()
-
- signed_transaction = self.keypair.sign_transaction(self.build_transaction())
- transaction_hash = self.eth.send_raw_transaction(signed_transaction.rawTransaction)
- logger.debug(f"Account: {self.address} | Bridging {self.amount} ETH | Transaction hash: {transaction_hash.hex()}")
- status = self.eth.wait_for_transaction_receipt(transaction_hash, timeout=60)
-
- if status.status != 1:
- raise Exception(f"Failed to bridge {self.amount} ETH to MINT, transaction failed")
-
- logger.success(f"Account: {self.address} | Bridged {self.amount} ETH to MINT")
-
- except (TimeExhausted, TransactionNotFound, TransactionIndexingInProgress) as error:
- logger.error(f"Account: {self.address} | Transaction not found or time exhausted | {error} | Retrying...")
- return self.send_transaction()
-
- except Exception as error:
- if "nonce too low" in str(error):
- self.nonce = int(re.search(r"next nonce (\d+)", str(error)).group(1))
- logger.warning(f"Account: {self.address} | Nonce too low | Next nonce: {self.nonce} | Retrying...")
- return self.send_transaction()
-
- raise Exception(f"Failed to bridge {self.amount} ETH | {error}")
diff --git a/src/exceptions/base.py b/src/exceptions/base.py
deleted file mode 100644
index a2dcb07..0000000
--- a/src/exceptions/base.py
+++ /dev/null
@@ -1,4 +0,0 @@
-class APIError(Exception):
- """Base class for API exceptions"""
-
- pass
diff --git a/src/wallet.py b/src/wallet.py
deleted file mode 100644
index 294a8fa..0000000
--- a/src/wallet.py
+++ /dev/null
@@ -1,31 +0,0 @@
-from eth_account import Account
-from eth_account.messages import encode_defunct
-from web3 import Web3
-from web3.types import Nonce
-
-from models import LoginData
-
-
-Account.enable_unaudited_hdwallet_features()
-
-
-class Wallet(Web3, Account):
- def __init__(self, mnemonic: str, rpc_url: str):
- super().__init__(Web3.HTTPProvider(rpc_url))
- self.keypair = self.from_mnemonic(mnemonic) if len(mnemonic.split()) in (12, 24) else self.from_key(mnemonic)
-
- @property
- def transactions_count(self) -> Nonce:
- return self.eth.get_transaction_count(self.keypair.address)
-
- @property
- def get_message(self) -> str:
- message = f"You are participating in the Mint Forest event: \n {self.keypair.address}\n\nNonce: {self.transactions_count}"
- return message
-
- def sign_login_message(self) -> LoginData:
- encoded_message = encode_defunct(text=self.get_message)
- signed_message = self.keypair.sign_message(encoded_message)
- return LoginData(
- message=self.get_message, signed_message=signed_message.signature.hex()
- )
diff --git a/twitter_api/__init__.py b/twitter_api/__init__.py
deleted file mode 100644
index b4831a4..0000000
--- a/twitter_api/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from .account import Account
-from .errors import *
diff --git a/twitter_api/account.py b/twitter_api/account.py
deleted file mode 100644
index c806bb9..0000000
--- a/twitter_api/account.py
+++ /dev/null
@@ -1,1664 +0,0 @@
-import asyncio
-import hashlib
-import math
-import mimetypes
-import platform
-import secrets
-import httpx
-
-from copy import deepcopy
-from datetime import datetime
-from string import ascii_letters
-from typing import Coroutine
-from uuid import uuid1, getnode
-
-from curl_cffi import requests
-from curl_cffi.requests.session import Response
-from httpx import Cookies, Headers
-from tqdm import tqdm
-
-from .models import *
-from .constants import *
-from .errors import TwitterAccountSuspended, RateLimitError
-from .models import BindAccountDataV1
-from .util import *
-
-# logging.getLogger("httpx").setLevel(logging.WARNING)
-
-if platform.system() != "Windows":
- try:
- import uvloop
-
- uvloop.install()
- except ImportError as e:
- ...
-
-
-class Account:
- def __init__(self):
- self._session: requests.Session = requests.Session()
- self._proxy: str = ""
- self._reformatted_proxy: str = ""
-
- self.gql_api = "https://twitter.com/i/api/graphql"
- self.v1_api = "https://api.twitter.com/1.1"
- self.v2_api = "https://twitter.com/i/api/2"
-
- @classmethod
- def run(
- cls,
- auth_token: str = None,
- cookies: dict[str] = None,
- proxy: str = None,
- setup_session: bool = True,
- ) -> "Account":
- account = cls()
- account._proxy = proxy
- if proxy:
- if proxy.startswith("http://"):
- account._session = requests.Session(
- proxies={"http://": account.proxy}, timeout=30, verify=False
- )
- account._reformatted_proxy = account.proxy
-
- else:
- account._reformatted_proxy = account.get_reformatted_proxy
- account._session = requests.Session(
- proxies=(
- {"http://": account._reformatted_proxy}
- if account._reformatted_proxy
- else None
- ),
- timeout=30,
- verify=False,
- )
-
- if not (auth_token, cookies):
- raise TwitterError(
- {
- "error_message": "Failed to authenticate account. You need to set cookies or auth_token."
- }
- )
-
- if setup_session:
- if auth_token:
- account.session.cookies.update({"auth_token": auth_token})
- account.setup_session()
- else:
- account.session.cookies.update(cookies)
-
- else:
- if not account.session.cookies.get(
- "auth_token"
- ) and not account.session.cookies.get("ct0"):
- account.session.cookies.update({"auth_token": auth_token})
- account.setup_session()
- else:
- account.session.cookies.update(cookies)
-
- return account
-
- @property
- def get_auth_data(self) -> dict:
- return {
- "auth_token": self.auth_token,
- "cookies": dict(self.cookies),
- "proxy": self.proxy,
- }
-
- def gql(
- self,
- method: str,
- operation: tuple,
- variables: dict,
- features: dict = Operation.default_features,
- ) -> dict:
- qid, op = operation
- params = {
- "queryId": qid,
- "features": features,
- "variables": Operation.default_variables | variables,
- }
- if method == "POST":
- data = {"json": params}
- else:
- data = {"params": {k: orjson.dumps(v).decode() for k, v in params.items()}}
-
- r = self.session.request(
- method=method,
- url=f"{self.gql_api}/{qid}/{op}",
- headers=self.session.headers,
- allow_redirects=True,
- **data,
- )
-
- return self._verify_response(r)
-
- def v1(self, path: str, params: dict) -> dict:
- headers = get_headers(self.session)
- headers["content-type"] = "application/x-www-form-urlencoded"
- r = self.session.post(
- f"{self.v1_api}/{path}", headers=headers, data=params, allow_redirects=True
- )
- return self._verify_response(r)
-
- @staticmethod
- def _verify_response(r: Response) -> dict:
- try:
- rate_limit_remaining = r.headers.get("x-rate-limit-remaining")
- if rate_limit_remaining and int(rate_limit_remaining) in (0, 1):
- reset_ts = int(r.headers.get("x-rate-limit-reset"))
- raise RateLimitError(
- f"Rate limit reached. Reset in {reset_ts - int(time.time())} seconds. "
- )
- # logger.info(
- # f"Rate limit reached | Reset in {reset_ts - int(time.time())} seconds | Sleeping..."
- # )
- # current_ts = int(time.time())
- # difference = reset_ts - current_ts
- # asyncio.sleep(difference)
-
- data = r.json()
- except ValueError:
- raise TwitterError(
- {
- "error_message": f"Failed to parse response: {r.text}. "
- "If you are using proxy, make sure it is not blocked by Twitter."
- }
- )
-
- if "errors" in data:
- error_message = (
- data["errors"][0].get("message") if data["errors"] else data["errors"]
- )
-
- error_code = data["errors"][0].get("code") if data["errors"] else None
-
- if isinstance(error_message, str) and error_message.lower().startswith(
- "to protect our users from spam and other"
- ):
- raise TwitterAccountSuspended(error_message)
-
- raise TwitterError(
- {
- "error_code": error_code,
- "error_message": error_message,
- }
- )
-
- try:
- r.raise_for_status()
- except httpx.HTTPError as http_error:
- raise TwitterError(
- {
- "error_message": str(http_error),
- }
- )
-
- return data
-
- @property
- def proxy(self):
- return self._proxy
-
- @property
- def get_reformatted_proxy(self):
- try:
- if self.proxy is None:
- return None
-
- ip, port, username, password = self.proxy.split(":")
- return f"http://{username}:{password}@{ip}:{port}"
-
- except (ValueError, AttributeError):
- raise TwitterError(
- {
- "error_message": "Failed to parse proxy. "
- "Make sure you are using correct proxy format: "
- "ip:port:username:password"
- }
- )
-
- @property
- def session(self):
- return self._session
-
- @property
- def cookies(self) -> Cookies:
- return self._session.cookies
-
- @property
- def headers(self) -> Headers:
- return self._session.headers
-
- @property
- def auth_token(self) -> str:
- return self._session.cookies.get("auth_token", "")
-
- @property
- def ct0(self) -> str:
- return self._session.cookies.get("ct0", "")
-
- def request_ct0(self) -> str:
- url = "https://twitter.com/i/api/2/oauth2/authorize"
- r = self.session.get(url, allow_redirects=True)
-
- if "ct0" in r.cookies:
- return r.cookies.get("ct0")
- else:
- raise TwitterError(
- {
- "error_message": "Failed to get ct0 token. "
- "Make sure you are using correct cookies."
- }
- )
-
- def request_guest_token(
- self, session: requests.Session, csrf_token: str = None
- ) -> str:
- if not (csrf_token, self.session.cookies.get("ct0", "")):
- raise TwitterError(
- {
- "error_message": "Failed to get guest token. "
- "Make sure you are using correct cookies."
- }
- )
-
- headers = {
- "content-type": "application/x-www-form-urlencoded",
- "authorization": "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs=1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA",
- "x-csrf-token": (
- csrf_token if csrf_token else self.session.cookies.get("ct0")
- ),
- }
- r = session.post(
- f"{self.v1_api}/guest/activate.json",
- headers=headers,
- allow_redirects=True,
- )
-
- data = self._verify_response(r)
- return data["guest_token"]
-
- def setup_session(self):
- session = requests.Session(
- # follow_redirects=True,
- proxies={"http://": self._reformatted_proxy} if self.proxy else None,
- timeout=30,
- verify=False,
- )
-
- generated_csrf_token = secrets.token_hex(16)
- guest_token = self.request_guest_token(session, generated_csrf_token)
-
- cookies = {"ct0": generated_csrf_token, "gt": guest_token}
- headers = {"x-guest-token": guest_token, "x-csrf-token": generated_csrf_token}
-
- self.session.headers.update(headers)
- self.session.cookies.update(cookies)
- csrf_token = self.request_ct0()
-
- self.session.headers["x-csrf-token"] = csrf_token
- self.session.cookies.delete("ct0")
- self.session.cookies.update({"ct0": csrf_token})
- self.session.headers = get_headers(self.session)
-
- self.verify_credentials()
- self.session.headers.update(
- {"x-csrf-token": self.session.cookies.get("ct0", domain=".twitter.com")}
- )
-
- def bind_account_v1(self, bind_params: BindAccountParamsV1) -> BindAccountDataV1:
-
- def get_oauth_token() -> str:
- _response = requests.get(str(bind_params.url), allow_redirects=True)
- raise_for_status(_response)
-
- token = re.search(
- r' 1:
- return token[1]
-
- raise TwitterError(
- {
- "error_message": "Failed to get oauth token. "
- "Make sure you are using correct cookies or url."
- }
- )
-
- def get_authenticity_token(_oauth_token: str) -> BindAccountDataV1 | str:
- params = {
- "oauth_token": _oauth_token,
- }
- _response = self.session.get(
- "https://api.twitter.com/oauth/authenticate", params=params
- )
- raise_for_status(_response)
-
- token = re.search(
- r' str:
- data = {
- "authenticity_token": _authenticity_token,
- "redirect_after_login": f"https://api.twitter.com/oauth/authorize?oauth_token={_oauth_token}",
- "oauth_token": _oauth_token,
- }
-
- response = self.session.post(
- "https://api.twitter.com/oauth/authorize",
- data=data,
- allow_redirects=True,
- )
- raise_for_status(response)
-
- _confirm_url = re.search(
- r' BindAccountDataV1:
- response = self.session.get(_url, allow_redirects=True)
- raise_for_status(response)
-
- if "status=error" in response.url:
- raise TwitterError(
- {
- "error_message": "Failed to bind account. "
- "Make sure you are using correct cookies or url."
- }
- )
-
- _oauth_token, _oauth_verifier = response.url.split("oauth_token=")[1].split(
- "&oauth_verifier="
- )
- return BindAccountDataV1(
- url=response.url,
- oauth_token=_oauth_token,
- oauth_verifier=_oauth_verifier,
- )
-
- oauth_token = get_oauth_token()
- authenticity_token = get_authenticity_token(oauth_token)
-
- if isinstance(authenticity_token, BindAccountDataV1):
- return authenticity_token
-
- confirm_url = get_confirm_url(oauth_token, authenticity_token)
- return process_confirm_url(confirm_url)
-
- def bind_account_v2(self, bind_params: BindAccountParamsV2) -> BindAccountDataV2:
-
- def get_auth_code() -> str:
- response = self.session.get(
- "https://twitter.com/i/api/2/oauth2/authorize",
- params=bind_params.model_dump(),
- )
- raise_for_status(response)
- self.session.headers.update(
- {"x-csrf-token": self.session.cookies.get("ct0", domain=".twitter.com")}
- )
- return response.json()["auth_code"]
-
- def approve_auth_code(_auth_code: str) -> str:
- _params = {
- "approval": "true",
- "code": _auth_code,
- }
-
- response = self.session.post(
- "https://twitter.com/i/api/2/oauth2/authorize",
- params=_params,
- allow_redirects=True,
- )
- raise_for_status(response)
-
- code = response.json()["redirect_uri"].split("code=")[1]
- return code
-
- auth_code = get_auth_code()
- approved_code = approve_auth_code(auth_code)
- return BindAccountDataV2(code=approved_code)
-
- def create_poll(self, text: str, choices: list[str], poll_duration: int) -> dict:
- options = {
- "twitter:card": "poll4choice_text_only",
- "twitter:api:api:endpoint": "1",
- "twitter:long:duration_minutes": poll_duration, # max: 10080
- }
- for i, c in enumerate(choices):
- options[f"twitter:string:choice{i + 1}_label"] = c
-
- headers = get_headers(self.session)
- headers["content-type"] = "application/x-www-form-urlencoded"
- url = "https://caps.twitter.com/v2/cards/create.json"
-
- r = self.session.post(
- url,
- headers=headers,
- params={"card_data": orjson.dumps(options).decode()},
- allow_redirects=True,
- )
- card_uri = (self._verify_response(r))["card_uri"]
-
- data = self.tweet(text, poll_params={"card_uri": card_uri})
- return data
-
- def verify_credentials(self) -> dict:
- r = self.session.get(
- f"{self.v1_api}/account/verify_credentials.json", allow_redirects=True
- )
- return self._verify_response(r)
-
- def email_phone_info(self) -> dict:
- r = self.session.get(
- f"{self.v1_api}/users/email_phone_info.json", allow_redirects=True
- )
- return self._verify_response(r)
-
- def settings_info(self) -> dict:
- r = self.session.get(
- f"{self.v1_api}/account/settings.json", allow_redirects=True
- )
- return self._verify_response(r)
-
- def screen_name(self) -> str:
- data = self.verify_credentials()
- return data["screen_name"]
-
- def user_id(self) -> int:
- data = self.verify_credentials()
- return data["id"]
-
- def name(self) -> str:
- data = self.verify_credentials()
- return data["name"]
-
- def location(self) -> str:
- data = self.verify_credentials()
- return data["location"]
-
- def description(self) -> str:
- data = self.verify_credentials()
- return data["description"]
-
- def followers_count(self) -> int:
- data = self.verify_credentials()
- return data["followers_count"]
-
- def friends_count(self) -> int:
- data = self.verify_credentials()
- return data["friends_count"]
-
- def registration_date(self) -> str:
- data = self.verify_credentials()
- return data["created_at"]
-
- def suspended(self) -> bool:
- data = self.verify_credentials()
- return data["suspended"]
-
- def dm(self, text: str, receivers: list[int], media: str = "") -> dict:
- variables = {
- "message": {},
- "requestId": str(uuid1(getnode())),
- "target": {"participant_ids": receivers},
- }
- if media:
- media_id = self.upload_media(media, is_dm=True)
- variables["message"]["media"] = {"id": media_id, "text": text}
- else:
- variables["message"]["text"] = {"text": text}
-
- res = self.gql("POST", Operation.useSendMessageMutation, variables)
- if find_key(res, "dm_validation_failure_type"):
- raise TwitterError(
- {
- "error_message": "Failed to send message. Sender does not have privilege to dm receiver(s)",
- "error_code": 349,
- }
- )
- return res
-
- def custom_dm(self, text: str, receiver: int) -> dict:
- json_data = {
- "event": {
- "type": "message_create",
- "message_create": {
- "target": {"recipient_id": f"{receiver}"},
- "message_data": {"text": f"{text}"},
- },
- }
- }
-
- r = self.session.post(
- f"{self.v1_api}/direct_messages/events/new.json",
- json=json_data,
- )
- return self._verify_response(r)
-
- def delete_tweet(self, tweet_id: int | str) -> dict:
- variables = {"tweet_id": tweet_id, "dark_request": False}
- return self.gql("POST", Operation.DeleteTweet, variables)
-
- def tweet(
- self, text: str, *, media: List[MediaEntity] = None, **kwargs
- ) -> dict:
- variables = {
- "tweet_text": text,
- "dark_request": False,
- "media": {
- "media_entities": [],
- "possibly_sensitive": False,
- },
- "semantic_annotation_ids": [],
- }
-
- if reply_params := kwargs.get("reply_params", {}):
- variables |= reply_params
- if quote_params := kwargs.get("quote_params", {}):
- variables |= quote_params
- if poll_params := kwargs.get("poll_params", {}):
- variables |= poll_params
-
- draft = kwargs.get("draft")
- schedule = kwargs.get("schedule")
-
- if draft or schedule:
- variables = {
- "post_tweet_request": {
- "auto_populate_reply_metadata": False,
- "status": text,
- "exclude_reply_user_ids": [],
- "media_ids": [],
- },
- }
- if media:
- for m in media:
- media_id = self.upload_media(m["media"])
- variables["post_tweet_request"]["media_ids"].append(media_id)
- if alt := m.get("alt"):
- self._add_alt_text(media_id, alt)
-
- if schedule:
- variables["execute_at"] = (
- datetime.strptime(schedule, "%Y-%m-%d %H:%M").timestamp()
- if isinstance(schedule, str)
- else schedule
- )
- return self.gql("POST", Operation.CreateScheduledTweet, variables)
-
- return self.gql("POST", Operation.CreateDraftTweet, variables)
-
- # regular tweet
- if media:
- for m in media:
-
- tagged_users_id = []
- for tagged_user in m.tagged_users:
- user_id = self.get_user_id(tagged_user)
- tagged_users_id.append(user_id)
-
- variables["media"]["media_entities"].append(
- {"media_id": m.media_id, "tagged_users": tagged_users_id}
- )
-
- return self.gql("POST", Operation.CreateTweet, variables)
-
- def schedule_tweet(
- self, text: str, date: int | str, *, media: List[MediaEntity] = None
- ) -> dict:
- variables = {
- "post_tweet_request": {
- "auto_populate_reply_metadata": False,
- "status": text,
- "exclude_reply_user_ids": [],
- "media_ids": [],
- },
- "execute_at": (
- datetime.strptime(date, "%Y-%m-%d %H:%M").timestamp()
- if isinstance(date, str)
- else date
- ),
- }
- if media:
- for m in media:
-
- tagged_users_id = []
- for tagged_user in m.tagged_users:
- user_id = self.get_user_id(tagged_user)
- tagged_users_id.append(user_id)
-
- variables["media"]["media_entities"].append(
- {"media_id": m.media_id, "tagged_users": tagged_users_id}
- )
-
- return self.gql("POST", Operation.CreateScheduledTweet, variables)
-
- def schedule_reply(
- self, text: str, date: int | str, tweet_id: int, *, media: list = None
- ) -> dict:
- variables = {
- "post_tweet_request": {
- "auto_populate_reply_metadata": True,
- "in_reply_to_status_id": tweet_id,
- "status": text,
- "exclude_reply_user_ids": [],
- "media_ids": [],
- },
- "execute_at": (
- datetime.strptime(date, "%Y-%m-%d %H:%M").timestamp()
- if isinstance(date, str)
- else date
- ),
- }
- if media:
- for m in media:
- media_id = self.upload_media(m["media"])
- variables["post_tweet_request"]["media_ids"].append(media_id)
- if alt := m.get("alt"):
- self._add_alt_text(media_id, alt)
-
- return self.gql("POST", Operation.CreateScheduledTweet, variables)
-
- def unschedule_tweet(self, tweet_id: int | str) -> dict:
- variables = {"scheduled_tweet_id": tweet_id}
- return self.gql("POST", Operation.DeleteScheduledTweet, variables)
-
- def untweet(self, tweet_id: int | str) -> dict:
- variables = {"tweet_id": tweet_id, "dark_request": False}
- return self.gql("POST", Operation.DeleteTweet, variables)
-
- def reply(
- self, text: str, tweet_id: int | str, media: List[MediaEntity] = None
- ) -> dict:
- variables = {
- "tweet_text": text,
- "reply": {
- "in_reply_to_tweet_id": tweet_id,
- "exclude_reply_user_ids": [],
- },
- "batch_compose": "BatchSubsequent",
- "dark_request": False,
- "media": {
- "media_entities": [],
- "possibly_sensitive": False,
- },
- "semantic_annotation_ids": [],
- }
-
- if media:
- for m in media:
- tagged_users_id = []
-
- for tagged_user in m.tagged_users:
- user_id = self.get_user_id(tagged_user)
- tagged_users_id.append(user_id)
-
- variables["media"]["media_entities"].append(
- {"media_id": m.media_id, "tagged_users": tagged_users_id}
- )
-
- return self.gql("POST", Operation.CreateTweet, variables)
-
- def quote(self, text: str, tweet_id: int) -> dict:
- variables = {
- "tweet_text": text,
- # can use `i` as it resolves to screen_name
- "attachment_url": f"https://twitter.com/i/status/{tweet_id}",
- "dark_request": False,
- "media": {
- "media_entities": [],
- "possibly_sensitive": False,
- },
- "semantic_annotation_ids": [],
- }
- return self.gql("POST", Operation.CreateTweet, variables)
-
- def retweet(self, tweet_id: int) -> dict:
- variables = {"tweet_id": tweet_id, "dark_request": False}
- return self.gql("POST", Operation.CreateRetweet, variables)
-
- def unretweet(self, tweet_id: int) -> dict:
- variables = {"source_tweet_id": tweet_id, "dark_request": False}
- return self.gql("POST", Operation.DeleteRetweet, variables)
-
- @staticmethod
- def __get_cursor_value(data: dict, target_cursor_type: str, target_entry_type: str):
- if target_entry_type != "threaded_conversation_with_injections_v2":
- for instruction in (
- data.get("data", {})
- .get(target_entry_type, {})
- .get("timeline", {})
- .get("instructions", [])
- ):
- for entry in instruction.get("entries", []):
- content = entry.get("content", {})
- cursor_type = content.get("cursorType")
- if (
- content.get("entryType") == "TimelineTimelineCursor"
- and cursor_type == target_cursor_type
- ):
- return content.get("value")
-
- else:
- for instruction in (
- data.get("data", {}).get(target_entry_type, {}).get("instructions", [])
- ):
- for entry in instruction.get("entries", []):
- content = entry.get("content", {})
- cursor_type = content.get("cursorType")
- if (
- content.get("entryType") == "TimelineTimelineCursor"
- and cursor_type == target_cursor_type
- ):
- return content.get("value")
-
- return None
-
- def tweet_likes(
- self, celery_task, tweet_id: int, limit: int = 0
- ) -> dict[str, list[dict]]:
- variables = {"tweetId": tweet_id, "count": 100}
- users_data = []
-
- while True:
- data = self.gql("GET", Operation.Favoriters, variables)
-
- for instruction in (
- data.get("data", {})
- .get("favoriters_timeline", {})
- .get("timeline", {})
- .get("instructions", [])
- ):
- try:
- for entry in instruction["entries"]:
- try:
- result = entry["content"]["itemContent"]["user_results"][
- "result"
- ]
- screen_name = result["legacy"]["screen_name"]
- if screen_name not in (
- user["screen_name"] for user in users_data
- ):
- users_data.append(
- self.get_user_data_from_user_results(result)
- )
-
- except (KeyError, TypeError, IndexError):
- continue
-
- except KeyError:
- return {"users": users_data[:limit] if limit > 0 else users_data}
-
- cursor_value = self.__get_cursor_value(
- data, "Bottom", "favoriters_timeline"
- )
- if not cursor_value or (0 < limit <= len(users_data)):
- return {"users": users_data[:limit] if limit > 0 else users_data}
-
- variables["cursor"] = cursor_value
-
- def tweet_retweeters(
- self, celery_task, tweet_id: int, limit: int = 0
- ) -> dict[str, list[Any]]:
- variables = {"tweetId": tweet_id, "count": 100}
- tweets_data = []
-
- while True:
- data = self.gql("GET", Operation.Retweeters, variables)
-
- for instruction in data["data"]["retweeters_timeline"]["timeline"][
- "instructions"
- ]:
- try:
- for entry in instruction["entries"]:
- try:
- result = entry["content"]["itemContent"]["user_results"][
- "result"
- ]
- screen_name = result["legacy"]["screen_name"]
- if screen_name not in (
- user["screen_name"] for user in tweets_data
- ):
- tweets_data.append(
- self.get_user_data_from_user_results(result)
- )
- except (KeyError, TypeError, IndexError):
- continue
-
- except KeyError:
- return {"users": tweets_data[:limit] if limit > 0 else tweets_data}
-
- cursor_value = self.__get_cursor_value(
- data, "Bottom", "retweeters_timeline"
- )
-
- if not cursor_value or (0 < limit <= len(tweets_data)):
- return {"users": tweets_data[:limit] if limit > 0 else tweets_data}
-
- variables["cursor"] = cursor_value
-
- @staticmethod
- def get_user_data_from_user_results(data: dict) -> dict:
- legacy = data.get("legacy", {})
-
- return {
- "id": data.get("rest_id"),
- "name": legacy.get("name"),
- "screen_name": legacy.get("screen_name"),
- "profile_image_url": legacy.get("profile_image_url_https"),
- "favourites_count": legacy.get("favourites_count"),
- "followers_count": legacy.get("followers_count"),
- "friends_count": legacy.get("friends_count"),
- "location": legacy.get("location"),
- "description": legacy.get("description"),
- "created_at": legacy.get("created_at"),
- }
-
- def tweet_replies(
- self, celery_task, tweet_id: int, limit: int = 0
- ) -> dict[str, list[dict[str, dict | Any]]]:
- variables = {"focalTweetId": tweet_id}
- replies_data = []
-
- while True:
- data = self.gql("GET", Operation.TweetDetail, variables)
-
- for entry in data["data"]["threaded_conversation_with_injections_v2"][
- "instructions"
- ][0]["entries"]:
- try:
- result = entry["content"]["items"][0]["item"]["itemContent"][
- "tweet_results"
- ]["result"]
- reply_text = result["legacy"]["full_text"]
- user_results = result["core"]["user_results"]["result"]
-
- if reply_text not in (
- reply["reply_text"] for reply in replies_data
- ):
- replies_data.append(
- {
- "reply_text": reply_text,
- "user_data": self.get_user_data_from_user_results(
- user_results
- ),
- }
- )
- except (KeyError, TypeError, IndexError):
- continue
-
- entries = data["data"]["threaded_conversation_with_injections_v2"][
- "instructions"
- ][0]["entries"]
- if not entries[-1]["entryId"].startswith("cursor-bottom") or (
- 0 < limit <= len(replies_data)
- ):
- return {"replies": replies_data[:limit] if limit > 0 else replies_data}
-
- for entry in entries:
- if entry["entryId"].startswith("cursor-bottom"):
- cursor_value = entry["content"]["itemContent"]["value"]
- variables["cursor"] = cursor_value
- break
-
- def user_followers(self, celery_task, username: str, limit: int = 0) -> list[str]:
- variables = {"screen_name": username, "count": 200}
- users = []
-
- while True:
- r = self.session.get(f"{self.v1_api}/followers/list.json", params=variables)
- if r.status_code == 503:
- asyncio.sleep(3)
- continue
-
- else:
- data = self._verify_response(r)
- new_users = [user["screen_name"] for user in data["users"]]
- users.extend(new_users)
-
- next_cursor = int(data.get("next_cursor"))
- if next_cursor == 0 or (0 < limit <= len(users)):
- return users[:limit] if limit > 0 else users
-
- variables["cursor"] = data["next_cursor_str"]
-
- def user_followings(self, username: str) -> list[str]:
- variables = {"screen_name": username, "count": 200}
- users = []
-
- while True:
- r = self.session.get(f"{self.v1_api}/friends/list.json", params=variables)
- if r.status_code == 503:
- asyncio.sleep(5)
- continue
-
- else:
- data = self._verify_response(r)
- new_users = [user["screen_name"] for user in data["users"]]
- users.extend(new_users)
-
- if int(data.get("next_cursor")) == 0:
- return users
-
- variables["cursor"] = data["next_cursor_str"]
-
- def user_last_tweets(
- self, user_id: int, username: str
- ) -> list[dict[str, str, str | None, str | None, str | None]]:
- data = self.gql("GET", Operation.UserTweets, {"userId": user_id})
-
- try:
- tweets_data = []
- timeline = data["data"]["user"]["result"]["timeline_v2"]["timeline"]
- for tweet in timeline["instructions"]:
- entries = tweet.get("entries", [])
- for entry in entries:
- if entry["entryId"].startswith("tweet"):
- tweet_link = f"https://twitter.com/{username}/status/{entry['entryId'].split('-')[-1]}"
- else:
- continue
-
- tweet_results = (
- entry.get("content", {})
- .get("itemContent", {})
- .get("tweet_results", {})
- .get("result", {})
- .get("legacy")
- )
- if tweet_results and tweet_results.get("full_text"):
- full_text = tweet_results["full_text"]
- created_at = tweet_results.get("created_at", "")
- is_quote_status = tweet_results.get("is_quote_status", "")
- lang = tweet_results.get("lang", "")
-
- tweets_data.append(
- {
- "tweet_link": tweet_link,
- "full_text": full_text,
- "created_at": created_at,
- "is_quote_status": is_quote_status,
- "lang": lang,
- }
- )
-
- return tweets_data
-
- except Exception as error:
- raise TwitterError({"error_message": f"Failed to get user tweets: {error}"})
-
- def like(self, tweet_id: int) -> dict:
- variables = {"tweet_id": tweet_id}
- return self.gql("POST", Operation.FavoriteTweet, variables)
-
- def unlike(self, tweet_id: int) -> dict:
- variables = {"tweet_id": tweet_id}
- return self.gql("POST", Operation.UnfavoriteTweet, variables)
-
- def bookmark(self, tweet_id: int) -> dict:
- variables = {"tweet_id": tweet_id}
- return self.gql("POST", Operation.CreateBookmark, variables)
-
- def unbookmark(self, tweet_id: int) -> dict:
- variables = {"tweet_id": tweet_id}
- return self.gql("POST", Operation.DeleteBookmark, variables)
-
- def create_list(self, name: str, description: str, private: bool) -> dict:
- variables = {
- "isPrivate": private,
- "name": name,
- "description": description,
- }
- return self.gql("POST", Operation.CreateList, variables)
-
- def update_list(
- self, list_id: int, name: str, description: str, private: bool
- ) -> dict:
- variables = {
- "listId": list_id,
- "isPrivate": private,
- "name": name,
- "description": description,
- }
- return self.gql("POST", Operation.UpdateList, variables)
-
- def update_pinned_lists(self, list_ids: list[int]) -> dict:
- """
- Update pinned lists.
- Reset all pinned lists and pin all specified lists in the order they are provided.
-
- @param list_ids: list of list ids to pin
- @return: response
- """
- return self.gql("POST", Operation.ListsPinMany, {"listIds": list_ids})
-
- def pin_list(self, list_id: int) -> dict:
- return self.gql("POST", Operation.ListPinOne, {"listId": list_id})
-
- def unpin_list(self, list_id: int) -> dict:
- return self.gql("POST", Operation.ListUnpinOne, {"listId": list_id})
-
- def add_list_member(self, list_id: int, user_id: int) -> dict:
- return self.gql(
- "POST", Operation.ListAddMember, {"listId": list_id, "userId": user_id}
- )
-
- def remove_list_member(self, list_id: int, user_id: int) -> dict:
- return self.gql(
- "POST", Operation.ListRemoveMember, {"listId": list_id, "userId": user_id}
- )
-
- def delete_list(self, list_id: int) -> dict:
- return self.gql("POST", Operation.DeleteList, {"listId": list_id})
-
- def update_list_banner(self, list_id: int, media: str) -> dict:
- media_id = self.upload_media(media)
- variables = {"listId": list_id, "mediaId": media_id}
- return self.gql("POST", Operation.EditListBanner, variables)
-
- def delete_list_banner(self, list_id: int) -> dict:
- return self.gql("POST", Operation.DeleteListBanner, {"listId": list_id})
-
- def follow_topic(self, topic_id: int) -> dict:
- return self.gql("POST", Operation.TopicFollow, {"topicId": str(topic_id)})
-
- def unfollow_topic(self, topic_id: int) -> dict:
- return self.gql("POST", Operation.TopicUnfollow, {"topicId": str(topic_id)})
-
- def pin(self, tweet_id: int) -> dict:
- return self.v1(
- "account/pin_tweet.json", {"tweet_mode": "extended", "id": tweet_id}
- )
-
- def unpin(self, tweet_id: int) -> dict:
- return self.v1(
- "account/unpin_tweet.json", {"tweet_mode": "extended", "id": tweet_id}
- )
-
- def get_user_id(self, username: str) -> int:
- headers = get_headers(self.session)
- headers["content-type"] = "application/x-www-form-urlencoded"
- r = self.session.get(
- f"{self.v1_api}/users/show.json",
- headers=headers,
- params={"screen_name": username},
- )
- data = self._verify_response(r)
- return data["id"]
-
- def get_user_info(self, username: str) -> dict:
- headers = get_headers(self.session)
- headers["content-type"] = "application/x-www-form-urlencoded"
- r = self.session.get(
- f"{self.v1_api}/users/show.json",
- headers=headers,
- params={"screen_name": username},
- )
- return self._verify_response(r)
-
- def follow(self, user_id: int | str) -> dict:
- settings = deepcopy(follow_settings)
- settings |= {"user_id": user_id}
- return self.v1("friendships/create.json", settings)
-
- def unfollow(self, user_id: int | str) -> dict:
- settings = deepcopy(follow_settings)
- settings |= {"user_id": user_id}
- return self.v1("friendships/destroy.json", settings)
-
- def mute(self, user_id: int) -> dict:
- return self.v1("mutes/users/create.json", {"user_id": user_id})
-
- def unmute(self, user_id: int) -> dict:
- return self.v1("mutes/users/destroy.json", {"user_id": user_id})
-
- def enable_follower_notifications(self, user_id: int) -> dict:
- settings = deepcopy(follower_notification_settings)
- settings |= {"id": user_id, "device": "true"}
- return self.v1("friendships/update.json", settings)
-
- def disable_follower_notifications(self, user_id: int) -> dict:
- settings = deepcopy(follower_notification_settings)
- settings |= {"id": user_id, "device": "false"}
- return self.v1("friendships/update.json", settings)
-
- def block(self, user_id: int) -> dict:
- return self.v1("blocks/create.json", {"user_id": user_id})
-
- def unblock(self, user_id: int) -> dict:
- return self.v1("blocks/destroy.json", {"user_id": user_id})
-
- def update_profile_image(self, media: str) -> dict:
- media_id = self.upload_media(media)
- params = {"media_id": media_id}
-
- r = self.session.post(
- f"{self.v1_api}/account/update_profile_image.json",
- headers=get_headers(self.session),
- params=params,
- )
- return self._verify_response(r)
-
- def update_profile_banner(self, media: str) -> dict:
- media_id = self.upload_media(media)
- params = {"media_id": media_id}
-
- r = self.session.post(
- f"{self.v1_api}/account/update_profile_banner.json",
- headers=get_headers(self.session),
- params=params,
- )
- return self._verify_response(r)
-
- def update_profile_info(self, params: dict) -> dict:
- headers = get_headers(self.session)
- r = self.session.post(
- f"{self.v1_api}/account/update_profile.json", headers=headers, params=params
- )
-
- return self._verify_response(r)
-
- def update_search_settings(self, settings: dict) -> dict:
- twid = int(self.session.cookies.get("twid").split("=")[-1].strip('"'))
- headers = get_headers(self.session)
-
- r = self.session.post(
- url=f"{self.v1_api}/strato/column/User/{twid}/search/searchSafety",
- headers=headers,
- json=settings,
- )
- return self._verify_response(r)
-
- def update_settings(self, settings: dict) -> dict:
- return self.v1("account/settings.json", settings)
-
- def update_username(self, username: str):
- return self.update_settings({"screen_name": username})
-
- def change_password(self, old: str, new: str) -> dict:
- params = {
- "current_password": old,
- "password": new,
- "password_confirmation": new,
- }
- headers = get_headers(self.session)
- headers["content-type"] = "application/x-www-form-urlencoded"
-
- r = self.session.post(
- f"{self.v1_api}/account/change_password.json",
- headers=headers,
- data=params,
- allow_redirects=True,
- )
- return self._verify_response(r)
-
- def remove_interests(self, *args) -> dict:
- """
- Pass 'all' to remove all interests
- """
- r = self.session.get(
- f"{self.v1_api}/account/personalization/twitter_interests.json",
- headers=get_headers(self.session),
- )
- current_interests = r.json()["interested_in"]
- if args == "all":
- disabled_interests = [x["id"] for x in current_interests]
- else:
- disabled_interests = [
- x["id"] for x in current_interests if x["display_name"] in args
- ]
- payload = {
- "preferences": {
- "interest_preferences": {
- "disabled_interests": disabled_interests,
- "disabled_partner_interests": [],
- }
- }
- }
- r = self.session.post(
- f"{self.v1_api}/account/personalization/p13n_preferences.json",
- headers=get_headers(self.session),
- json=payload,
- )
- return self._verify_response(r)
-
- def home_timeline(self, limit=math.inf) -> list[dict]:
- return self._paginate(
- "POST", Operation.HomeTimeline, Operation.default_variables, int(limit)
- )
-
- def home_latest_timeline(self, limit=math.inf) -> list[dict]:
- return self._paginate(
- "POST",
- Operation.HomeLatestTimeline,
- Operation.default_variables,
- int(limit),
- )
-
- def bookmarks(self, limit=math.inf) -> list[dict]:
- return self._paginate("GET", Operation.Bookmarks, {}, int(limit))
-
- def _paginate(
- self, method: str, operation: tuple, variables: dict, limit: int
- ) -> list[dict]:
- initial_data = self.gql(method, operation, variables)
- res = [initial_data]
- ids = set(find_key(initial_data, "rest_id"))
- dups = 0
- DUP_LIMIT = 3
-
- cursor = get_cursor(initial_data)
- while (dups < DUP_LIMIT) and cursor:
- prev_len = len(ids)
- if prev_len >= limit:
- return res
-
- variables["cursor"] = cursor
- data = self.gql(method, operation, variables)
-
- cursor = get_cursor(data)
- ids |= set(find_key(data, "rest_id"))
-
- if prev_len == len(ids):
- dups += 1
-
- res.append(data)
- return res
-
- def custom_upload_media(self, file: Path) -> int | None:
- url = "https://upload.twitter.com/1.1/media/upload.json"
-
- headers = get_headers(self.session)
- with httpx.Client(
- headers=headers, cookies=dict(self.session.cookies)
- ) as client:
- upload_type = "tweet"
- media_type = mimetypes.guess_type(file)[0]
- media_category = (
- f"{upload_type}_gif"
- if "gif" in media_type
- else f'{upload_type}_{media_type.split("/")[0]}'
- )
-
- files = {"media": file.read_bytes()}
-
- post_data = {}
- if media_category is not None:
- post_data["media_category"] = media_category
-
- r = client.post(url=url, json=params, params=post_data, files=files)
-
- data = self._verify_response(r)
- return data["media_id"]
-
- def upload_media(self, filename: str, is_dm: bool = False) -> int | None:
- """
- https://developer.twitter.com/en/docs/twitter-api/v1/media/upload-media/uploading-media/media-best-practices
- """
-
- def check_media(category: str, size: int) -> None:
- fmt = lambda x: f"{(x / 1e6):.2f} MB"
- msg = (
- lambda x: f"cannot upload {fmt(size)} {category}, max size is {fmt(x)}"
- )
- if category == "image" and size > MAX_IMAGE_SIZE:
- raise Exception(msg(MAX_IMAGE_SIZE))
- if category == "gif" and size > MAX_GIF_SIZE:
- raise Exception(msg(MAX_GIF_SIZE))
- if category == "video" and size > MAX_VIDEO_SIZE:
- raise Exception(msg(MAX_VIDEO_SIZE))
-
- # if is_profile:
- # url = 'https://upload.twitter.com/i/media/upload.json'
- # else:
- # url = 'https://upload.twitter.com/1.1/media/upload.json'
-
- url = "https://upload.twitter.com/i/media/upload.json"
-
- file = Path(filename)
- total_bytes = file.stat().st_size
- headers = get_headers(self.session)
-
- upload_type = "dm" if is_dm else "tweet"
- media_type = mimetypes.guess_type(file)[0]
- media_category = (
- f"{upload_type}_gif"
- if "gif" in media_type
- else f'{upload_type}_{media_type.split("/")[0]}'
- )
-
- check_media(media_category, total_bytes)
-
- params = {
- "command": "INIT",
- "media_type": media_type,
- "total_bytes": total_bytes,
- "media_category": media_category,
- }
- r = self.session.post(
- url=url, headers=headers, params=params, allow_redirects=True
- )
-
- data = self._verify_response(r)
- media_id = data["media_id"]
-
- desc = f"uploading: {file.name}"
- with tqdm(
- total=total_bytes, desc=desc, unit="B", unit_scale=True, unit_divisor=1024
- ) as pbar:
- with open(file, "rb") as fp:
- i = 0
- while chunk := fp.read(UPLOAD_CHUNK_SIZE):
- params = {
- "command": "APPEND",
- "media_id": media_id,
- "segment_index": i,
- }
- try:
- pad = bytes(
- "".join(random.choices(ascii_letters, k=16)),
- encoding="utf-8",
- )
- data = b"".join(
- [
- b"------WebKitFormBoundary",
- pad,
- b'\r\nContent-Disposition: form-data; name="media"; filename="blob"',
- b"\r\nContent-Type: application/octet-stream",
- b"\r\n\r\n",
- chunk,
- b"\r\n------WebKitFormBoundary",
- pad,
- b"--\r\n",
- ]
- )
- _headers = {
- b"content-type": b"multipart/form-data; boundary=----WebKitFormBoundary"
- + pad
- }
- self.session.post(
- url=url,
- headers=headers | _headers,
- params=params,
- content=data,
- allow_redirects=True,
- )
- except Exception as error:
- try:
- files = {"media": chunk}
- self.session.post(
- url=url, headers=headers, params=params, files=files
- )
- except Exception as error:
- return
-
- i += 1
- pbar.update(fp.tell() - pbar.n)
-
- params = {"command": "FINALIZE", "media_id": media_id, "allow_async": "true"}
- if is_dm:
- params |= {"original_md5": hashlib.md5(file.read_bytes()).hexdigest()}
-
- r = self.session.post(
- url=url, headers=headers, params=params, allow_redirects=True
- )
- data = self._verify_response(r)
-
- processing_info = data.get("processing_info")
- while processing_info:
- state = processing_info["state"]
- if error := processing_info.get("error"):
- return
- if state == MEDIA_UPLOAD_SUCCEED:
- break
- if state == MEDIA_UPLOAD_FAIL:
- return
- check_after_secs = processing_info.get(
- "check_after_secs", random.randint(1, 5)
- )
-
- time.sleep(check_after_secs)
- params = {"command": "STATUS", "media_id": media_id}
-
- r = self.session.get(
- url=url, headers=headers, params=params, allow_redirects=True
- )
- data = self._verify_response(r)
- processing_info = data.get("processing_info")
-
- return media_id
-
- def _add_alt_text(self, media_id: int, text: str) -> dict:
- params = {"media_id": media_id, "alt_text": {"text": text}}
- url = f"{self.v1_api}/media/metadata/create.json"
- r = self.session.post(url, headers=get_headers(self.session), json=params)
- return self._verify_response(r)
-
- def dm_inbox(self) -> dict:
- """
- Get DM inbox metadata.
-
- @return: inbox as dict
- """
- r = self.session.get(
- f"{self.v1_api}/dm/inbox_initial_state.json",
- headers=get_headers(self.session),
- params=dm_params,
- )
- return self._verify_response(r)
-
- # def dm_history(self, conversation_ids: list[str] = None) -> list[dict]:
- # """
- # Get DM history.
- #
- # Call without arguments to get all DMS from all conversations.
- #
- # @param conversation_ids: optional list of conversation ids
- # @return: list of messages as dicts
- # """
- #
- # def get(session: AsyncClient, conversation_id: str):
- # params = deepcopy(dm_params)
- # r = session.get(
- # f"{self.v1_api}/dm/conversation/{conversation_id}.json",
- # params=params,
- # )
- # res = (self._verify_response(r)).get("conversation_timeline", {})
- # data = [x.get("message") for x in res.get("entries", [])]
- # entry_id = res.get("min_entry_id")
- # while entry_id:
- # params["max_id"] = entry_id
- # r = session.get(
- # f"{self.v1_api}/dm/conversation/{conversation_id}.json",
- # params=params,
- # )
- # res = (self._verify_response(r)).get("conversation_timeline", {})
- # data.extend(x["message"] for x in res.get("entries", []))
- # entry_id = res.get("min_entry_id")
- # return data
- #
- # def process(ids):
- # limits = Limits(max_connections=100)
- # headers, cookies = get_headers(self.session), self.session.cookies
- # async with AsyncClient(
- # limits=limits, headers=headers, cookies=cookies, timeout=20
- # ) as c:
- # return tqdm_asyncio.gather(
- # *(get(c, _id) for _id in ids), desc="Getting DMs"
- # )
- #
- # if conversation_ids:
- # ids = conversation_ids
- # else:
- # # get all conversations
- # inbox = self.dm_inbox()
- # ids = list(inbox["inbox_initial_state"]["conversations"])
- #
- # return asyncio.run(process(ids))
-
- def dm_delete(self, *, conversation_id: str = None, message_id: str = None) -> dict:
- """
- Delete operations
-
- - delete (hide) a single DM
- - delete an entire conversation
-
- @param conversation_id: the conversation id
- @param message_id: the message id
- @return: result metadata
- """
- self.session.headers.update(headers=get_headers(self.session))
- results = {"conversation": None, "message": None}
- if conversation_id:
- results["conversation"] = self.session.post(
- f"{self.v1_api}/dm/conversation/{conversation_id}/delete.json",
- ) # not json response
- if message_id:
- # delete single message
- _id, op = Operation.DMMessageDeleteMutation
- results["message"] = self.session.post(
- f"{self.gql_api}/{_id}/{op}",
- json={"queryId": _id, "variables": {"messageId": message_id}},
- )
- return results
-
- def dm_search(self, query: str) -> dict:
- """
- Search DMs by keyword
-
- @param query: search term
- @return: search results as dict
- """
-
- def get(cursor=None):
- if cursor:
- params["variables"]["cursor"] = cursor.pop()
- _id, op = Operation.DmAllSearchSlice
- r = self.session.get(
- f"{self.gql_api}/{_id}/{op}",
- params=build_params(params),
- )
- res = r.json()
- cursor = find_key(res, "next_cursor")
- return res, cursor
-
- self.session.headers.update(headers=get_headers(self.session))
- variables = deepcopy(Operation.default_variables)
- variables["count"] = 50 # strict limit, errors thrown if exceeded
- variables["query"] = query
- params = {"variables": variables, "features": Operation.default_features}
- res, cursor = get()
- data = [res]
- while cursor:
- res, cursor = get(cursor)
- data.append(res)
- return {"query": query, "data": data}
-
- def scheduled_tweets(self, ascending: bool = True) -> dict:
- variables = {"ascending": ascending}
- return self.gql("GET", Operation.FetchScheduledTweets, variables)
-
- def delete_scheduled_tweet(self, tweet_id: int) -> dict:
- """duplicate, same as `unschedule_tweet()`"""
- variables = {"scheduled_tweet_id": tweet_id}
- return self.gql("POST", Operation.DeleteScheduledTweet, variables)
-
- def clear_scheduled_tweets(self) -> None:
- user_id = int(re.findall('"u=(\d+)"', self.session.cookies.get("twid"))[0])
- drafts = self.gql("GET", Operation.FetchScheduledTweets, {"ascending": True})
- for _id in set(find_key(drafts, "rest_id")):
- if _id != user_id:
- self.gql(
- "POST", Operation.DeleteScheduledTweet, {"scheduled_tweet_id": _id}
- )
-
- def draft_tweets(self, ascending: bool = True) -> dict:
- variables = {"ascending": ascending}
- return self.gql("GET", Operation.FetchDraftTweets, variables)
-
- def delete_draft_tweet(self, tweet_id: int) -> dict:
- variables = {"draft_tweet_id": tweet_id}
- return self.gql("POST", Operation.DeleteDraftTweet, variables)
-
- def clear_draft_tweets(self) -> None:
- user_id = int(re.findall('"u=(\d+)"', self.session.cookies.get("twid"))[0])
- drafts = self.gql("GET", Operation.FetchDraftTweets, {"ascending": True})
- for _id in set(find_key(drafts, "rest_id")):
- if _id != user_id:
- self.gql("POST", Operation.DeleteDraftTweet, {"draft_tweet_id": _id})
-
- def notifications(self, params: dict = None) -> dict:
- r = self.session.get(
- f"{self.v2_api}/notifications/all.json",
- headers=get_headers(self.session),
- params=params or live_notification_params,
- )
- return self._verify_response(r)
-
- def recommendations(self, params: dict = None) -> dict:
- r = self.session.get(
- f"{self.v1_api}/users/recommendations.json",
- headers=get_headers(self.session),
- params=params or recommendations_params,
- )
- return self._verify_response(r)
-
- def fleetline(self, params: dict = None) -> dict:
- r = self.session.get(
- "https://twitter.com/i/api/fleets/v1/fleetline",
- headers=get_headers(self.session),
- params=params or {},
- )
- return self._verify_response(r)
-
- @property
- def id(self) -> int:
- """Get User ID"""
- return int(re.findall('"u=(\d+)"', self.session.cookies.get("twid"))[0])
-
- def save_cookies(self, fname: str = None):
- """Save cookies to file"""
- cookies = self.session.cookies
- Path(f'{fname or cookies.get("username")}.cookies').write_bytes(
- orjson.dumps(dict(cookies))
- )
diff --git a/twitter_api/constants.py b/twitter_api/constants.py
deleted file mode 100644
index 643b8c3..0000000
--- a/twitter_api/constants.py
+++ /dev/null
@@ -1,801 +0,0 @@
-from dataclasses import dataclass
-
-
-MAX_IMAGE_SIZE = 5_242_880 # ~5 MB
-MAX_GIF_SIZE = 15_728_640 # ~15 MB
-MAX_VIDEO_SIZE = 536_870_912 # ~530 MB
-
-UPLOAD_CHUNK_SIZE = 4 * 1024 * 1024
-MEDIA_UPLOAD_SUCCEED = "succeeded"
-MEDIA_UPLOAD_FAIL = "failed"
-
-BLACK = "\x1b[30m"
-RED = "\x1b[31m"
-GREEN = "\x1b[32m"
-YELLOW = "\x1b[33m"
-BLUE = "\x1b[34m"
-MAGENTA = "\x1b[35m"
-CYAN = "\x1b[36m"
-WHITE = "\x1b[37m"
-BOLD = "\x1b[1m"
-RESET = "\x1b[0m"
-
-LOG_CONFIG = {
- "version": 1,
- "disable_existing_loggers": False,
- "formatters": {
- "standard": {
- "format": "%(asctime)s.%(msecs)03d [%(levelname)s] :: %(message)s",
- "datefmt": "%Y-%m-%d %H:%M:%S",
- },
- },
- "handlers": {
- "console": {
- "class": "logging.StreamHandler",
- "level": "DEBUG",
- "formatter": "standard",
- "stream": "ext://sys.stdout",
- },
- "file": {
- "class": "logging.FileHandler",
- "level": "DEBUG",
- "formatter": "standard",
- "filename": "twitter.log",
- "mode": "a",
- },
- },
- "loggers": {
- "twitter": {
- "handlers": ["console", "file"],
- "level": "DEBUG",
- }
- },
-}
-
-ID_MAP = {
- "Followers": "^user-\d+$",
- "Following": "^user-\d+$",
- "UserTweets": "^tweet-\d+$",
- "Likes": "^tweet-\d+$",
- "UserMedia": "^tweet-\d+$",
- "TweetResultByRestId": "^tweet-\d+$",
- "TweetsAndReplies": "^profile-conversation-\d+-tweet-\d+$",
- "TweetDetail": "^conversationthread-\d+-tweet-\d+$", # if another key after tweet-\d+, it's an ad
- "Retweeters": "^user-\d+$",
- "Favoriters": "^user-\d+$",
-}
-
-
-@dataclass
-class SearchCategory:
- Top = "Top"
- Latest = "Latest"
- People = "People"
- Photos = "Photos"
- Videos = "Videos"
-
-
-@dataclass
-class SpaceCategory:
- Top = "Top"
- Live = "Live"
- Upcoming = "Upcoming"
-
-
-@dataclass
-class SpaceState:
- Ended = "Ended"
- Canceled = "Canceled"
- NotStarted = "NotStarted"
- PrePublished = "PrePublished"
- Running = "Running"
- TimedOut = "TimedOut"
-
-
-@dataclass
-class Operation:
- # todo: dynamically update
- SearchTimeline = (
- {"rawQuery": str, "product": str},
- "nK1dw4oV3k4w5TdtcAdSww",
- "SearchTimeline",
- )
- AudioSpaceById = {"id": str}, "fYAuJHiY3TmYdBmrRtIKhA", "AudioSpaceById"
- AudioSpaceSearch = (
- {"filter": str, "query": str},
- "NTq79TuSz6fHj8lQaferJw",
- "AudioSpaceSearch",
- )
- UserByScreenName = (
- {"screen_name": str},
- "sLVLhk0bGj3MVFEKTdax1w",
- "UserByScreenName",
- )
- UserTweets = "HuTx74BxAnezK1gWvYY7zg", "UserTweets"
- ProfileSpotlightsQuery = (
- {"screen_name": str},
- "9zwVLJ48lmVUk8u_Gh9DmA",
- "ProfileSpotlightsQuery",
- )
- UserByRestId = {"userId": int}, "GazOglcBvgLigl3ywt6b3Q", "UserByRestId"
- UsersByRestIds = {"userIds": list}, "OJBgJQIrij6e3cjqQ3Zu1Q", "UsersByRestIds"
- UserMedia = {"userId": int}, "YqiE3JL1KNgf9nSljYdxaA", "UserMedia"
- UserTweetsAndReplies = (
- {"userId": int},
- "RIWc55YCNyUJ-U3HHGYkdg",
- "UserTweetsAndReplies",
- )
- TweetResultByRestId = (
- {"tweetId": int},
- "D_jNhjWZeRZT5NURzfJZSQ",
- "TweetResultByRestId",
- )
- TweetDetail = "zXaXQgfyR4GxE21uwYQSyA", "TweetDetail"
- TweetStats = {"rest_id": int}, "EvbTkPDT-xQCfupPu0rWMA", "TweetStats"
- Likes = {"userId": int}, "nXEl0lfN_XSznVMlprThgQ", "Likes"
- Followers = {"userId": int}, "pd8Tt1qUz1YWrICegqZ8cw", "Followers"
- Following = {"userId": int}, "wjvx62Hye2dGVvnvVco0xA", "Following"
- Retweeters = "0BoJlKAxoNPQUHRftlwZ2w", "Retweeters"
- Favoriters = "XRRjv1-uj1HZn3o324etOQ", "Favoriters"
- ConnectTabTimeline = (
- {"context": dict},
- "lq02A-gEzbLefqTgD_PFzQ",
- "ConnectTabTimeline",
- )
-
- # Account Operations
- useSendMessageMutation = "MaxK2PKX1F9Z-9SwqwavTw", "useSendMessageMutation"
- CreateTweet = "7TKRKCPuAGsmYde0CudbVg", "CreateTweet"
- DeleteTweet = "VaenaVgh5q5ih7kvyVjgtg", "DeleteTweet"
- CreateScheduledTweet = "LCVzRQGxOaGnOnYH01NQXg", "CreateScheduledTweet"
- DeleteScheduledTweet = "CTOVqej0JBXAZSwkp1US0g", "DeleteScheduledTweet"
- CreateRetweet = "ojPdsZsimiJrUGLR1sjUtA", "CreateRetweet"
- DeleteRetweet = "iQtK4dl5hBmXewYZuEOKVw", "DeleteRetweet"
- FavoriteTweet = "lI07N6Otwv1PhnEgXILM7A", "FavoriteTweet"
- UnfavoriteTweet = "ZYKSe-w7KEslx3JhSIk5LA", "UnfavoriteTweet"
- CreateBookmark = "aoDbu3RHznuiSkQ9aNM67Q", "CreateBookmark"
- DeleteBookmark = "Wlmlj2-xzyS1GN3a6cj-mQ", "DeleteBookmark"
- CreateList = "hQAsnViq2BrMLbPuQ9umDA", "CreateList"
- UpdateList = "4dCEFWtxEbhnSLcJdJ6PNg", "UpdateList"
- ListsPinMany = "2X4Vqu6XLneR-XZnGK5MAw", "ListsPinMany"
- ListPinOne = "2pYlo-kjdXoNOZJoLzI6KA", "ListPinOne"
- ListUnpinOne = "c4ce-hzx6V4heV5IzdeBkA", "ListUnpinOne"
- ListAddMember = "P8tyfv2_0HzofrB5f6_ugw", "ListAddMember"
- ListRemoveMember = "DBZowzFN492FFkBPBptCwg", "ListRemoveMember"
- DeleteList = "UnN9Th1BDbeLjpgjGSpL3Q", "DeleteList"
- EditListBanner = "Uk0ZwKSMYng56aQdeJD1yw", "EditListBanner"
- DeleteListBanner = "-bOKetDVCMl20qXn7YDXIA", "DeleteListBanner"
- TopicFollow = "ElqSLWFmsPL4NlZI5e1Grg", "TopicFollow"
- TopicUnfollow = "srwjU6JM_ZKTj_QMfUGNcw", "TopicUnfollow"
- HomeLatestTimeline = "zhX91JE87mWvfprhYE97xA", "HomeLatestTimeline"
- HomeTimeline = "HCosKfLNW1AcOo3la3mMgg", "HomeTimeline"
- Bookmarks = "tmd4ifV8RHltzn8ymGg1aw", "Bookmarks"
-
- # misc/not implemented
- AdAccounts = "a8KxGfFQAmm3WxqemuqSRA", "AdAccounts"
- ArticleTimeline = "o9FyvnC-xg8mVBXqL4g-rg", "ArticleTimeline"
- ArticleTweetsTimeline = "x4ywSpvg6BesoDszkfbFQg", "ArticleTweetsTimeline"
- AudienceEstimate = "1LYVUabJBYkPlUAWRabB3g", "AudienceEstimate"
- AuthenticatedUserTFLists = "QjN8ZdavFDqxUjNn3r9cig", "AuthenticatedUserTFLists"
- BirdwatchAliasSelect = "3ss48WFwGokBH_gj8t_8aQ", "BirdwatchAliasSelect"
- BirdwatchCreateAppeal = "TKdL0YFsX4DMOpMKeneLvA", "BirdwatchCreateAppeal"
- BirdwatchCreateNote = "36EUZZyaciVmNrq4CRZcmw", "BirdwatchCreateNote"
- BirdwatchCreateRating = "bD3AEK9BMCSpRods_ng2fA", "BirdwatchCreateRating"
- BirdwatchDeleteNote = "IKS_qrShkDyor6Ri1ahd9g", "BirdwatchDeleteNote"
- BirdwatchDeleteRating = "OpvCOyOoQClUND66zDzrnA", "BirdwatchDeleteRating"
- BirdwatchEditNotificationSettings = (
- "FLgLReVIssXjB_ui3wcrRQ",
- "BirdwatchEditNotificationSettings",
- )
- BirdwatchFetchAliasSelfSelectOptions = (
- "szoXMke8AZOErso908iglw",
- "BirdwatchFetchAliasSelfSelectOptions",
- )
- BirdwatchFetchAliasSelfSelectStatus = (
- "LUEdtkcpBlGktUtms4BvwA",
- "BirdwatchFetchAliasSelfSelectStatus",
- )
- BirdwatchFetchAuthenticatedUserProfile = (
- "pMbW6Y4LuS5MzlSOEqERJQ",
- "BirdwatchFetchAuthenticatedUserProfile",
- )
- BirdwatchFetchBirdwatchProfile = (
- "btgGtchypc3D491MJ7XXWA",
- "BirdwatchFetchBirdwatchProfile",
- )
- BirdwatchFetchContributorNotesSlice = (
- "t6r3Wq7wripUW9gB3FQNBw",
- "BirdwatchFetchContributorNotesSlice",
- )
- BirdwatchFetchGlobalTimeline = (
- "L3LftPt6fhYqoQ5Vnxm7UQ",
- "BirdwatchFetchGlobalTimeline",
- )
- BirdwatchFetchNotes = "ZGMhf1M7kPKMOhEk1nz0Yw", "BirdwatchFetchNotes"
- BirdwatchFetchOneNote = "GO8BR2MM2WZB63cdOoC7lw", "BirdwatchFetchOneNote"
- BirdwatchFetchPublicData = "9bDdJ6AL26RLkcUShEcF-A", "BirdwatchFetchPublicData"
- BirdwatchProfileAcknowledgeEarnOut = (
- "cED9wJy8Nd1kZCCYuIq9zQ",
- "BirdwatchProfileAcknowledgeEarnOut",
- )
- BizProfileFetchUser = "6OFpJ3TH3p8JpwOSgfgyhg", "BizProfileFetchUser"
- BlockedAccountsAll = "h52d1F7dumWGE1tJAhQBpg", "BlockedAccountsAll"
- BlockedAccountsAutoBlock = "8w-D2OhT0jmGzXaNY--UQA", "BlockedAccountsAutoBlock"
- BlockedAccountsImported = "8LDNeOEm0kA98uoDsqXvMg", "BlockedAccountsImported"
- BookmarkFolderTimeline = "13H7EUATwethsj-XxX5ohw", "BookmarkFolderTimeline"
- BookmarkFoldersSlice = "i78YDd0Tza-dV4SYs58kRg", "BookmarkFoldersSlice"
- BookmarksAllDelete = "skiACZKC1GDYli-M8RzEPQ", "BookmarksAllDelete"
- Budgets = "mbK3oSQotwcJXyQIBE3uYw", "Budgets"
- CardPreviewByTweetText = "jnwTSDR-Eo_HWlSkXPcMGA", "CardPreviewByTweetText"
- CheckTweetForNudge = "C2dcvh7H69JALtomErxWlA", "CheckTweetForNudge"
- CombinedLists = "rIxum3avpCu7APi7mxTNjw", "CombinedLists"
- CommunitiesMainDiscoveryModule = (
- "8UB2fhB8TiYIW2M6vbBFXg",
- "CommunitiesMainDiscoveryModule",
- )
- CommunitiesMainPageTimeline = (
- "DzcxPzkGYVQk-BD0pqAcZw",
- "CommunitiesMainPageTimeline",
- )
- CommunitiesMembershipsSlice = (
- "s8-oxdVsoJ3w2CFD0nFt9g",
- "CommunitiesMembershipsSlice",
- )
- CommunitiesMembershipsTimeline = (
- "QXo-eKTsvhpCyFotNz2u6g",
- "CommunitiesMembershipsTimeline",
- )
- CommunityAboutTimeline = "plOgdpBzpVVQbTOEVuRc_A", "CommunityAboutTimeline"
- CommunityByRestId = "bCVwRBDPi15jrdJQ7NCENQ", "CommunityByRestId"
- CommunityCreateRule = "dShPoN6voXRusgxC1uvGog", "CommunityCreateRule"
- CommunityDiscoveryTimeline = "b3rceNUXWRyo5mSwVZF74Q", "CommunityDiscoveryTimeline"
- CommunityEditBannerMedia = "KVkZwp8Q6xy6iyhlQE5d7Q", "CommunityEditBannerMedia"
- CommunityEditName = "SKToKhvm3Z4Rir8ENCJ3YQ", "CommunityEditName"
- CommunityEditPurpose = "eMat-u2kx6KocreGTAt-hA", "CommunityEditPurpose"
- CommunityEditRule = "9nEl5bNcdteuPGbGCdvEFA", "CommunityEditRule"
- CommunityEditTheme = "4OhW6gWJwiu-JTAgBPsU1w", "CommunityEditTheme"
- CommunityHashtagsTimeline = "hril1TsnshopHbmnjdUmhQ", "CommunityHashtagsTimeline"
- CommunityMemberRelationshipTypeahead = (
- "NEwac2-8ONgf0756ne8oXA",
- "CommunityMemberRelationshipTypeahead",
- )
- CommunityModerationKeepTweet = (
- "f_YqrHSCc1mPlG-aB7pFRw",
- "CommunityModerationKeepTweet",
- )
- CommunityModerationTweetCasesSlice = (
- "V-iC7tjWOlzBJ44SanqGzw",
- "CommunityModerationTweetCasesSlice",
- )
- CommunityRemoveBannerMedia = "lSdK1v30qVhm37rDTgHq0Q", "CommunityRemoveBannerMedia"
- CommunityRemoveRule = "EI_g43Ss_Ixg0EC4K7nzlQ", "CommunityRemoveRule"
- CommunityReorderRules = "VwluNMGnl5uaNZ3LnlCQ_A", "CommunityReorderRules"
- CommunityTweetsRankedTimeline = (
- "P38EspBBPhAfSKPP74-s2Q",
- "CommunityTweetsRankedTimeline",
- )
- CommunityTweetsTimeline = "2JgHOlqfeLusxAT0yGQJjg", "CommunityTweetsTimeline"
- CommunityUpdateRole = "5eq76kkUqfdCzInCtcxQOA", "CommunityUpdateRole"
- CommunityUserInvite = "x8hUNaBCOV2tSalqB9cwWQ", "CommunityUserInvite"
- CommunityUserRelationshipTypeahead = (
- "gi_UGcUurYp6N6p2BaLJqQ",
- "CommunityUserRelationshipTypeahead",
- )
- ConversationControlChange = "hb1elGcj6769uT8qVYqtjw", "ConversationControlChange"
- ConversationControlDelete = "OoMO_aSZ1ZXjegeamF9QmA", "ConversationControlDelete"
- ConvertRitoSuggestedActions = (
- "2njnYoE69O2jdUM7KMEnDw",
- "ConvertRitoSuggestedActions",
- )
- Coupons = "R1h43jnAl2bsDoUkgZb7NQ", "Coupons"
- CreateCommunity = "lRjZKTRcWuqwtYwCWGy9_w", "CreateCommunity"
- CreateCustomerPortalSession = (
- "2LHXrd1uYeaMWhciZgPZFw",
- "CreateCustomerPortalSession",
- )
- CreateDraftTweet = "cH9HZWz_EW9gnswvA4ZRiQ", "CreateDraftTweet"
- CreateNoteTweet = "Pyx6nga4XtTVhfTh1gtX1A", "CreateNoteTweet"
- CreateQuickPromotion = "oDSoVgHhJxnd5IkckgPZdg", "CreateQuickPromotion"
- CreateTrustedFriendsList = "2tP8XUYeLHKjq5RHvuvpZw", "CreateTrustedFriendsList"
- CreateTweetDownvote = "Eo65jl-gww30avDgrXvhUA", "CreateTweetDownvote"
- CreateTweetReaction = "D7M6X3h4-mJE8UB1Ap3_dQ", "CreateTweetReaction"
- DataSaverMode = "xF6sXnKJfS2AOylzxRjf6A", "DataSaverMode"
- DeleteBookmarkFolder = "2UTTsO-6zs93XqlEUZPsSg", "DeleteBookmarkFolder"
- DeleteDraftTweet = "bkh9G3FGgTldS9iTKWWYYw", "DeleteDraftTweet"
- DeletePaymentMethod = "VaaLGwK5KNLoc7wsOmp4uw", "DeletePaymentMethod"
- DeleteTweetDownvote = "VNEvEGXaUAMfiExP8Tbezw", "DeleteTweetDownvote"
- DeleteTweetReaction = "GKwK0Rj4EdkfwdHQMZTpuw", "DeleteTweetReaction"
- DisableUserAccountLabel = "_ckHEj05gan2VfNHG6thBA", "DisableUserAccountLabel"
- DisableVerifiedPhoneLabel = "g2m0pAOamawNtVIfjXNMJg", "DisableVerifiedPhoneLabel"
- DismissRitoSuggestedAction = "jYvwa61cv3NwNP24iUru6g", "DismissRitoSuggestedAction"
- DmAllSearchSlice = "U-QXVRZ6iddb1QuZweh5DQ", "DmAllSearchSlice"
- DmGroupSearchSlice = "5zpY1dCR-8NyxQJS_CFJoQ", "DmGroupSearchSlice"
- DmMutedTimeline = "lrcWa13oyrQc7L33wRdLAQ", "DmMutedTimeline"
- DMMessageDeleteMutation = "BJ6DtxA2llfjnRoRjaiIiw", "DMMessageDeleteMutation"
- DmNsfwMediaFilterUpdate = "of_N6O33zfyD4qsFJMYFxA", "DmNsfwMediaFilterUpdate"
- DmPeopleSearchSlice = "xYSm8m5kJnzm_gFCn5GH-w", "DmPeopleSearchSlice"
- EditBookmarkFolder = "a6kPp1cS1Dgbsjhapz1PNw", "EditBookmarkFolder"
- EditDraftTweet = "JIeXE-I6BZXHfxsgOkyHYQ", "EditDraftTweet"
- EditScheduledTweet = "_mHkQ5LHpRRjSXKOcG6eZw", "EditScheduledTweet"
- EnableLoggedOutWebNotifications = (
- "BqIHKmwZKtiUBPi07jKctg",
- "EnableLoggedOutWebNotifications",
- )
- EnableVerifiedPhoneLabel = "C3RJFfMsb_KcEytpKmRRkw", "EnableVerifiedPhoneLabel"
- EnrollCoupon = "SOyGmNGaEXcvk15s5bqDrA", "EnrollCoupon"
- ExplorePage = "fkypGKlR9Xz9kLvUZDLoXw", "ExplorePage"
- FeatureSettingsUpdate = "-btar_vkBwWA7s3YWfp_9g", "FeatureSettingsUpdate"
- FetchDraftTweets = "ZkqIq_xRhiUme0PBJNpRtg", "FetchDraftTweets"
- FetchScheduledTweets = "ITtjAzvlZni2wWXwf295Qg", "FetchScheduledTweets"
- FollowersYouKnow = "RvojYJJB90VwJ0rdVhbjMQ", "FollowersYouKnow"
- ForYouExplore = "wVEXnyTWzQlEsIuLq_D3tw", "ForYouExplore"
- GenericTimelineById = "LZfAdxTdNolKXw6ZkoY_kA", "GenericTimelineById"
- GetSafetyModeSettings = "AhxTX0lkbIos4WG53xwzSA", "GetSafetyModeSettings"
- GetTweetReactionTimeline = "ihIcULrtrtPGlCuprduRrA", "GetTweetReactionTimeline"
- GetUserClaims = "lFi3xnx0auUUnyG4YwpCNw", "GetUserClaims"
- GraphQLError = "2V2W3HIBuMW83vEMtfo_Rg", "GraphQLError"
- ImmersiveMedia = "UGQD_VslAJBJ4XzigsBYAA", "ImmersiveMedia"
- JoinCommunity = "PXO-mA1KfmLqB9I6R-lOng", "JoinCommunity"
- LeaveCommunity = "AtiTdhEyRN8ruNFW069ewQ", "LeaveCommunity"
- ListByRestId = "wXzyA5vM_aVkBL9G8Vp3kw", "ListByRestId"
- ListBySlug = "3-E3eSWorCv24kYkK3CCiQ", "ListBySlug"
- ListCreationRecommendedUsers = (
- "Zf8ZwG57EKtss-rPlryIqg",
- "ListCreationRecommendedUsers",
- )
- ListEditRecommendedUsers = "-F4wsOirYNXjjg-ZjccQpQ", "ListEditRecommendedUsers"
- ListLatestTweetsTimeline = "2TemLyqrMpTeAmysdbnVqw", "ListLatestTweetsTimeline"
- ListMembers = "vA952kfgGw6hh8KatWnbqw", "ListMembers"
- ListMemberships = "BlEXXdARdSeL_0KyKHHvvg", "ListMemberships"
- ListOwnerships = "wQcOSjSQ8NtgxIwvYl1lMg", "ListOwnerships"
- ListPins = "J0JOhmi8HSsle8LfSWv0cw", "ListPins"
- ListProductSubscriptions = "wwdBYgScze0_Jnan79jEUw", "ListProductSubscriptions"
- ListRankedTweetsTimeline = "07lytXX9oG9uCld1RY4b0w", "ListRankedTweetsTimeline"
- ListSubscribe = "FjvrQI3k-97JIUbEE6Gxcw", "ListSubscribe"
- ListSubscribers = "e57wIELAAe0fYt4Hmqsk6g", "ListSubscribers"
- ListUnsubscribe = "bXyvW9HoS_Omy4ADhexj8A", "ListUnsubscribe"
- ListsDiscovery = "ehnzbxPHA69pyaV2EydN1g", "ListsDiscovery"
- ListsManagementPageTimeline = (
- "nhYp4n09Hi5n2hQWseQztg",
- "ListsManagementPageTimeline",
- )
- LiveCommerceItemsSlice = "-lnNX56S2YrZYrLzbccFAQ", "LiveCommerceItemsSlice"
- ModerateTweet = "pjFnHGVqCjTcZol0xcBJjw", "ModerateTweet"
- ModeratedTimeline = "hnaqw2Vok5OETdBVa_uexw", "ModeratedTimeline"
- MuteList = "ZYyanJsskNUcltu9bliMLA", "MuteList"
- MutedAccounts = "-G9eXTmseyiSenbqjrEG6w", "MutedAccounts"
- NoteworthyAccountsPage = "3fOJzEwYMnVyzwgLTLIBkw", "NoteworthyAccountsPage"
- PaymentMethods = "mPF_G9okpbZuLcD6mN8K9g", "PaymentMethods"
- PinReply = "GA2_1uKP9b_GyR4MVAQXAw", "PinReply"
- ProfileUserPhoneState = "5kUWP8C1hcd6omvg6HXXTQ", "ProfileUserPhoneState"
- PutClientEducationFlag = "IjQ-egg0uPkY11NyPMfRMQ", "PutClientEducationFlag"
- QuickPromoteEligibility = "LtpCXh66W-uXh7u7XSRA8Q", "QuickPromoteEligibility"
- RemoveFollower = "QpNfg0kpPRfjROQ_9eOLXA", "RemoveFollower"
- RemoveTweetFromBookmarkFolder = (
- "2Qbj9XZvtUvyJB4gFwWfaA",
- "RemoveTweetFromBookmarkFolder",
- )
- RequestToJoinCommunity = "6G66cW5zuxPXmHOeBOjF2w", "RequestToJoinCommunity"
- RitoActionedTweetsTimeline = "px9Zbs48D-YdQPEROK6-nA", "RitoActionedTweetsTimeline"
- RitoFlaggedAccountsTimeline = (
- "lMzaBZHIbD6GuPqJJQubMg",
- "RitoFlaggedAccountsTimeline",
- )
- RitoFlaggedTweetsTimeline = "iCuXMibh6yj9AelyjKXDeA", "RitoFlaggedTweetsTimeline"
- RitoSuggestedActionsFacePile = (
- "GnQKeEdL1LyeK3dTQCS1yw",
- "RitoSuggestedActionsFacePile",
- )
- SetDefault = "QEMLEzEMzoPNbeauKCCLbg", "SetDefault"
- SetSafetyModeSettings = "qSJIPIpf4gA7Wn21bT3D4w", "SetSafetyModeSettings"
- SharingAudiospacesListeningDataWithFollowersUpdate = (
- "5h0kNbk3ii97rmfY6CdgAA",
- "SharingAudiospacesListeningDataWithFollowersUpdate",
- )
- SubscribeToScheduledSpace = "Sxn4YOlaAwEKjnjWV0h7Mw", "SubscribeToScheduledSpace"
- SubscriptionCheckoutUrlWithEligibility = (
- "hKfOOObQr5JmfmxW0YtPvg",
- "SubscriptionCheckoutUrlWithEligibility",
- )
- SubscriptionProductDetails = "f0dExZDmFWFSWMCPQSAemQ", "SubscriptionProductDetails"
- SubscriptionProductFeaturesFetch = (
- "Me2CVcAXxvK2WMr-Nh_Qqg",
- "SubscriptionProductFeaturesFetch",
- )
- SuperFollowers = "o0YtPFnd4Lk_pOQb9alCvA", "SuperFollowers"
- TopicByRestId = "4OUZZOonV2h60I0wdlQb_w", "TopicByRestId"
- TopicLandingPage = "mAKQjs1kyTS75VLZzuIXXw", "TopicLandingPage"
- TopicNotInterested = "cPCFdDAaqRjlMRYInZzoDA", "TopicNotInterested"
- TopicToFollowSidebar = "RPWVYYupHVZkJOnokbt2cw", "TopicToFollowSidebar"
- TopicUndoNotInterested = "4tVnt6FoSxaX8L-mDDJo4Q", "TopicUndoNotInterested"
- TopicsManagementPage = "Jvdjpe8qzsJD84BpK3qdkQ", "TopicsManagementPage"
- TopicsPickerPage = "UvG-XXtWNcJN1LzF0u3ByA", "TopicsPickerPage"
- TopicsPickerPageById = "t6kH4v2c_VzWKljc2yNwHA", "TopicsPickerPageById"
- TrustedFriendsTypeahead = "RRnOwHttRGscWKC1zY9VRA", "TrustedFriendsTypeahead"
- TweetEditHistory = "8eaWKjHszkS-G_hprUd9AA", "TweetEditHistory"
- TwitterArticleByRestId = "hwrvh-Qt24lcprL-BDfqRA", "TwitterArticleByRestId"
- TwitterArticleCreate = "aV-sm-IkvwplcxdYDoLZHQ", "TwitterArticleCreate"
- TwitterArticleDelete = "6st-stMDc7KBqLT8KvWhHg", "TwitterArticleDelete"
- TwitterArticleUpdateCoverImage = (
- "fpcVRSAsjvkwmCiN1HheqQ",
- "TwitterArticleUpdateCoverImage",
- )
- TwitterArticleUpdateData = "XpBTYp_QXwyZ0XT0JXCBJw", "TwitterArticleUpdateData"
- TwitterArticleUpdateMedia = "3ojmmegfBC_oHyrmPhxj-g", "TwitterArticleUpdateMedia"
- TwitterArticleUpdateTitle = "dvH6Ql989I4e5jWEV7HfaQ", "TwitterArticleUpdateTitle"
- TwitterArticleUpdateVisibility = (
- "8M35gHyfpcy3S4UXejUGfA",
- "TwitterArticleUpdateVisibility",
- )
- TwitterArticlesSlice = "UUPSi_aS8_kHDFTWqSBPUA", "TwitterArticlesSlice"
- UnmentionUserFromConversation = (
- "xVW9j3OqoBRY9d6_2OONEg",
- "UnmentionUserFromConversation",
- )
- UnmoderateTweet = "pVSyu6PA57TLvIE4nN2tsA", "UnmoderateTweet"
- UnmuteList = "pMZrHRNsmEkXgbn3tOyr7Q", "UnmuteList"
- UnpinReply = "iRe6ig5OV1EzOtldNIuGDQ", "UnpinReply"
- UnsubscribeFromScheduledSpace = (
- "Zevhh76Msw574ZSs2NQHGQ",
- "UnsubscribeFromScheduledSpace",
- )
- UrtFixtures = "I_0j1mjMwv94SdS66S4pqw", "UrtFixtures"
- UserAboutTimeline = "dm7ReTFJoeU0qkiZCO1E1g", "UserAboutTimeline"
- UserAccountLabel = "rD5gLxVmMvtdtYU1UHWlFQ", "UserAccountLabel"
- UserBusinessProfileTeamTimeline = (
- "dq1eUCn3N8v0BywlP4nT7A",
- "UserBusinessProfileTeamTimeline",
- )
- UserPromotableTweets = "jF-OgMv-9vAym3JaCPUnhQ", "UserPromotableTweets"
- UserSessionsList = "vJ-XatpmQSG8bDch8-t9Jw", "UserSessionsList"
- UserSuperFollowTweets = "1by3q8-AJWdNYhtltjlPTQ", "UserSuperFollowTweets"
- Viewer = "okNaf-6AQWu2DD2H_MAoVw", "Viewer"
- ViewerEmailSettings = "JpjlNgn4sLGvS6tgpTzYBg", "ViewerEmailSettings"
- ViewerTeams = "D8mVcJSVv66_3NcR7fOf6g", "ViewerTeams"
- ViewingOtherUsersTopicsPage = (
- "tYXo6h_rpnHXbdLUFMatZA",
- "ViewingOtherUsersTopicsPage",
- )
- WriteDataSaverPreferences = "H03etWvZGz41YASxAU2YPg", "WriteDataSaverPreferences"
- WriteEmailNotificationSettings = (
- "2qKKYFQift8p5-J1k6kqxQ",
- "WriteEmailNotificationSettings",
- )
- adFreeArticleDomains = "zwTrX9CtnMvWlBXjsx95RQ", "adFreeArticleDomains"
- articleNudgeDomains = "88Bu08U2ddaVVjKmmXjVYg", "articleNudgeDomains"
- bookmarkTweetToFolder = "4KHZvvNbHNf07bsgnL9gWA", "bookmarkTweetToFolder"
- createBookmarkFolder = "6Xxqpq8TM_CREYiuof_h5w", "createBookmarkFolder"
- getAltTextPromptPreference = "PFIxTk8owMoZgiMccP0r4g", "getAltTextPromptPreference"
- getCaptionsAlwaysDisplayPreference = (
- "BwgMOGpOViDS0ri7VUgglg",
- "getCaptionsAlwaysDisplayPreference",
- )
- timelinesFeedback = "vfVbgvTPTQ-dF_PQ5lD1WQ", "timelinesFeedback"
- updateAltTextPromptPreference = (
- "aQKrduk_DA46XfOQDkcEng",
- "updateAltTextPromptPreference",
- )
- updateCaptionsAlwaysDisplayPreference = (
- "uCUQhvZ5sJ9qHinRp6CFlQ",
- "updateCaptionsAlwaysDisplayPreference",
- )
-
- default_variables = {
- "count": 1000,
- "withSafetyModeUserFields": True,
- "includePromotedContent": True,
- "withQuickPromoteEligibilityTweetFields": True,
- "withVoice": True,
- "withV2Timeline": True,
- "withDownvotePerspective": False,
- "withBirdwatchNotes": True,
- "withCommunity": True,
- "withSuperFollowsUserFields": True,
- "withReactionsMetadata": False,
- "withReactionsPerspective": False,
- "withSuperFollowsTweetFields": True,
- "isMetatagsQuery": False,
- "withReplays": True,
- "withClientEventToken": False,
- "withAttachments": True,
- "withConversationQueryHighlights": True,
- "withMessageQueryHighlights": True,
- "withMessages": True,
- }
- default_features = {
- "blue_business_profile_image_shape_enabled": True,
- "creator_subscriptions_tweet_preview_api_enabled": True,
- "freedom_of_speech_not_reach_fetch_enabled": True,
- "graphql_is_translatable_rweb_tweet_is_translatable_enabled": True,
- "graphql_timeline_v2_bookmark_timeline": True,
- "hidden_profile_likes_enabled": True,
- "highlights_tweets_tab_ui_enabled": True,
- "interactive_text_enabled": True,
- "longform_notetweets_consumption_enabled": True,
- "longform_notetweets_inline_media_enabled": True,
- "longform_notetweets_rich_text_read_enabled": True,
- "longform_notetweets_richtext_consumption_enabled": True,
- "profile_foundations_tweet_stats_enabled": True,
- "profile_foundations_tweet_stats_tweet_frequency": True,
- "responsive_web_birdwatch_note_limit_enabled": True,
- "responsive_web_edit_tweet_api_enabled": True,
- "responsive_web_enhance_cards_enabled": False,
- "responsive_web_graphql_exclude_directive_enabled": True,
- "responsive_web_graphql_skip_user_profile_image_extensions_enabled": False,
- "responsive_web_graphql_timeline_navigation_enabled": True,
- "responsive_web_media_download_video_enabled": False,
- "responsive_web_text_conversations_enabled": False,
- "responsive_web_twitter_article_data_v2_enabled": True,
- "responsive_web_twitter_article_tweet_consumption_enabled": False,
- "responsive_web_twitter_blue_verified_badge_is_enabled": True,
- "rweb_lists_timeline_redesign_enabled": True,
- "spaces_2022_h2_clipping": True,
- "spaces_2022_h2_spaces_communities": True,
- "standardized_nudges_misinfo": True,
- "subscriptions_verification_info_verified_since_enabled": True,
- "tweet_awards_web_tipping_enabled": False,
- "tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled": True,
- "tweetypie_unmention_optimization_enabled": True,
- "verified_phone_label_enabled": False,
- "vibe_api_enabled": True,
- "view_counts_everywhere_api_enabled": True,
- }
-
-
-trending_params = {
- "include_profile_interstitial_type": "1",
- "include_blocking": "1",
- "include_blocked_by": "1",
- "include_followed_by": "1",
- "include_want_retweets": "1",
- "include_mute_edge": "1",
- "include_can_dm": "1",
- "include_can_media_tag": "1",
- "include_ext_has_nft_avatar": "1",
- "include_ext_is_blue_verified": "1",
- "include_ext_verified_type": "1",
- "skip_status": "1",
- "cards_platform": "Web-12",
- "include_cards": "1",
- "include_ext_alt_text": "true",
- "include_ext_limited_action_results": "false",
- "include_quote_count": "true",
- "include_reply_count": "1",
- "tweet_mode": "extended",
- "include_ext_views": "true",
- "include_entities": "true",
- "include_user_entities": "true",
- "include_ext_media_color": "true",
- "include_ext_media_availability": "true",
- "include_ext_sensitive_media_warning": "true",
- "include_ext_trusted_friends_metadata": "true",
- "send_error_codes": "true",
- "simple_quoted_tweet": "true",
- "count": 1000,
- "requestContext": "launch",
- "include_page_configuration": "true",
- "initial_tab_id": "trending",
- "entity_tokens": "false",
- "ext": "mediaStats,highlightedLabel,hasNftAvatar,voiceInfo,birdwatchPivot,enrichments,superFollowMetadata,unmentionInfo,editControl,vibe",
-}
-
-account_settings = {
- "address_book_live_sync_enabled": False,
- "allow_ads_personalization": False,
- "allow_authenticated_periscope_requests": True,
- "allow_dm_groups_from": "following",
- "allow_dms_from": "following", # all
- "allow_location_history_personalization": False,
- "allow_logged_out_device_personalization": False,
- "allow_media_tagging": "none", # all, following
- "allow_sharing_data_for_third_party_personalization": False,
- "alt_text_compose_enabled": None,
- "always_use_https": True,
- "autoplay_disabled": False,
- "country_code": "us",
- "discoverable_by_email": False,
- "discoverable_by_mobile_phone": False,
- "display_sensitive_media": True,
- "dm_quality_filter": "enabled", # disabled
- "dm_receipt_setting": "all_disabled", # all_enabled
- "geo_enabled": False,
- "include_alt_text_compose": True,
- "include_mention_filter": True,
- "include_nsfw_admin_flag": True,
- "include_nsfw_user_flag": True,
- "include_ranked_timeline": True,
- "language": "en",
- "mention_filter": "unfiltered",
- "nsfw_admin": False,
- "nsfw_user": False,
- "personalized_trends": True,
- "protected": False,
- "ranked_timeline_eligible": None,
- "ranked_timeline_setting": None,
- "require_password_login": False,
- "requires_login_verification": False,
- "settings_metadata": {},
- "sleep_time": {"enabled": False, "end_time": None, "start_time": None},
- "translator_type": "none",
- "universal_quality_filtering_enabled": "enabled",
- "use_cookie_personalization": False,
- ## todo: not yet implemented - requires additional steps
- # 'allow_contributor_request': 'all',
- # 'protect_password_reset': False,
-}
-follower_notification_settings = {
- "cursor": "-1",
- "include_profile_interstitial_type": "1",
- "include_blocking": "1",
- "include_blocked_by": "1",
- "include_followed_by": "1",
- "include_want_retweets": "1",
- "include_mute_edge": "1",
- "include_can_dm": "1",
- "include_can_media_tag": "1",
- "include_ext_has_nft_avatar": "1",
- "include_ext_is_blue_verified": "1",
- "include_ext_verified_type": "1",
- "skip_status": "1",
-}
-
-follow_settings = {
- "include_profile_interstitial_type": "1",
- "include_blocking": "1",
- "include_blocked_by": "1",
- "include_followed_by": "1",
- "include_want_retweets": "1",
- "include_mute_edge": "1",
- "include_can_dm": "1",
- "include_can_media_tag": "1",
- "include_ext_has_nft_avatar": "1",
- "include_ext_is_blue_verified": "1",
- "include_ext_verified_type": "1",
- "skip_status": "1",
-}
-
-account_search_settings = {
- "optInFiltering": True, # filter out nsfw content
- "optInBlocking": True, # filter out blocked accounts
-}
-
-profile_settings = {
- "birthdate_day": int,
- "birthdate_month": int,
- "birthdate_year": int, # 1985
- "birthdate_visibility": str, # 'self',
- "birthdate_year_visibility": str, # 'self',
- "displayNameMaxLength": int, # '50',
- "url": str, # 'https://example.com',
- "name": str, # 'foo',
- "description": str, # 'bar',
- "location": str, # 'world',
-}
-
-search_config = {
- "include_profile_interstitial_type": 1,
- "include_blocking": 1,
- "include_blocked_by": 1,
- "include_followed_by": 1,
- "include_want_retweets": 1,
- "include_mute_edge": 1,
- "include_can_dm": 1,
- "include_can_media_tag": 1,
- "include_ext_has_nft_avatar": 1,
- "include_ext_is_blue_verified": 1,
- "include_ext_verified_type": 1,
- "skip_status": 1,
- "cards_platform": "Web-12",
- "include_cards": 1,
- "include_ext_alt_text": "true",
- "include_ext_limited_action_results": "false",
- "include_quote_count": "true",
- "include_reply_count": 1,
- "tweet_mode": "extended",
- "include_ext_collab_control": "true",
- "include_ext_views": "true",
- "include_entities": "true",
- "include_user_entities": "true",
- "include_ext_media_color": "true",
- "include_ext_media_availability": "true",
- "include_ext_sensitive_media_warning": "true",
- "include_ext_trusted_friends_metadata": "true",
- "send_error_codes": "true",
- "simple_quoted_tweet": "true",
- "query_source": "typed_query",
- "count": 1000,
- "q": "",
- "requestContext": "launch",
- "pc": 1,
- "spelling_corrections": 1,
- "include_ext_edit_control": "true",
- "ext": "mediaStats,highlightedLabel,hasNftAvatar,voiceInfo,birdwatchPivot,enrichments,superFollowMetadata,unmentionInfo,editControl,collab_control,vibe",
-}
-
-dm_params = {
- "context": "FETCH_DM_CONVERSATION",
- "include_profile_interstitial_type": "1",
- "include_blocking": "1",
- "include_blocked_by": "1",
- "include_followed_by": "1",
- "include_want_retweets": "1",
- "include_mute_edge": "1",
- "include_can_dm": "1",
- "include_can_media_tag": "1",
- "include_ext_has_nft_avatar": "1",
- "include_ext_is_blue_verified": "1",
- "include_ext_verified_type": "1",
- "include_ext_profile_image_shape": "1",
- "skip_status": "1",
- "dm_secret_conversations_enabled": "false",
- "krs_registration_enabled": "true",
- "cards_platform": "Web-12",
- "include_cards": "1",
- "include_ext_alt_text": "true",
- "include_ext_limited_action_results": "false",
- "include_quote_count": "true",
- "include_reply_count": "1",
- "tweet_mode": "extended",
- "include_ext_views": "true",
- "dm_users": "false",
- "include_groups": "true",
- "include_inbox_timelines": "true",
- "include_ext_media_color": "true",
- "supports_reactions": "true",
- "include_conversation_info": "true",
- "ext": "mediaColor,altText,mediaStats,highlightedLabel,hasNftAvatar,voiceInfo,birdwatchPivot,superFollowMetadata,unmentionInfo,editControl",
-}
-
-live_notification_params = params = {
- "cards_platform": "Web-12",
- "count": "50", # max value
- "ext": "mediaStats,highlightedLabel,hasNftAvatar,voiceInfo,birdwatchPivot,superFollowMetadata,unmentionInfo,editControl",
- "include_blocked_by": "1",
- "include_blocking": "1",
- "include_can_dm": "1",
- "include_can_media_tag": "1",
- "include_cards": "1",
- "include_entities": "true",
- "include_ext_alt_text": "true",
- "include_ext_has_nft_avatar": "1",
- "include_ext_is_blue_verified": "1",
- "include_ext_limited_action_results": "true",
- "include_ext_media_availability": "true",
- "include_ext_media_color": "true",
- "include_ext_profile_image_shape": "1",
- "include_ext_sensitive_media_warning": "true",
- "include_ext_trusted_friends_metadata": "true",
- "include_ext_verified_type": "1",
- "include_ext_views": "true",
- "include_followed_by": "1",
- "include_mute_edge": "1",
- "include_profile_interstitial_type": "1",
- "include_quote_count": "true",
- "include_reply_count": "1",
- "include_user_entities": "true",
- "include_want_retweets": "1",
- "send_error_codes": "true",
- "simple_quoted_tweet": "true",
- "skip_status": "1",
- "tweet_mode": "extended",
-}
-
-recommendations_params = {
- "include_profile_interstitial_type": "1",
- "include_blocking": "1",
- "include_blocked_by": "1",
- "include_followed_by": "1",
- "include_want_retweets": "1",
- "include_mute_edge": "1",
- "include_can_dm": "1",
- "include_can_media_tag": "1",
- "include_ext_has_nft_avatar": "1",
- "include_ext_is_blue_verified": "1",
- "include_ext_verified_type": "1",
- "include_ext_profile_image_shape": "1",
- "skip_status": "1",
- "pc": "true",
- "display_location": "profile_accounts_sidebar",
- "limit": 100,
- "ext": "mediaStats,highlightedLabel,hasNftAvatar,voiceInfo,birdwatchPivot,superFollowMetadata,unmentionInfo,editControl",
-}
diff --git a/twitter_api/errors.py b/twitter_api/errors.py
deleted file mode 100644
index 164289e..0000000
--- a/twitter_api/errors.py
+++ /dev/null
@@ -1,88 +0,0 @@
-class TwitterError(Exception):
- """Base class for Twitter errors"""
-
- def __init__(self, error_dict: dict):
- self.error_dict = error_dict
-
- @property
- def error_message(self) -> str:
- if self.error_code == 32:
- return "Failed to authenticate account. Check your credentials."
-
- elif self.error_code == 36:
- return "You cannot use your own user ID to report spam call"
-
- elif self.error_code == 38:
- return "The request is missing the parameter (such as media, text, etc.) in the request."
-
- elif self.error_code == 50:
- return "User not found."
-
- elif self.error_code == 89:
- return "The access token used in the request is incorrect or has expired."
-
- elif self.error_code == 92:
- return "SSL is required. Only TLS v1.2 connections are allowed in the API. Update the request to a secure connection."
-
- elif self.error_code == 139:
- return "You have already favorited this tweet. (Duplicate)"
-
- elif self.error_code == 160:
- return "You've already requested to follow the user. (Duplicate)"
-
- elif self.error_code == 186:
- return "Tweet needs to be a bit shorter. The text is too long."
-
- elif self.error_code == 187:
- return "Text of your tweet is identical to another tweet. Change your text. (Duplicate)"
-
- elif self.error_code == 205:
- return "The account limit for reporting spam has been reached. Try again later."
-
- elif self.error_code == 214:
- return "Account is not set up to have open Direct Messages when trying to set up a welcome message."
-
- elif self.error_code == 220:
- return "The authentication token in use is restricted and cannot access the requested resource."
-
- elif self.error_code == 323:
- return "Only one animated GIF may be attached to a single Post."
-
- elif self.error_code == 325:
- return "The media ID attached to the Post was not found."
-
- elif self.error_code == 327:
- return "You cannot repost the same Post more than once."
-
- elif self.error_code == 349:
- return "You does not have privileges to Direct Message the recipient."
-
- return self.error_dict.get("error_message")
-
- @property
- def error_code(self) -> int:
- return self.error_dict.get("error_code")
-
-
-class TwitterAccountSuspended(Exception):
- """Raised when account is suspended"""
-
- pass
-
-
-class CaptchaError(Exception):
- """Raised when captcha solving failed"""
-
- pass
-
-
-class RateLimitError(Exception):
- """Raised when rate limit exceeded"""
-
- pass
-
-
-class IncorrectData(Exception):
- """Raised when validation error"""
-
- pass
diff --git a/twitter_api/models/__init__.py b/twitter_api/models/__init__.py
deleted file mode 100644
index e80df5c..0000000
--- a/twitter_api/models/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from .tweets import *
-from .users import *
-from .data import *
diff --git a/twitter_api/models/data/__init__.py b/twitter_api/models/data/__init__.py
deleted file mode 100644
index f3e0a47..0000000
--- a/twitter_api/models/data/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from .bind_account_v2 import *
-from .bind_account_v1 import *
diff --git a/twitter_api/models/data/bind_account_v1.py b/twitter_api/models/data/bind_account_v1.py
deleted file mode 100644
index ad86ea7..0000000
--- a/twitter_api/models/data/bind_account_v1.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from pydantic import BaseModel, field_validator, HttpUrl
-
-
-class BindAccountParamsV1(BaseModel):
- url: HttpUrl
-
-
-class BindAccountDataV1(BaseModel):
- url: HttpUrl
- oauth_token: str
- oauth_verifier: str
diff --git a/twitter_api/models/data/bind_account_v2.py b/twitter_api/models/data/bind_account_v2.py
deleted file mode 100644
index 81c9c5a..0000000
--- a/twitter_api/models/data/bind_account_v2.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from pydantic import BaseModel, field_validator, HttpUrl
-
-
-class BindAccountParamsV2(BaseModel):
- code_challenge: str
- code_challenge_method: str = "plain"
- client_id: str
- redirect_uri: HttpUrl
- response_type: str = "code"
- scope: str = "tweet.read users.read follows.read offline.access"
- state: str
-
- @field_validator("redirect_uri", mode="after")
- def validate_uri(cls, value):
- # url = HttpUrl("https://google.com")
- return str(value)
-
-
-class BindAccountDataV2(BaseModel):
- code: str
diff --git a/twitter_api/models/tweets/__init__.py b/twitter_api/models/tweets/__init__.py
deleted file mode 100644
index 1e869f4..0000000
--- a/twitter_api/models/tweets/__init__.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from .create_tweet import *
-from .delete_tweet import *
-from .retweet import *
-from .favorite_tweet import *
-from .delete_retweet import *
-from .delete_favorite_tweet import *
-from .bookmark_tweet import *
-from .unbookmark_tweet import *
-from .create_reply import *
-from .scrape_replies import *
-from .scrape_favorites import *
-from .scrape_retweets import *
-from .create_schedule_tweet import *
-from .delete_unschedule_tweet import *
diff --git a/twitter_api/models/tweets/bookmark_tweet.py b/twitter_api/models/tweets/bookmark_tweet.py
deleted file mode 100644
index ee8118c..0000000
--- a/twitter_api/models/tweets/bookmark_tweet.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from pydantic import BaseModel
-from typing import Optional, Dict
-
-
-class CreateBookmarkData(BaseModel):
- id: str | int
-
-
-class CreateBookmarkResult(BaseModel):
- tweet_bookmark_put: Optional[str]
-
-
-class CreateBookmarkResultData(BaseModel):
- data: Optional[CreateBookmarkResult]
diff --git a/twitter_api/models/tweets/create_reply.py b/twitter_api/models/tweets/create_reply.py
deleted file mode 100644
index b502da5..0000000
--- a/twitter_api/models/tweets/create_reply.py
+++ /dev/null
@@ -1,150 +0,0 @@
-from pydantic import BaseModel
-from typing import Optional, Dict, List, Any
-
-from .create_tweet import MediaEntity
-
-
-class CreateReplyData(BaseModel):
- id: str | int
- text: str
- media_entities: List[MediaEntity] | None = None
-
-
-class Legacy(BaseModel):
- can_dm: Optional[bool]
- can_media_tag: Optional[bool]
- created_at: Optional[str]
- default_profile: Optional[bool]
- default_profile_image: Optional[bool]
- description: Optional[str]
- entities: Optional[Dict[str, Any]]
- fast_followers_count: Optional[int]
- favourites_count: Optional[int]
- followers_count: Optional[int]
- friends_count: Optional[int]
- has_custom_timelines: Optional[bool]
- is_translator: Optional[bool]
- listed_count: Optional[int]
- location: Optional[str]
- media_count: Optional[int]
- name: Optional[str]
- needs_phone_verification: Optional[bool]
- normal_followers_count: Optional[int]
- pinned_tweet_ids_str: Optional[List[str]]
- possibly_sensitive: Optional[bool]
- profile_image_url_https: Optional[str]
- profile_interstitial_type: Optional[str]
- screen_name: Optional[str]
- statuses_count: Optional[int]
- translator_type: Optional[str]
- verified: Optional[bool]
- want_retweets: Optional[bool]
- withheld_in_countries: Optional[List[str]]
-
-
-class UserResults(BaseModel):
- __typename: Optional[str]
- id: Optional[str]
- rest_id: Optional[str]
- affiliates_highlighted_label: Optional[Dict[str, Any]]
- has_graduated_access: Optional[bool]
- is_blue_verified: Optional[bool]
- profile_image_shape: Optional[str]
- legacy: Optional[Legacy]
- smart_blocked_by: Optional[bool]
- smart_blocking: Optional[bool]
-
-
-class CoreUserResult(BaseModel):
- result: Optional[UserResults]
-
-
-class Core(BaseModel):
- user_results: Optional[CoreUserResult]
-
-
-class Views(BaseModel):
- state: Optional[str]
-
-
-class EditControl(BaseModel):
- edit_tweet_ids: Optional[List[str]]
- editable_until_msecs: Optional[str]
- is_edit_eligible: Optional[bool]
- edits_remaining: Optional[str]
-
-
-class Media(BaseModel):
- display_url: Optional[str]
- expanded_url: Optional[str]
- id_str: Optional[str]
- indices: Optional[List[int]]
- media_url_https: Optional[str]
- type: Optional[str]
- url: Optional[str]
- features: Optional[Dict[str, Any]]
- sizes: Optional[Dict[str, Any]]
- original_info: Optional[Dict[str, int]]
-
-
-class Entities(BaseModel):
- user_mentions: Optional[List[Dict[str, Any]]]
- urls: Optional[List[Any]]
- hashtags: Optional[List[Any]]
- symbols: Optional[List[Any]]
-
-
-class ExtendedEntities(BaseModel):
- media: Optional[List[Media]]
-
-
-class Legacy2(BaseModel):
- bookmark_count: Optional[int]
- bookmarked: Optional[bool]
- created_at: Optional[str]
- conversation_id_str: Optional[str]
- entities: Optional[Entities]
- favorite_count: Optional[int]
- favorited: Optional[bool]
- full_text: Optional[str]
- in_reply_to_screen_name: Optional[str]
- in_reply_to_status_id_str: Optional[str]
- in_reply_to_user_id_str: Optional[str]
- is_quote_status: Optional[bool]
- lang: Optional[str]
- quote_count: Optional[int]
- reply_count: Optional[int]
- retweet_count: Optional[int]
- retweeted: Optional[bool]
- user_id_str: Optional[str]
- id_str: Optional[str]
-
-
-class UnmentionInfo(BaseModel):
- pass
-
-
-class CreateReplyResult(BaseModel):
- rest_id: Optional[str]
- has_birdwatch_notes: Optional[bool]
- core: Optional[Core]
- is_translatable: Optional[bool]
- views: Optional[Views]
- source: Optional[str]
- legacy: Optional[Legacy2]
-
-
-class CreateReplyResultDataV3(BaseModel):
- result: Optional[CreateReplyResult]
-
-
-class CreateReplyResultDataV2(BaseModel):
- tweet_results: Optional[CreateReplyResultDataV3]
-
-
-class CreateReplyResultDataV1(BaseModel):
- create_tweet: Optional[CreateReplyResultDataV2]
-
-
-class CreateReplyResultData(BaseModel):
- data: Optional[CreateReplyResultDataV1]
diff --git a/twitter_api/models/tweets/create_schedule_tweet.py b/twitter_api/models/tweets/create_schedule_tweet.py
deleted file mode 100644
index 8e25478..0000000
--- a/twitter_api/models/tweets/create_schedule_tweet.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from typing import List, Optional
-from pydantic import BaseModel
-
-from .create_tweet import MediaEntity
-
-
-class CreateScheduleTweetData(BaseModel):
- text: str
- date: int | str
- media_entities: List[MediaEntity] | None = None
-
-
-class CreateScheduleTweetResult(BaseModel):
- rest_id: str
-
-
-class CreateScheduleTweetResultDataV1(BaseModel):
- tweet: Optional[CreateScheduleTweetResult]
-
-
-class CreateScheduleTweetResultData(BaseModel):
- data: Optional[CreateScheduleTweetResultDataV1]
diff --git a/twitter_api/models/tweets/create_tweet.py b/twitter_api/models/tweets/create_tweet.py
deleted file mode 100644
index decd5e3..0000000
--- a/twitter_api/models/tweets/create_tweet.py
+++ /dev/null
@@ -1,156 +0,0 @@
-from typing import List, Optional, Any, Dict
-
-from pydantic import BaseModel, field_validator
-from twitter_api.errors import IncorrectData
-
-
-class MediaEntity(BaseModel):
- media_id: int
- tagged_users: List[str] | None = []
-
- @field_validator("tagged_users")
- @classmethod
- def validate_users(cls, users: List[str]):
- if users:
- if len(users) > 10:
- raise IncorrectData("Maximum 10 tagged users allowed")
-
- return users
-
-
-class CreateTweetData(BaseModel):
- text: str
- media_entities: List[MediaEntity] | None = None
-
-
-class Legacy(BaseModel):
- can_dm: Optional[bool]
- can_media_tag: Optional[bool]
- created_at: Optional[str]
- default_profile: Optional[bool]
- default_profile_image: Optional[bool]
- description: Optional[str]
- entities: Optional[Dict[str, Any]]
- fast_followers_count: Optional[int]
- favourites_count: Optional[int]
- followers_count: Optional[int]
- friends_count: Optional[int]
- has_custom_timelines: Optional[bool]
- is_translator: Optional[bool]
- listed_count: Optional[int]
- location: Optional[str]
- media_count: Optional[int]
- name: Optional[str]
- needs_phone_verification: Optional[bool]
- normal_followers_count: Optional[int]
- pinned_tweet_ids_str: Optional[List[str]]
- possibly_sensitive: Optional[bool]
- profile_image_url_https: Optional[str]
- profile_interstitial_type: Optional[str]
- screen_name: Optional[str]
- statuses_count: Optional[int]
- translator_type: Optional[str]
- verified: Optional[bool]
- want_retweets: Optional[bool]
- withheld_in_countries: Optional[List[str]]
-
-
-class UserResult(BaseModel):
- __typename: Optional[str]
- id: Optional[str]
- rest_id: Optional[str]
- affiliates_highlighted_label: Optional[Dict[str, Any]]
- has_graduated_access: Optional[bool]
- is_blue_verified: Optional[bool]
- profile_image_shape: Optional[str]
- legacy: Optional[Legacy]
- smart_blocked_by: Optional[bool]
- smart_blocking: Optional[bool]
-
-
-class Result(BaseModel):
- result: Optional[UserResult]
-
-
-class Core(BaseModel):
- user_results: Optional[Result]
-
-
-class Views(BaseModel):
- state: Optional[str]
-
-
-class Entities(BaseModel):
- user_mentions: Optional[List[Any]]
- urls: Optional[List[Any]]
- hashtags: Optional[List[Any]]
- symbols: Optional[List[Any]]
-
-
-class Legacy2(BaseModel):
- bookmark_count: Optional[int]
- bookmarked: Optional[bool]
- created_at: Optional[str]
- conversation_id_str: Optional[str]
- display_text_range: Optional[List[int]]
- entities: Optional[Entities]
- favorite_count: Optional[int]
- favorited: Optional[bool]
- full_text: Optional[str]
- is_quote_status: Optional[bool]
- lang: Optional[str]
- quote_count: Optional[int]
- reply_count: Optional[int]
- retweet_count: Optional[int]
- retweeted: Optional[bool]
- user_id_str: Optional[str]
- id_str: Optional[str]
-
-
-class EditControl(BaseModel):
- edit_tweet_ids: Optional[List[str]]
- editable_until_msecs: Optional[str]
- is_edit_eligible: Optional[bool]
- edits_remaining: Optional[str]
-
-
-class QuickPromoteEligibility(BaseModel):
- eligibility: Optional[str]
-
-
-class UnmentionData(BaseModel):
- pass
-
-
-class UnmentionInfo(BaseModel):
- pass
-
-
-class CreateTweetResult(BaseModel):
- rest_id: Optional[str]
- has_birdwatch_notes: Optional[bool]
- core: Optional[Core]
- unmention_data: Optional[UnmentionData]
- edit_control: Optional[EditControl]
- is_translatable: Optional[bool]
- views: Optional[Views]
- source: Optional[str]
- legacy: Optional[Legacy2]
- quick_promote_eligibility: Optional[QuickPromoteEligibility]
- unmention_info: Optional[UnmentionInfo]
-
-
-class CreateTweetResultDataV3(BaseModel):
- result: Optional[CreateTweetResult]
-
-
-class CreateTweetResultDataV2(BaseModel):
- tweet_results: Optional[CreateTweetResultDataV3]
-
-
-class CreateTweetResultDataV1(BaseModel):
- create_tweet: Optional[CreateTweetResultDataV2]
-
-
-class CreateTweetResultData(BaseModel):
- data: Optional[CreateTweetResultDataV1]
diff --git a/twitter_api/models/tweets/delete_favorite_tweet.py b/twitter_api/models/tweets/delete_favorite_tweet.py
deleted file mode 100644
index ca941f1..0000000
--- a/twitter_api/models/tweets/delete_favorite_tweet.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from pydantic import BaseModel
-from typing import Optional
-
-
-class DeleteFavoriteTweetData(BaseModel):
- id: int | str
-
-
-class DeleteFavoriteTweetResult(BaseModel):
- unfavorite_tweet: Optional[str]
-
-
-class DeleteFavoriteTweetResultData(BaseModel):
- data: Optional[DeleteFavoriteTweetResult]
diff --git a/twitter_api/models/tweets/delete_retweet.py b/twitter_api/models/tweets/delete_retweet.py
deleted file mode 100644
index 57b4268..0000000
--- a/twitter_api/models/tweets/delete_retweet.py
+++ /dev/null
@@ -1,31 +0,0 @@
-from pydantic import BaseModel
-from typing import Optional
-
-
-class DeleteRetweetData(BaseModel):
- id: int | str
-
-
-class Legacy(BaseModel):
- full_text: Optional[str]
-
-
-class DeleteRetweetResult(BaseModel):
- rest_id: Optional[str]
- legacy: Optional[Legacy]
-
-
-class DeleteRetweetResultDataV3(BaseModel):
- result: Optional[DeleteRetweetResult]
-
-
-class DeleteRetweetResultDataV2(BaseModel):
- source_tweet_results: Optional[DeleteRetweetResultDataV3]
-
-
-class DeleteRetweetResultDataV1(BaseModel):
- unretweet: Optional[DeleteRetweetResultDataV2]
-
-
-class DeleteRetweetResultData(BaseModel):
- data: Optional[DeleteRetweetResultDataV1]
diff --git a/twitter_api/models/tweets/delete_tweet.py b/twitter_api/models/tweets/delete_tweet.py
deleted file mode 100644
index 4696fc5..0000000
--- a/twitter_api/models/tweets/delete_tweet.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from pydantic import BaseModel
-
-
-class DeleteTweetData(BaseModel):
- id: int | str
-
-
-class DeleteTweetResult(BaseModel):
- pass
-
-
-class DeleteTweetResultDataV2(BaseModel):
- tweet_results: DeleteTweetResult
-
-
-class DeleteTweetResultDataV1(BaseModel):
- delete_tweet: DeleteTweetResultDataV2
-
-
-class DeleteTweetResultData(BaseModel):
- data: DeleteTweetResultDataV1
diff --git a/twitter_api/models/tweets/delete_unschedule_tweet.py b/twitter_api/models/tweets/delete_unschedule_tweet.py
deleted file mode 100644
index 7e3d7af..0000000
--- a/twitter_api/models/tweets/delete_unschedule_tweet.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from typing import Optional
-
-from pydantic import BaseModel
-
-
-class DeleteScheduleTweetData(BaseModel):
- id: str | int
-
-
-class DeleteScheduleTweetResult(BaseModel):
- scheduledtweet_delete: Optional[str]
-
-
-class DeleteScheduleTweetResultData(BaseModel):
- data: Optional[DeleteScheduleTweetResult]
diff --git a/twitter_api/models/tweets/favorite_tweet.py b/twitter_api/models/tweets/favorite_tweet.py
deleted file mode 100644
index 30d6d53..0000000
--- a/twitter_api/models/tweets/favorite_tweet.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from pydantic import BaseModel
-from typing import Optional
-
-
-class CreateFavoriteTweetData(BaseModel):
- id: int | str
-
-
-class FavoriteTweetResult(BaseModel):
- favorite_tweet: Optional[str]
-
-
-class FavoriteTweetResultData(BaseModel):
- data: Optional[FavoriteTweetResult]
diff --git a/twitter_api/models/tweets/retweet.py b/twitter_api/models/tweets/retweet.py
deleted file mode 100644
index 3f7bb55..0000000
--- a/twitter_api/models/tweets/retweet.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from typing import Optional
-
-from pydantic import BaseModel
-
-
-class CreateRetweetData(BaseModel):
- id: int | str
-
-
-class Legacy(BaseModel):
- full_text: Optional[str]
-
-
-class RetweetResult(BaseModel):
- rest_id: Optional[str]
- legacy: Optional[Legacy]
-
-
-class RetweetResultDataV3(BaseModel):
- result: Optional[RetweetResult]
-
-
-class RetweetResultDataV2(BaseModel):
- retweet_results: Optional[RetweetResultDataV3]
-
-
-class RetweetResultDataV1(BaseModel):
- create_retweet: Optional[RetweetResultDataV2]
-
-
-class RetweetResultData(BaseModel):
- data: Optional[RetweetResultDataV1]
diff --git a/twitter_api/models/tweets/scrape_favorites.py b/twitter_api/models/tweets/scrape_favorites.py
deleted file mode 100644
index 36d1b84..0000000
--- a/twitter_api/models/tweets/scrape_favorites.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from pydantic import BaseModel, field_validator
-from twitter_api.errors import IncorrectData
-
-
-class ScrapeTweetFavoritesData(BaseModel):
- id: int | str
- limit: int = 200
-
- @field_validator("limit")
- @classmethod
- def limit_must_be_positive(cls, v):
- if v < 0:
- raise IncorrectData("Limit must be positive integer")
-
- return v
-
-
-class UserData(BaseModel):
- id: int | str
- name: str
- screen_name: str
- profile_image_url: str
- favourites_count: int
- followers_count: int
- friends_count: int
- location: str
- description: str
- created_at: str
-
-
-class ScrapeTweetFavoritesResult(BaseModel):
- users: list[UserData]
diff --git a/twitter_api/models/tweets/scrape_replies.py b/twitter_api/models/tweets/scrape_replies.py
deleted file mode 100644
index e8d7254..0000000
--- a/twitter_api/models/tweets/scrape_replies.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from pydantic import BaseModel, field_validator
-from twitter_api.errors import IncorrectData
-
-
-class ScrapeTweetRepliesData(BaseModel):
- id: int | str
- limit: int = 200
-
- @field_validator("limit")
- @classmethod
- def limit_must_be_positive(cls, v):
- if v < 0:
- raise IncorrectData("Limit must be positive integer")
-
- return v
-
-
-class UserData(BaseModel):
- id: int | str
- name: str
- screen_name: str
- profile_image_url: str
- favourites_count: int
- followers_count: int
- friends_count: int
- location: str
- description: str
- created_at: str
-
-
-class ScrapeTweetRepliesResult(BaseModel):
- reply_text: str
- user_data: UserData
-
-
-class ScrapeTweetRepliesResultData(BaseModel):
- replies: list[ScrapeTweetRepliesResult]
diff --git a/twitter_api/models/tweets/scrape_retweets.py b/twitter_api/models/tweets/scrape_retweets.py
deleted file mode 100644
index 897a0e7..0000000
--- a/twitter_api/models/tweets/scrape_retweets.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from pydantic import BaseModel, field_validator
-from twitter_api.errors import IncorrectData
-from .scrape_favorites import UserData
-
-
-class ScrapeTweetRetweetsData(BaseModel):
- id: int | str
- limit: int = 200
-
- @field_validator("limit")
- @classmethod
- def limit_must_be_positive(cls, v):
- if v < 0:
- raise IncorrectData("Limit must be positive integer")
-
- return v
-
-
-class ScrapeTweetRetweetsResult(BaseModel):
- users: list[UserData]
diff --git a/twitter_api/models/tweets/unbookmark_tweet.py b/twitter_api/models/tweets/unbookmark_tweet.py
deleted file mode 100644
index c4425a5..0000000
--- a/twitter_api/models/tweets/unbookmark_tweet.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from pydantic import BaseModel
-from typing import Optional, Dict
-
-
-class DeleteBookmarkData(BaseModel):
- id: str | int
-
-
-class DeleteBookmarkResult(BaseModel):
- tweet_bookmark_delete: Optional[str]
-
-
-class DeleteBookmarkResultData(BaseModel):
- data: Optional[DeleteBookmarkResult]
diff --git a/twitter_api/models/users/__init__.py b/twitter_api/models/users/__init__.py
deleted file mode 100644
index 4edec9c..0000000
--- a/twitter_api/models/users/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from .follows import *
-from .user_info import *
-from .followers import *
diff --git a/twitter_api/models/users/followers.py b/twitter_api/models/users/followers.py
deleted file mode 100644
index def57ed..0000000
--- a/twitter_api/models/users/followers.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from pydantic import BaseModel, field_validator
-from typing import Optional, List, Dict, Any
-from twitter_api.errors import IncorrectData
-
-
-class UserFollowersData(BaseModel):
- username: str
- limit: int = 200
-
- @field_validator("limit")
- @classmethod
- def limit_must_be_positive(cls, v):
- if v < 0:
- raise IncorrectData("Limit must be positive integer")
-
- return v
diff --git a/twitter_api/models/users/follows.py b/twitter_api/models/users/follows.py
deleted file mode 100644
index bcf448e..0000000
--- a/twitter_api/models/users/follows.py
+++ /dev/null
@@ -1,70 +0,0 @@
-from typing import Optional, List
-
-from pydantic import BaseModel, model_validator
-from twitter_api.errors import IncorrectData
-
-
-class UnfollowUserData(BaseModel):
- id: int | str = None
- username: str = None
-
- @model_validator(mode="before")
- @classmethod
- def validate_data(cls, values: dict):
- if not values.get("id") and not values.get("username"):
- raise IncorrectData("Either id or username must be provided")
-
- return values
-
-
-class FollowUserData(BaseModel):
- id: str | int = None
- username: str = None
-
- @model_validator(mode="before")
- @classmethod
- def validate_data(cls, values: dict):
- if not values.get("id") and not values.get("username"):
- raise IncorrectData("Either id or username must be provided")
-
- return values
-
-
-class FollowsUserResult(BaseModel):
- id: Optional[int]
- id_str: Optional[str]
- name: Optional[str]
- screen_name: Optional[str]
- location: Optional[str]
- description: Optional[str]
- url: Optional[str]
- protected: Optional[bool]
- followers_count: Optional[int]
- fast_followers_count: Optional[int]
- normal_followers_count: Optional[int]
- friends_count: Optional[int]
- listed_count: Optional[int]
- created_at: Optional[str]
- favourites_count: Optional[int]
- utc_offset: Optional[int]
- time_zone: Optional[str]
- geo_enabled: Optional[bool]
- verified: Optional[bool]
- statuses_count: Optional[int]
- media_count: Optional[int]
- lang: Optional[str]
- profile_image_url: Optional[str]
- profile_image_url_https: Optional[str]
- profile_banner_url: Optional[str]
- pinned_tweet_ids: Optional[List[int]]
- pinned_tweet_ids_str: Optional[List[str]]
- has_custom_timelines: Optional[bool]
- can_dm: Optional[bool]
- can_media_tag: Optional[bool]
- following: Optional[bool]
- follow_request_sent: Optional[bool]
- blocking: Optional[bool]
- business_profile_state: Optional[str]
- followed_by: Optional[bool]
- ext_is_blue_verified: Optional[bool]
- ext_has_nft_avatar: Optional[bool]
diff --git a/twitter_api/models/users/user_info.py b/twitter_api/models/users/user_info.py
deleted file mode 100644
index 0e7c4d7..0000000
--- a/twitter_api/models/users/user_info.py
+++ /dev/null
@@ -1,66 +0,0 @@
-from typing import Optional, List, Dict, Any
-from pydantic import BaseModel
-
-
-class UserProfileInfoData(BaseModel):
- username: str
-
-
-class UserProfileInfoResult(BaseModel):
- id: Optional[int]
- id_str: Optional[str]
- name: Optional[str]
- screen_name: Optional[str]
- location: Optional[str]
- profile_location: Optional[Dict[str, Any]]
- description: Optional[str]
- url: Optional[str]
- # entities: Optional[Entities]
- protected: Optional[bool]
- followers_count: Optional[int]
- fast_followers_count: Optional[int]
- normal_followers_count: Optional[int]
- friends_count: Optional[int]
- listed_count: Optional[int]
- created_at: Optional[str]
- favourites_count: Optional[int]
- utc_offset: Optional[int]
- time_zone: Optional[str]
- geo_enabled: Optional[bool]
- verified: Optional[bool]
- statuses_count: Optional[int]
- media_count: Optional[int]
- lang: Optional[str]
- # status: Optional[Status]
- contributors_enabled: Optional[bool]
- is_translator: Optional[bool]
- is_translation_enabled: Optional[bool]
- profile_background_color: Optional[str]
- profile_background_image_url: Optional[str]
- profile_background_image_url_https: Optional[str]
- profile_background_tile: Optional[bool]
- profile_image_url: Optional[str]
- profile_image_url_https: Optional[str]
- profile_banner_url: Optional[str]
- profile_link_color: Optional[str]
- profile_sidebar_border_color: Optional[str]
- profile_sidebar_fill_color: Optional[str]
- profile_text_color: Optional[str]
- profile_use_background_image: Optional[bool]
- has_extended_profile: Optional[bool]
- default_profile: Optional[bool]
- default_profile_image: Optional[bool]
- pinned_tweet_ids: Optional[List[int]]
- pinned_tweet_ids_str: Optional[List[str]]
- has_custom_timelines: Optional[bool]
- can_media_tag: Optional[bool]
- followed_by: Optional[bool]
- following: Optional[bool]
- follow_request_sent: Optional[bool]
- notifications: Optional[bool]
- advertiser_account_type: Optional[str]
- advertiser_account_service_levels: Optional[List[str]]
- business_profile_state: Optional[str]
- translator_type: Optional[str]
- withheld_in_countries: Optional[List[str]]
- require_some_consent: Optional[bool]
diff --git a/twitter_api/requirements.txt b/twitter_api/requirements.txt
deleted file mode 100644
index 260dd0f..0000000
--- a/twitter_api/requirements.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-pydantic
-orjson
-httpx
-curl-cffi
-tqdm
\ No newline at end of file
diff --git a/twitter_api/util.py b/twitter_api/util.py
deleted file mode 100644
index 861f8fc..0000000
--- a/twitter_api/util.py
+++ /dev/null
@@ -1,296 +0,0 @@
-import random
-import re
-import string
-import time
-import orjson
-
-from logging import Logger
-from pathlib import Path
-from urllib.parse import urlsplit, urlencode, urlunsplit, parse_qs, quote
-from httpx import Response, Client
-
-from .constants import GREEN, MAGENTA, RED, RESET, ID_MAP
-from .errors import TwitterError
-
-
-def init_session():
- client = Client(
- headers={
- "authorization": "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs=1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA",
- "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36",
- },
- follow_redirects=True,
- )
- r = client.post("https://api.twitter.com/1.1/guest/activate.json").json()
- client.headers.update(
- {
- "content-type": "application/json",
- "x-guest-token": r["guest_token"],
- "x-twitter-active-user": "yes",
- }
- )
- return client
-
-
-def batch_ids(ids: list[int], char_limit: int = 4_500) -> list[dict]:
- """To avoid 431 errors"""
- length = 0
- res, batch = [], []
- for x in map(str, ids):
- curr_length = len(x)
- if length + curr_length > char_limit:
- res.append(batch)
- batch = []
- length = 0
- batch.append(x)
- length += curr_length
- if batch:
- res.append(batch)
- return res
-
-
-def build_params(params: dict) -> dict:
- return {k: orjson.dumps(v).decode() for k, v in params.items()}
-
-
-def save_json(r: Response, path: Path, name: str, **kwargs):
- try:
- data = r.json()
- kwargs.pop("cursor", None)
- out = path / "_".join(map(str, kwargs.values()))
- out.mkdir(parents=True, exist_ok=True)
- (out / f"{time.time_ns()}_{name}.json").write_bytes(orjson.dumps(data))
- except Exception as e:
- print(f"Failed to save data: {e}")
-
-
-def flatten(seq: list | tuple) -> list:
- flat = []
- for e in seq:
- if isinstance(e, list | tuple):
- flat.extend(flatten(e))
- else:
- flat.append(e)
- return flat
-
-
-def get_json(res: list[Response], **kwargs) -> list:
- cursor = kwargs.get("cursor")
- temp = res
- if any(isinstance(r, (list, tuple)) for r in res):
- temp = flatten(res)
- results = []
- for r in temp:
- try:
- data = r.json()
- if cursor:
- results.append([data, cursor])
- else:
- results.append(data)
- except Exception as e:
- print("Cannot parse JSON response", e)
- return results
-
-
-def set_qs(url: str, qs: dict, update=False, **kwargs) -> str:
- *_, q, f = urlsplit(url)
- return urlunsplit(
- (
- *_,
- urlencode(
- qs | parse_qs(q) if update else qs,
- doseq=True,
- quote_via=quote,
- safe=kwargs.get("safe", ""),
- ),
- f,
- )
- )
-
-
-def get_cursor(data: list | dict) -> str:
- # inefficient, but need to deal with arbitrary schema
- entries = find_key(data, "entries")
- if entries:
- for entry in entries.pop():
- entry_id = entry.get("entryId", "")
- if ("cursor-bottom" in entry_id) or ("cursor-showmorethreads" in entry_id):
- content = entry["content"]
- if itemContent := content.get("itemContent"):
- return itemContent["value"] # v2 cursor
- return content["value"] # v1 cursor
-
-
-def get_headers(session, **kwargs) -> dict:
- """
- Get the headers required for authenticated requests
- """
- cookies = session.cookies
- headers = kwargs | {
- "authorization": "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs=1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA",
- # "cookie": "; ".join(f"{k}={v}" for k, v in cookies.items()),
- "referer": "https://twitter.com/",
- "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36",
- "x-csrf-token": cookies.get("ct0", ""),
- # "x-guest-token": cookies.get("guest_token", ""),
- "x-twitter-auth-type": "OAuth2Session" if cookies.get("auth_token") else "",
- "x-twitter-active-user": "yes",
- "x-twitter-client-language": "en",
- }
- return dict(sorted({k.lower(): v for k, v in headers.items()}.items()))
-
-
-def find_key(obj: any, key: str) -> list:
- """
- Find all values of a given key within a nested dict or list of dicts
-
- Most data of interest is nested, and sometimes defined by different schemas.
- It is not worth our time to enumerate all absolute paths to a given key, then update
- the paths in our parsing functions every time Twitter changes their API.
- Instead, we recursively search for the key here, then run post-processing functions on the results.
-
- @param obj: dictionary or list of dictionaries
- @param key: key to search for
- @return: list of values
- """
-
- def helper(obj: any, key: str, L: list) -> list:
- if not obj:
- return L
-
- if isinstance(obj, list):
- for e in obj:
- L.extend(helper(e, key, []))
- return L
-
- if isinstance(obj, dict) and obj.get(key):
- L.append(obj[key])
-
- if isinstance(obj, dict) and obj:
- for k in obj:
- L.extend(helper(obj[k], key, []))
- return L
-
- return helper(obj, key, [])
-
-
-def log(logger: Logger, level: int, r: Response):
- def stat(r, txt, data):
- if level >= 1:
- logger.debug(f"{r.url.path}")
- if level >= 2:
- logger.debug(f"{r.url}")
- if level >= 3:
- logger.debug(f"{txt}")
- if level >= 4:
- logger.debug(f"{data}")
-
- try:
- limits = {k: v for k, v in r.headers.items() if "x-rate-limit" in k}
- current_time = int(time.time())
- wait = int(r.headers.get("x-rate-limit-reset", current_time)) - current_time
- remaining = limits.get("x-rate-limit-remaining")
- limit = limits.get("x-rate-limit-limit")
- logger.debug(f"remaining: {MAGENTA}{remaining}/{limit}{RESET} requests")
- logger.debug(f"reset: {MAGENTA}{(wait / 60):.2f}{RESET} minutes")
- except Exception as e:
- logger.error(f"Rate limit info unavailable: {e}")
-
- try:
- status = r.status_code
- (
- txt,
- data,
- ) = (
- r.text,
- r.json(),
- )
- if "json" in r.headers.get("content-type", ""):
- if data.get("errors") and not find_key(data, "instructions"):
- logger.error(f"[{RED}error{RESET}] {status} {data}")
- else:
- logger.debug(fmt_status(status))
- stat(r, txt, data)
- else:
- logger.debug(fmt_status(status))
- stat(r, txt, {})
- except Exception as e:
- logger.error(f"Failed to log: {e}")
-
-
-def fmt_status(status: int) -> str:
- color = None
- if 200 <= status < 300:
- color = GREEN
- elif 300 <= status < 400:
- color = MAGENTA
- elif 400 <= status < 600:
- color = RED
- return f"[{color}{status}{RESET}]"
-
-
-def get_ids(data: list | dict, operation: tuple) -> set:
- expr = ID_MAP[operation[-1]]
- return {k for k in find_key(data, "entryId") if re.search(expr, k)}
-
-
-def dump(path: str, **kwargs):
- fname, data = list(kwargs.items())[0]
- out = Path(path)
- out.mkdir(exist_ok=True, parents=True)
- (out / f"{fname}_{time.time_ns()}.json").write_bytes(
- orjson.dumps(data, option=orjson.OPT_INDENT_2 | orjson.OPT_SORT_KEYS)
- )
-
-
-def get_code(cls, retries=5) -> str | None:
- """Get verification code from Proton Mail inbox"""
-
- def poll_inbox():
- inbox = cls.inbox()
- for c in inbox.get("Conversations", []):
- if c["Senders"][0]["Address"] == "info@twitter.com":
- exprs = [
- "Your Twitter confirmation code is (.+)",
- "(.+) is your Twitter verification code",
- ]
- if temp := list(
- filter(None, (re.search(expr, c["Subject"]) for expr in exprs))
- ):
- return temp[0].group(1)
-
- for i in range(retries + 1):
- if code := poll_inbox():
- return code
- if i == retries:
- print(f"Max retries exceeded")
- return
- t = 2**i + random.random()
- print(f'Retrying in {f"{t:.2f}"} seconds')
- time.sleep(t)
-
-
-def get_random_string(len_: int) -> str:
- return "".join(
- random.choice(string.ascii_lowercase + string.digits) for _ in range(len_)
- )
-
-
-def get_random_number(len_: int) -> str:
- return "".join(random.choice(string.digits) for _ in range(len_))
-
-
-def generate_random_string() -> str:
- return "".join([random.choice(string.ascii_letters + "-_") for _ in range(352)])
-
-
-def raise_for_status(response):
- http_error_msg = ""
- if 400 <= response.status_code < 500:
- http_error_msg = f"{response.status_code} Client Error for url {response.url}"
-
- elif 500 <= response.status_code < 600:
- http_error_msg = f"{response.status_code} Server Error for url: {response.url}"
-
- if http_error_msg:
- raise TwitterError({"error_message": http_error_msg})
diff --git a/utils/__init__.py b/utils/__init__.py
index 15b6a64..6fb0734 100644
--- a/utils/__init__.py
+++ b/utils/__init__.py
@@ -1 +1,3 @@
-from .main import *
+from .console import *
+from .file_utils import *
+from .load_config import load_config
diff --git a/utils/main.py b/utils/console.py
similarity index 78%
rename from utils/main.py
rename to utils/console.py
index a9002e9..be60554 100644
--- a/utils/main.py
+++ b/utils/console.py
@@ -3,7 +3,7 @@
def show_dev_info():
tprint("JamBit")
- print("\033[36m" + "VERSION: " + "\033[34m" + "1.0" + "\033[34m")
+ print("\033[36m" + "VERSION: " + "\033[34m" + "3.0" + "\033[34m")
print("\033[36m" + "Channel: " + "\033[34m" + "https://t.me/JamBitPY" + "\033[34m")
print(
"\033[36m"
@@ -16,7 +16,7 @@ def show_dev_info():
"\033[36m"
+ "DONATION EVM ADDRESS: "
+ "\033[34m"
- + "0x08e3fdbb830ee591c0533C5E58f937D312b07198"
+ + "0xe23380ae575D990BebB3b81DB2F90Ce7eDbB6dDa"
+ "\033[0m"
)
print()
diff --git a/utils/file_utils.py b/utils/file_utils.py
new file mode 100644
index 0000000..4b20060
--- /dev/null
+++ b/utils/file_utils.py
@@ -0,0 +1,12 @@
+import os
+
+from loguru import logger
+
+
+def export_trees_ids(results: list[tuple[str, str]]):
+ if not os.path.exists("./trees_results"):
+ with open("./config/trees_results.txt", "w") as file:
+ for result in results:
+ file.write(f"{result[0]}:{result[1]}\n")
+
+ logger.success("Trees IDs exported to trees_results.txt")
diff --git a/config/load_config.py b/utils/load_config.py
similarity index 66%
rename from config/load_config.py
rename to utils/load_config.py
index 634775c..3665513 100644
--- a/config/load_config.py
+++ b/utils/load_config.py
@@ -7,7 +7,7 @@
def get_accounts() -> Account:
- accounts_path = os.path.join(os.path.dirname(__file__), "accounts.txt")
+ accounts_path = os.path.join(os.getcwd(), "config", "accounts.txt")
if not os.path.exists(accounts_path):
logger.error(f"File <<{accounts_path}>> does not exist")
exit(1)
@@ -36,7 +36,7 @@ def get_accounts() -> Account:
def load_config() -> Config:
- settings_path = os.path.join(os.path.dirname(__file__), "settings.yaml")
+ settings_path = os.path.join(os.getcwd(), "config", "settings.yaml")
if not os.path.exists(settings_path):
logger.error(f"File <<{settings_path}>> does not exist")
exit(1)
@@ -46,15 +46,19 @@ def load_config() -> Config:
REQUIRED_KEYS = (
"referral_code",
- "eth_rpc_url",
- "sepolia_rpc_url",
+ "mint_rpc_url",
+ "arb_rpc_url",
"threads",
- "min_amount_to_bridge",
- "max_amount_to_bridge",
"min_delay_before_start",
"max_delay_before_start",
"spin_turntable_by_percentage_of_energy",
"shuffle_accounts",
+ "comet_bridge_amount_min",
+ "comet_bridge_amount_max",
+ "comet_bridge_wallet",
+ "mint_random_all_nfts",
+ "delay_between_mint_min",
+ "delay_between_mint_max",
)
for key in REQUIRED_KEYS:
@@ -66,15 +70,4 @@ def load_config() -> Config:
if settings["shuffle_accounts"]:
random.shuffle(accounts)
- return Config(
- accounts=accounts,
- referral_code=settings["referral_code"],
- threads=settings["threads"],
- min_amount_to_bridge=settings["min_amount_to_bridge"],
- max_amount_to_bridge=settings["max_amount_to_bridge"],
- eth_rpc_url=settings["eth_rpc_url"],
- sepolia_rpc_url=settings["sepolia_rpc_url"],
- min_delay_before_start=settings["min_delay_before_start"],
- max_delay_before_start=settings["max_delay_before_start"],
- spin_turntable_by_percentage_of_energy=settings["spin_turntable_by_percentage_of_energy"],
- )
+ return Config(accounts=accounts, **settings)