shadowPaySDK 0.1.0__py3-none-any.whl → 0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,74 +1,85 @@
1
+ import shadowPaySDK
1
2
  from web3 import Web3
2
3
  import json
3
4
  from typing import Union, Optional
4
-
5
- ERC20_ABI = json.loads("""[
6
- {"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"type":"function"},
7
- {"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"type":"function"},
8
- {"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"type":"function"},
9
- {"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"type":"function"},
10
- {"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"type":"function"},
11
- {"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"type":"function"},
12
- {"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"type":"function"},
13
- {"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"type":"function"},
14
- {"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"type":"function"}
15
- ]""")
5
+ from shadowPaySDK.const import __ERC20_ABI__
16
6
 
17
7
 
18
8
  class ERC20Token:
19
- def __init__(self, web3: Web3, token: str, explorer: Optional[str] = None):
20
- self.web3 = web3
9
+ def __init__(self, w3: Optional[Web3] = None, explorer: Optional[str] = None):
10
+ self.web3 = w3
21
11
  self.explorer = explorer
22
- self.address = Web3.to_checksum_address(token)
23
- self.contract = web3.eth.contract(address=self.address, abi=ERC20_ABI)
12
+
13
+ self.address = None
14
+ self.contract = None
15
+
16
+ def set_params(self, token_address: Optional[str] = None, w3:Optional[Web3] = None):
17
+ if w3:
18
+ self.web3 = w3
19
+ if token_address:
20
+ self.address = Web3.to_checksum_address(token_address)
21
+ self.contract = self.web3.eth.contract(address=self.address, abi=__ERC20_ABI__)
22
+
23
+ def _ensure_contract(self):
24
+ if not self.contract:
25
+ raise ValueError("Token address is not set. Use set_params first.")
24
26
 
25
27
  def _format_tx(self, tx_hash: str) -> str:
26
28
  if self.explorer:
27
29
  return f"{self.explorer.rstrip('/')}/tx/{tx_hash}"
28
30
  return tx_hash
29
-
30
-
31
-
31
+ def gen_wallet(self) -> str:
32
+ account = self.web3.eth.account.create()
33
+ return account
32
34
  def get_decimals(self) -> int:
35
+ self._ensure_contract()
36
+
33
37
  return self.contract.functions.decimals().call()
34
38
 
35
39
  def get_symbol(self) -> str:
40
+ self._ensure_contract()
36
41
  return self.contract.functions.symbol().call()
37
42
 
38
43
  def get_balance(self, wallet_address: str) -> float:
39
- raw_balance = self.contract.functions.balanceOf(
40
- Web3.to_checksum_address(wallet_address)
41
- ).call()
42
- return raw_balance / (10 ** self.get_decimals())
43
-
44
+ self._ensure_contract()
45
+ raw = self.contract.functions.balanceOf(Web3.to_checksum_address(wallet_address)).call()
46
+ return raw
44
47
 
45
48
 
46
49
  def allowance(self, owner: str, spender: str) -> float:
50
+ self._ensure_contract()
47
51
  raw = self.contract.functions.allowance(
48
52
  Web3.to_checksum_address(owner),
49
53
  Web3.to_checksum_address(spender)
50
54
  ).call()
51
- return raw / (10 ** self.get_decimals())
55
+ return raw
52
56
 
53
- def ensure_allowance(self, private_key: str, spender: str, amount: float) -> Union[bool, str]:
57
+ def ensure_allowance(self, private_key: str, spender: str, amount, converted_amount: bool = False) -> Union[bool, str]:
58
+ self._ensure_contract()
54
59
  account = self.web3.eth.account.from_key(private_key)
55
- current_allowance = self.allowance(account.address, spender)
56
- if current_allowance >= amount:
60
+ current = self.allowance(account.address, spender)
61
+ if current == amount:
57
62
  return True
58
- return self.approve(private_key, spender, amount)
59
-
63
+ return self.approve(private_key, spender, amount, conveted_amount=converted_amount)
64
+
60
65
  def transfer(self, private_key: str, to: str, amount: float) -> str:
66
+ self._ensure_contract()
61
67
  account = self.web3.eth.account.from_key(private_key)
62
- decimals = self.get_decimals()
63
- value = int(amount * (10 ** decimals))
64
-
68
+
69
+ estimated_gas = self.contract.functions.transfer(
70
+ Web3.to_checksum_address(to),
71
+ amount
72
+ ).estimate_gas({
73
+ 'from': account.address,
74
+ 'gasPrice': self.web3.to_wei('5', 'gwei'),
75
+ })
65
76
  txn = self.contract.functions.transfer(
66
77
  Web3.to_checksum_address(to),
67
- value
78
+ amount
68
79
  ).build_transaction({
69
80
  'from': account.address,
70
81
  'nonce': self.web3.eth.get_transaction_count(account.address),
71
- 'gas': 100_000,
82
+ 'gas': estimated_gas,
72
83
  'gasPrice': self.web3.to_wei('5', 'gwei'),
73
84
  })
74
85
 
@@ -76,27 +87,34 @@ class ERC20Token:
76
87
  tx_hash = self.web3.eth.send_raw_transaction(signed.raw_transaction)
77
88
  return self._format_tx(self.web3.to_hex(tx_hash))
78
89
 
79
- def approve(self, private_key: str, spender: str, amount: float) -> str:
80
- account = self.web3.eth.account.from_key(private_key)
81
- decimals = self.get_decimals()
82
- value = int(amount * (10 ** decimals))
83
-
90
+ def approve(self, spender: str, amount: float,address:Optional[str] = None, private_key: Optional[str] = None, conveted_amount: bool = True) -> str:
91
+
92
+ self._ensure_contract()
93
+ key = private_key
94
+
95
+ if key:
96
+ address = Web3.to_checksum_address(self.web3.eth.account.from_key(key).address)
97
+
98
+ elif self.address:
99
+ address = Web3.to_checksum_address(self.address)
100
+ else:
101
+ raise ValueError("No private key or address provided")
84
102
  txn = self.contract.functions.approve(
85
103
  Web3.to_checksum_address(spender),
86
- value
104
+ amount
87
105
  ).build_transaction({
88
- 'from': account.address,
89
- 'nonce': self.web3.eth.get_transaction_count(account.address),
90
- 'gas': 100_000,
91
- 'gasPrice': self.web3.to_wei('5', 'gwei'),
106
+ 'from': address,
107
+ 'nonce': self.web3.eth.get_transaction_count(address),
108
+ 'gas': 60000,
109
+
110
+ 'gasPrice': self.web3.eth.gas_price,
92
111
  })
112
+
93
113
 
94
- signed = self.web3.eth.account.sign_transaction(txn, private_key)
114
+ signed = self.web3.eth.account.sign_transaction(txn, key)
95
115
  tx_hash = self.web3.eth.send_raw_transaction(signed.raw_transaction)
96
- return self._format_tx(self.web3.to_hex(tx_hash))
97
-
98
-
99
-
100
-
101
-
116
+ tx_receipt = self.web3.eth.wait_for_transaction_receipt(tx_hash)
117
+ if tx_receipt.status != 1:
118
+ raise ValueError(f"aaprove fail.\n {self._format_tx(self.web3.to_hex(tx_hash))}")
119
+ return f"{self._format_tx(self.web3.to_hex(tx_hash))}"
102
120
 
@@ -0,0 +1,225 @@
1
+ import asyncio
2
+ import solana
3
+ from solana.rpc.async_api import AsyncClient, GetTokenAccountsByOwnerResp
4
+ from solders.transaction import Transaction
5
+ from solders.system_program import TransferParams as p
6
+ import spl
7
+ import spl.token
8
+ import spl.token.constants
9
+ from spl.token.instructions import get_associated_token_address, create_associated_token_account, transfer, close_account, TransferParams
10
+ from solders.system_program import transfer as ts
11
+ from solders.system_program import TransferParams as tsf
12
+ from spl.token.constants import TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID
13
+ from solana.rpc.types import TxOpts, TokenAccountOpts
14
+ from solana.rpc.types import TxOpts
15
+ import solders
16
+ from solders.message import Message
17
+
18
+ # from solders.pubkey import Pubkey
19
+ # from solders.keypair import Keypair
20
+ # from solders.signature import Signature
21
+ # from solders.transaction import Transaction
22
+ from spl.token.async_client import AsyncToken
23
+
24
+
25
+ from solana.rpc.commitment import Confirmed
26
+ from solana.rpc.async_api import AsyncClient
27
+ import anchorpy
28
+ from anchorpy import Provider, Wallet, Idl
29
+ from typing import Optional, Union
30
+ import pprint
31
+ import httpx
32
+ import base64
33
+ import re
34
+
35
+
36
+ LAMPORTS_PER_SOL = 1_000_000_000 # 1 SOL = 1,000,000,000 lamports
37
+
38
+ class SOL:
39
+ def __init__(self, rpc_url = "https://api.mainnet-beta.solana.com", KEYPAIR: Optional[Union[str, solders.keypair.Keypair]] = None,TOKEN_MINT: Optional[str] = None):
40
+ self.rpc_url = rpc_url
41
+
42
+ self.client = AsyncClient(rpc_url)
43
+ self.KEYPAIR = None
44
+ self.PROGRAM_ID = TOKEN_PROGRAM_ID # Default to the SPL Token Program ID
45
+ self.TOKEN_MINT = TOKEN_MINT
46
+ self.WRAPED_SOL_ID = spl.token.constants.WRAPPED_SOL_MINT
47
+ if KEYPAIR:
48
+ self.set_keypair(KEYPAIR)
49
+
50
+ def set_keypair(self, KEYPAIR: Union[str, solders.keypair.Keypair]):
51
+ if isinstance(KEYPAIR, str):
52
+ try:
53
+ self.KEYPAIR = solders.keypair.Keypair.from_base58_string(KEYPAIR)
54
+ except Exception as e:
55
+ raise ValueError(f"Invalid Keypair string: {e}")
56
+ elif isinstance(KEYPAIR, solders.keypair.Keypair):
57
+ self.KEYPAIR = KEYPAIR
58
+ else:
59
+ raise ValueError("KEYPAIR must be a Keypair instance or a base58 encoded string.")
60
+
61
+ def set_params(self, rpc_url: Optional[str] = None, KEYPAIR: Optional[Union[str, solders.keypair.Keypair]] = None,TOKEN_MINT: Optional[str] = None):
62
+ if rpc_url:
63
+ self.rpc_url = rpc_url
64
+ self.client = AsyncClient(rpc_url)
65
+ if KEYPAIR:
66
+ self.set_keypair(KEYPAIR)
67
+ if TOKEN_MINT:
68
+ self.TOKEN_MINT = TOKEN_MINT
69
+
70
+ def get_pubkey(self, returnString: Optional[bool] = None):
71
+
72
+
73
+ if self.KEYPAIR:
74
+ pubkey = self.KEYPAIR.pubkey()
75
+ pubkey_str = str(pubkey)
76
+ if returnString:
77
+ return pubkey_str
78
+ return pubkey
79
+
80
+ raise ValueError("Keypair not set")
81
+
82
+ def gen_wallet(self):
83
+ return solders.keypair.Keypair()
84
+ async def get_balance(self):
85
+ resp = await self.client.get_balance(self.get_pubkey())
86
+ lamports = resp.value
87
+ sol_balance = lamports / LAMPORTS_PER_SOL
88
+ return sol_balance
89
+ async def get_token_accounts_by_owner(self,owner_pubkey: Optional[str] = None):
90
+ if not owner_pubkey:
91
+ print("No owner pubkey provided, using the wallet's pubkey.")
92
+ owner_pubkey = self.get_pubkey(returnString=True)
93
+ headers = {
94
+ "Content-Type": "application/json",
95
+ }
96
+ body = {
97
+ "jsonrpc": "2.0",
98
+ "id": 1,
99
+ "method": "getTokenAccountsByOwner",
100
+ "params": [
101
+ str(owner_pubkey),
102
+ {"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"},
103
+ {"encoding": "jsonParsed"}
104
+ ]
105
+ }
106
+ async with httpx.AsyncClient() as client:
107
+ response = await client.post(self.rpc_url, headers=headers, json=body)
108
+ result = response.json()
109
+ accounts = result["result"]["value"]
110
+
111
+ token_data = {}
112
+ for acc in accounts:
113
+ parsed = acc["account"]["data"]["parsed"]["info"]
114
+ mint = parsed["mint"]
115
+ ui_amount = parsed["tokenAmount"]["uiAmount"]
116
+ token_data[mint] = {"amount": ui_amount}
117
+
118
+
119
+
120
+ return token_data
121
+
122
+ async def fetch_metadata_raw(self,mint_address: str):
123
+ METADATA_PROGRAM_ID = solders.pubkey.Pubkey.from_string("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s")
124
+ mint = solders.pubkey.Pubkey.from_string(mint_address)
125
+ seeds = [
126
+ b"metadata",
127
+ bytes(METADATA_PROGRAM_ID),
128
+ bytes(mint),
129
+ ]
130
+ pda, _ = solders.pubkey.Pubkey.find_program_address(seeds, METADATA_PROGRAM_ID)
131
+
132
+ payload = {
133
+ "jsonrpc": "2.0",
134
+ "id": 1,
135
+ "method": "getAccountInfo",
136
+ "params": [
137
+ str(pda),
138
+ {"encoding": "base64"}
139
+ ]
140
+ }
141
+
142
+ async with httpx.AsyncClient() as client:
143
+ r = await client.post(self.rpc_url, json=payload)
144
+ data = r.json()
145
+
146
+ if not data["result"]["value"]:
147
+ return None
148
+
149
+ b64_data = data["result"]["value"]["data"][0]
150
+ raw_bytes = base64.b64decode(b64_data)
151
+
152
+ name = raw_bytes[1+32+32 : 1+32+32+32].decode("utf-8").rstrip("\x00")
153
+ name = re.sub(r'[^\x20-\x7E]', '', name)
154
+ return {
155
+ "mint": mint_address,
156
+ "name": name,
157
+
158
+
159
+ }
160
+ async def transfer_token(self, to: str, amount: float):
161
+
162
+ if not self.TOKEN_MINT:
163
+ raise ValueError("not set TOKEN_MINT.")
164
+ if not self.KEYPAIR:
165
+ raise ValueError("not set KEYPAIR.")
166
+
167
+ sender_pubkey = self.get_pubkey()
168
+ receiver_pubkey = solders.pubkey.Pubkey.from_string(to)
169
+ token_pubkey = solders.pubkey.Pubkey.from_string(self.TOKEN_MINT)
170
+
171
+ token = AsyncToken(self.client, token_pubkey, TOKEN_PROGRAM_ID, self.KEYPAIR)
172
+ sender_ata = get_associated_token_address(sender_pubkey, token_pubkey)
173
+ receiver_ata = get_associated_token_address(receiver_pubkey, token_pubkey)
174
+
175
+ tx = Transaction()
176
+
177
+ res = await self.client.get_account_info(receiver_ata)
178
+ if res.value is None:
179
+ tx.add(
180
+ create_associated_token_account(
181
+ payer=sender_pubkey,
182
+ owner=receiver_pubkey,
183
+ mint=token_pubkey
184
+ )
185
+ )
186
+
187
+ decimals = (await token.get_mint_info()).decimals
188
+ real_amount = int(amount * (10 ** decimals))
189
+ params = TransferParams(
190
+ program_id=TOKEN_PROGRAM_ID,
191
+ source=sender_ata,
192
+ dest=receiver_ata,
193
+ owner=sender_pubkey,
194
+ amount=real_amount
195
+ )
196
+
197
+ tx.add(transfer(params))
198
+
199
+ resp = await self.client.send_transaction(tx, self.KEYPAIR, opts=TxOpts(skip_preflight=True, preflight_commitment=Confirmed))
200
+ return resp.value
201
+
202
+
203
+ async def transfer_native(self, to:str, amount: int):
204
+ if not self.KEYPAIR:
205
+ raise ValueError("not set KEYPAIR.")
206
+
207
+ sender_pubkey = self.get_pubkey()
208
+ receiver_pubkey = solders.pubkey.Pubkey.from_string(to)
209
+ ixns = [
210
+ ts(tsf(
211
+ from_pubkey=sender_pubkey,
212
+ to_pubkey=receiver_pubkey,
213
+ lamports=int(amount * LAMPORTS_PER_SOL)
214
+ ))
215
+ ]
216
+ msg = Message(ixns, self.get_pubkey())
217
+ latest_blockhash_resp = await self.client.get_latest_blockhash()
218
+
219
+ blockhash_str = latest_blockhash_resp.value.blockhash
220
+ tx = Transaction([self.KEYPAIR], msg, blockhash_str)
221
+ resp = await self.client.send_transaction(tx)
222
+ return resp.value
223
+
224
+
225
+