shadowPaySDK 0.1.1__py3-none-any.whl → 0.2.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.
- shadowPaySDK/__init__.py +29 -2
- shadowPaySDK/api.py +48 -0
- shadowPaySDK/const.py +546 -0
- shadowPaySDK/interface/__init__.py +4 -0
- shadowPaySDK/interface/erc20.py +60 -48
- shadowPaySDK/interface/sol.py +162 -0
- shadowPaySDK/types/EVMcheque.py +325 -0
- shadowPaySDK/types/SOLcheque.py +27 -0
- shadowPaySDK/types/__init__.py +4 -0
- shadowPaySDK/utils/__init__.py +8 -0
- shadowPaySDK/utils/utils.py +28 -0
- {shadowpaysdk-0.1.1.dist-info → shadowpaysdk-0.2.1.dist-info}/METADATA +5 -2
- shadowpaysdk-0.2.1.dist-info/RECORD +17 -0
- shadowpaysdk-0.1.1.dist-info/RECORD +0 -9
- {shadowpaysdk-0.1.1.dist-info → shadowpaysdk-0.2.1.dist-info}/WHEEL +0 -0
- {shadowpaysdk-0.1.1.dist-info → shadowpaysdk-0.2.1.dist-info}/licenses/LICENSE +0 -0
- {shadowpaysdk-0.1.1.dist-info → shadowpaysdk-0.2.1.dist-info}/top_level.txt +0 -0
shadowPaySDK/interface/erc20.py
CHANGED
@@ -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,
|
20
|
-
self.web3 =
|
9
|
+
def __init__(self, w3:Web3, explorer: Optional[str] = None):
|
10
|
+
self.web3 = w3
|
21
11
|
self.explorer = explorer
|
22
|
-
self.address =
|
23
|
-
self.contract =
|
12
|
+
self.address = None
|
13
|
+
self.contract = None
|
14
|
+
|
15
|
+
def set_params(self, token_address: Optional[str] = None, w3:Optional[Web3] = None):
|
16
|
+
if w3:
|
17
|
+
self.web3 = w3
|
18
|
+
if token_address:
|
19
|
+
self.address = Web3.to_checksum_address(token_address)
|
20
|
+
self.contract = self.web3.eth.contract(address=self.address, abi=__ERC20_ABI__)
|
21
|
+
|
22
|
+
def _ensure_contract(self):
|
23
|
+
if not self.contract:
|
24
|
+
raise ValueError("Token address is not set. Use set_token(token_address) first.")
|
24
25
|
|
25
26
|
def _format_tx(self, tx_hash: str) -> str:
|
26
27
|
if self.explorer:
|
27
28
|
return f"{self.explorer.rstrip('/')}/tx/{tx_hash}"
|
28
29
|
return tx_hash
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
def get_decimals(self) -> int:
|
30
|
+
def gen_wallet(self) -> str:
|
31
|
+
account = self.web3.eth.account.create()
|
32
|
+
return account
|
33
|
+
def get_decimals(self, token) -> int:
|
34
|
+
self._ensure_contract()
|
35
|
+
if token:
|
36
|
+
self.set_params(token_address=token)
|
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
|
-
|
40
|
-
|
41
|
-
|
42
|
-
return raw_balance / (10 ** self.get_decimals())
|
43
|
-
|
44
|
-
|
44
|
+
self._ensure_contract()
|
45
|
+
raw = self.contract.functions.balanceOf(Web3.to_checksum_address(wallet_address)).call()
|
46
|
+
return raw / (10 ** self.get_decimals())
|
45
47
|
|
46
|
-
def allowance(self, owner: str, spender: str) -> float:
|
48
|
+
def allowance(self, owner: str, spender: str, token) -> float:
|
49
|
+
self._ensure_contract()
|
47
50
|
raw = self.contract.functions.allowance(
|
48
51
|
Web3.to_checksum_address(owner),
|
49
52
|
Web3.to_checksum_address(spender)
|
50
53
|
).call()
|
51
|
-
return raw / (10 ** self.get_decimals())
|
54
|
+
return raw / (10 ** self.get_decimals(token))
|
52
55
|
|
53
|
-
def ensure_allowance(self, private_key: str, spender: str, amount
|
56
|
+
def ensure_allowance(self, private_key: str, spender: str, amount, token) -> Union[bool, str]:
|
57
|
+
self._ensure_contract()
|
54
58
|
account = self.web3.eth.account.from_key(private_key)
|
55
|
-
|
56
|
-
if
|
59
|
+
current = self.allowance(account.address, spender, token)
|
60
|
+
if current == amount:
|
57
61
|
return True
|
58
|
-
return self.approve(private_key, spender, amount)
|
59
|
-
|
62
|
+
return self.approve(private_key, spender, amount, token)
|
63
|
+
|
60
64
|
def transfer(self, private_key: str, to: str, amount: float) -> str:
|
65
|
+
self._ensure_contract()
|
61
66
|
account = self.web3.eth.account.from_key(private_key)
|
62
67
|
decimals = self.get_decimals()
|
63
68
|
value = int(amount * (10 ** decimals))
|
64
|
-
|
69
|
+
estimated_gas = self.contract.functions.transfer(
|
70
|
+
Web3.to_checksum_address(to),
|
71
|
+
value
|
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
78
|
value
|
68
79
|
).build_transaction({
|
69
80
|
'from': account.address,
|
70
81
|
'nonce': self.web3.eth.get_transaction_count(account.address),
|
71
|
-
'gas':
|
82
|
+
'gas': estimated_gas,
|
72
83
|
'gasPrice': self.web3.to_wei('5', 'gwei'),
|
73
84
|
})
|
74
85
|
|
@@ -76,27 +87,28 @@ 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:
|
90
|
+
def approve(self, private_key: str, spender: str, amount: float, token) -> str:
|
91
|
+
self._ensure_contract()
|
80
92
|
account = self.web3.eth.account.from_key(private_key)
|
81
|
-
decimals = self.get_decimals()
|
82
|
-
|
83
|
-
|
93
|
+
decimals = self.get_decimals(token=token)
|
94
|
+
amount = int(amount * (10 ** decimals))
|
95
|
+
|
84
96
|
txn = self.contract.functions.approve(
|
85
97
|
Web3.to_checksum_address(spender),
|
86
|
-
|
98
|
+
amount
|
87
99
|
).build_transaction({
|
88
100
|
'from': account.address,
|
89
101
|
'nonce': self.web3.eth.get_transaction_count(account.address),
|
90
|
-
'gas':
|
91
|
-
|
102
|
+
'gas': 60000,
|
103
|
+
|
104
|
+
'gasPrice': self.web3.eth.gas_price,
|
92
105
|
})
|
93
106
|
|
94
107
|
signed = self.web3.eth.account.sign_transaction(txn, private_key)
|
95
108
|
tx_hash = self.web3.eth.send_raw_transaction(signed.raw_transaction)
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
109
|
+
tx_receipt = self.web3.eth.wait_for_transaction_receipt(tx_hash)
|
110
|
+
if tx_receipt.status != 1:
|
111
|
+
raise ValueError(f"aaprove fail.\n {self._format_tx(self.web3.to_hex(tx_hash))}")
|
112
|
+
|
113
|
+
return f"approve: {self._format_tx(self.web3.to_hex(tx_hash))}"
|
102
114
|
|
@@ -0,0 +1,162 @@
|
|
1
|
+
import asyncio
|
2
|
+
from solana.rpc.async_api import AsyncClient, GetTokenAccountsByOwnerResp
|
3
|
+
import spl
|
4
|
+
import spl.token
|
5
|
+
import spl.token.constants
|
6
|
+
from spl.token.instructions import get_associated_token_address, create_associated_token_account, transfer, close_account
|
7
|
+
from spl.token.constants import TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID
|
8
|
+
from solana.constants import *
|
9
|
+
from solana.rpc.types import TxOpts, TokenAccountOpts
|
10
|
+
from solana.rpc.types import TxOpts
|
11
|
+
import solders
|
12
|
+
from solders.pubkey import Pubkey
|
13
|
+
from solders.keypair import Keypair
|
14
|
+
from solders.signature import Signature
|
15
|
+
import anchorpy
|
16
|
+
from anchorpy import Provider, Wallet, Idl
|
17
|
+
from typing import Optional, Union
|
18
|
+
import pprint
|
19
|
+
import httpx
|
20
|
+
import base64
|
21
|
+
import re
|
22
|
+
|
23
|
+
class SolTokens:
|
24
|
+
def __init__(self, rpc_url: str = "https://api.mainnet-beta.solana.com"):
|
25
|
+
self.rpc_url = rpc_url
|
26
|
+
self.client = AsyncClient(rpc_url)
|
27
|
+
self.PROGRAM_ID = TOKEN_PROGRAM_ID # Default to the SPL Token Program ID
|
28
|
+
self.WRAPED_SOL_ID = spl.token.constants.WRAPPED_SOL_MINT
|
29
|
+
def set_params(self, rpc_url: Optional[str] = None, PROGRAM_ID: Optional[str] = None):
|
30
|
+
if rpc_url:
|
31
|
+
self.rpc_url = rpc_url
|
32
|
+
self.client = AsyncClient(rpc_url)
|
33
|
+
|
34
|
+
class SOL:
|
35
|
+
|
36
|
+
def __init__(self, rpc_url = "https://api.mainnet-beta.solana.com", KEYPAIR: Optional[Union[str, Keypair]] = None):
|
37
|
+
self.rpc_url = rpc_url
|
38
|
+
self.client = AsyncClient(rpc_url)
|
39
|
+
self.KEYPAIR = None
|
40
|
+
|
41
|
+
if KEYPAIR:
|
42
|
+
self.set_keypair(KEYPAIR)
|
43
|
+
|
44
|
+
def set_keypair(self, KEYPAIR: Union[str, Keypair]):
|
45
|
+
if isinstance(KEYPAIR, str):
|
46
|
+
try:
|
47
|
+
self.KEYPAIR = Keypair.from_base58_string(KEYPAIR)
|
48
|
+
except Exception as e:
|
49
|
+
raise ValueError(f"Invalid Keypair string: {e}")
|
50
|
+
elif isinstance(KEYPAIR, Keypair):
|
51
|
+
self.KEYPAIR = KEYPAIR
|
52
|
+
else:
|
53
|
+
raise ValueError("KEYPAIR must be a Keypair instance or a base58 encoded string.")
|
54
|
+
|
55
|
+
def set_params(self, rpc_url: Optional[str] = None, KEYPAIR: Optional[Union[str, Keypair]] = None):
|
56
|
+
if rpc_url:
|
57
|
+
self.rpc_url = rpc_url
|
58
|
+
self.client = AsyncClient(rpc_url)
|
59
|
+
if KEYPAIR:
|
60
|
+
self.set_keypair(KEYPAIR)
|
61
|
+
|
62
|
+
def get_pubkey(self, returnString: Optional[bool] = None):
|
63
|
+
|
64
|
+
|
65
|
+
if self.KEYPAIR:
|
66
|
+
pubkey = self.KEYPAIR.pubkey()
|
67
|
+
pubkey_str = str(pubkey)
|
68
|
+
if returnString:
|
69
|
+
return pubkey_str
|
70
|
+
return pubkey
|
71
|
+
|
72
|
+
raise ValueError("Keypair not set")
|
73
|
+
|
74
|
+
def gen_wallet(self):
|
75
|
+
return Keypair()
|
76
|
+
async def get_balance(self):
|
77
|
+
resp = await self.client.get_balance(self.get_pubkey())
|
78
|
+
lamports = resp.value
|
79
|
+
sol_balance = lamports / LAMPORTS_PER_SOL
|
80
|
+
return sol_balance
|
81
|
+
async def get_token_accounts_by_owner(self,owner_pubkey: Optional[str] = None):
|
82
|
+
if not owner_pubkey:
|
83
|
+
print("No owner pubkey provided, using the wallet's pubkey.")
|
84
|
+
owner_pubkey = self.get_pubkey(returnString=True)
|
85
|
+
headers = {
|
86
|
+
"Content-Type": "application/json",
|
87
|
+
}
|
88
|
+
body = {
|
89
|
+
"jsonrpc": "2.0",
|
90
|
+
"id": 1,
|
91
|
+
"method": "getTokenAccountsByOwner",
|
92
|
+
"params": [
|
93
|
+
str(owner_pubkey),
|
94
|
+
{"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"},
|
95
|
+
{"encoding": "jsonParsed"}
|
96
|
+
]
|
97
|
+
}
|
98
|
+
async with httpx.AsyncClient() as client:
|
99
|
+
response = await client.post(self.rpc_url, headers=headers, json=body)
|
100
|
+
result = response.json()
|
101
|
+
accounts = result["result"]["value"]
|
102
|
+
|
103
|
+
token_data = {}
|
104
|
+
for acc in accounts:
|
105
|
+
parsed = acc["account"]["data"]["parsed"]["info"]
|
106
|
+
mint = parsed["mint"]
|
107
|
+
ui_amount = parsed["tokenAmount"]["uiAmount"]
|
108
|
+
token_data[mint] = {"amount": ui_amount}
|
109
|
+
|
110
|
+
filtered = {mint: data for mint, data in token_data.items() if data["amount"] > 0.001}
|
111
|
+
|
112
|
+
return filtered
|
113
|
+
async def is_connected(self):
|
114
|
+
return await self.client.is_connected()
|
115
|
+
|
116
|
+
async def close(self):
|
117
|
+
await self.client.close()
|
118
|
+
|
119
|
+
async def fetch_metadata_raw(self,mint_address: str):
|
120
|
+
METADATA_PROGRAM_ID = Pubkey.from_string("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s")
|
121
|
+
mint = Pubkey.from_string(mint_address)
|
122
|
+
seeds = [
|
123
|
+
b"metadata",
|
124
|
+
bytes(METADATA_PROGRAM_ID),
|
125
|
+
bytes(mint),
|
126
|
+
]
|
127
|
+
pda, _ = Pubkey.find_program_address(seeds, METADATA_PROGRAM_ID)
|
128
|
+
|
129
|
+
payload = {
|
130
|
+
"jsonrpc": "2.0",
|
131
|
+
"id": 1,
|
132
|
+
"method": "getAccountInfo",
|
133
|
+
"params": [
|
134
|
+
str(pda),
|
135
|
+
{"encoding": "base64"}
|
136
|
+
]
|
137
|
+
}
|
138
|
+
|
139
|
+
async with httpx.AsyncClient() as client:
|
140
|
+
r = await client.post("https://api.mainnet-beta.solana.com", json=payload)
|
141
|
+
data = r.json()
|
142
|
+
|
143
|
+
if not data["result"]["value"]:
|
144
|
+
return None
|
145
|
+
|
146
|
+
b64_data = data["result"]["value"]["data"][0]
|
147
|
+
raw_bytes = base64.b64decode(b64_data)
|
148
|
+
|
149
|
+
name = raw_bytes[1+32+32 : 1+32+32+32].decode("utf-8").rstrip("\x00")
|
150
|
+
name = re.sub(r'[^\x20-\x7E]', '', name)
|
151
|
+
return {
|
152
|
+
"mint": mint_address,
|
153
|
+
"name": name,
|
154
|
+
}
|
155
|
+
|
156
|
+
|
157
|
+
|
158
|
+
|
159
|
+
|
160
|
+
if __name__ == "__main__":
|
161
|
+
newKeypair = Keypair()
|
162
|
+
print("New Keypair:", newKeypair)
|
@@ -0,0 +1,325 @@
|
|
1
|
+
import shadowPaySDK
|
2
|
+
from shadowPaySDK.const import __SHADOWPAY_ABI__ERC20__, __ALLOW_CHAINS__, __SHADOWPAY_CONTRACT_ADDRESS__ERC20__
|
3
|
+
from shadowPaySDK.api import __CREATE__CHEQUE__
|
4
|
+
from web3 import Web3
|
5
|
+
from typing import Optional
|
6
|
+
import httpx
|
7
|
+
|
8
|
+
|
9
|
+
class Cheque:
|
10
|
+
def __init__(self, w3:Web3,private_key:str, ABI = __SHADOWPAY_ABI__ERC20__, allowed_chains = __ALLOW_CHAINS__):
|
11
|
+
self.w3 = w3
|
12
|
+
print(f"chain id: {self.w3.eth.chain_id}")
|
13
|
+
print(f"allowed chains", allowed_chains)
|
14
|
+
self.amount = None
|
15
|
+
self.token = None
|
16
|
+
self.private_key = private_key
|
17
|
+
self.ABI = ABI
|
18
|
+
|
19
|
+
self.allowed_chains = allowed_chains
|
20
|
+
if self.__allow__():
|
21
|
+
print(f"Allowed chains: {self.allowed_chains}")
|
22
|
+
|
23
|
+
def __get__id(self, tx):
|
24
|
+
try:
|
25
|
+
logs = self.contract.events.ChequeCreated().process_receipt(tx)
|
26
|
+
cheque_id = logs[0]["args"]["id"]
|
27
|
+
return cheque_id.hex()
|
28
|
+
except Exception as e:
|
29
|
+
print(f"Failed to get cheque ID from transaction receipt: {str(e)}")
|
30
|
+
return False
|
31
|
+
def __allow__(self):
|
32
|
+
for chain in self.allowed_chains:
|
33
|
+
|
34
|
+
if chain == self.w3.eth.chain_id:
|
35
|
+
self.get_contract_for_chain(chain_id=self.w3.eth.chain_id)
|
36
|
+
|
37
|
+
return True
|
38
|
+
|
39
|
+
raise ValueError(f"Chain {str(self.w3.eth.chain_id)} is not allowed. Allowed chains are: {self.allowed_chains}")
|
40
|
+
def get_contract_for_chain(self,chain_id: str):
|
41
|
+
c = None
|
42
|
+
for chain in __SHADOWPAY_CONTRACT_ADDRESS__ERC20__ :
|
43
|
+
print(f"Checking chain {chain} against {self.w3.eth.chain_id}")
|
44
|
+
if str(chain) == str(chain_id):
|
45
|
+
c = __SHADOWPAY_CONTRACT_ADDRESS__ERC20__[chain_id]
|
46
|
+
print(f"Contract address: {c}, type {type(c)} ")
|
47
|
+
contract_address = Web3.to_checksum_address(c)
|
48
|
+
contract = self.w3.eth.contract(address=contract_address, abi=__SHADOWPAY_ABI__ERC20__)
|
49
|
+
self.contract = contract
|
50
|
+
return contract
|
51
|
+
raise ValueError(f"Chain {chain_id} is not supported. Supported chains are: {list(__SHADOWPAY_CONTRACT_ADDRESS__ERC20__.keys())}")
|
52
|
+
|
53
|
+
def set_parameters(self,chain_id: Optional[str] = None, w3:Optional[Web3] = None, amount:Optional[int] = None, private_key:Optional[str] = None, token:Optional[str] = None):
|
54
|
+
if w3:
|
55
|
+
self.w3 = w3
|
56
|
+
self.get_contract_for_chain(chain_id=chain_id or self.w3.eth.chain_id)
|
57
|
+
if amount:
|
58
|
+
self.amount = amount
|
59
|
+
if private_key:
|
60
|
+
self.private_key = private_key
|
61
|
+
if token:
|
62
|
+
self.token = token
|
63
|
+
def __convert__(self):
|
64
|
+
return self.w3.to_wei(self.amount, 'ether')
|
65
|
+
|
66
|
+
async def InitCheque(self, amount, receiver:list, private_key:Optional[str] = None):
|
67
|
+
if not isinstance(receiver,list):
|
68
|
+
raise ValueError("Receiver must be a list of addresses, [""0x1234...5678", "0x2345...6789""]")
|
69
|
+
|
70
|
+
receiver = [Web3.to_checksum_address(addr) for addr in receiver]
|
71
|
+
estimated_gas = self.contract.functions.InitCheque(receiver).estimate_gas({
|
72
|
+
'from': self.w3.eth.account.from_key(private_key or self.private_key).address,
|
73
|
+
'value': self.w3.to_wei(amount, 'ether'),
|
74
|
+
'gasPrice': self.w3.eth.gas_price
|
75
|
+
})
|
76
|
+
txn = self.contract.functions.InitCheque(receiver).build_transaction({
|
77
|
+
'from': self.w3.eth.account.from_key(private_key or self.private_key).address,
|
78
|
+
'value': self.w3.to_wei(amount, 'ether'),
|
79
|
+
'nonce': self.w3.eth.get_transaction_count(
|
80
|
+
self.w3.eth.account.from_key(private_key or self.private_key).address
|
81
|
+
),
|
82
|
+
'gas': estimated_gas,
|
83
|
+
'gasPrice': self.w3.eth.gas_price,
|
84
|
+
'chainId': self.w3.eth.chain_id
|
85
|
+
})
|
86
|
+
signed_txn = self.w3.eth.account.sign_transaction(txn, private_key or self.private_key)
|
87
|
+
txn_hash = self.w3.eth.send_raw_transaction(signed_txn.raw_transaction)
|
88
|
+
txn_receipt = self.w3.eth.wait_for_transaction_receipt(txn_hash)
|
89
|
+
insert_to_dn = None
|
90
|
+
logs = self.__get__id(txn_receipt)
|
91
|
+
if logs:
|
92
|
+
cheque_id = logs
|
93
|
+
else:
|
94
|
+
cheque_id = None
|
95
|
+
return {
|
96
|
+
"hash": txn_hash.hex(),
|
97
|
+
"chequeId": cheque_id,
|
98
|
+
}
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
|
103
|
+
async def CashOutCheque(
|
104
|
+
self,
|
105
|
+
private_key: str,
|
106
|
+
cheque_id: str # hex-строка типа "0xabc..."
|
107
|
+
):
|
108
|
+
if not private_key:
|
109
|
+
private_key = self.private_key
|
110
|
+
|
111
|
+
|
112
|
+
account = self.w3.eth.account.from_key(private_key)
|
113
|
+
sender_address = account.address
|
114
|
+
|
115
|
+
|
116
|
+
# подготовка транзакции
|
117
|
+
nonce = self.eth.get_transaction_count(sender_address)
|
118
|
+
|
119
|
+
txn = self.contract.functions.CashOutCheque(
|
120
|
+
Web3.to_bytes(hexstr=cheque_id)).build_transaction({
|
121
|
+
'from': sender_address,
|
122
|
+
'nonce': nonce,
|
123
|
+
'gas': 300_000, # пример
|
124
|
+
'gasPrice': self.w3.to_wei('5', 'gwei'),
|
125
|
+
})
|
126
|
+
|
127
|
+
# подписываем
|
128
|
+
signed_txn = self.w3.eth.account.sign_transaction(txn, private_key=private_key)
|
129
|
+
|
130
|
+
# отправляем
|
131
|
+
tx_hash = self.w3.eth.send_raw_transaction(signed_txn.raw_transaction)
|
132
|
+
|
133
|
+
print(f"⏳ Transaction sent: {tx_hash.hex()}")
|
134
|
+
receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash)
|
135
|
+
print(f"✅ Transaction confirmed in block {receipt.blockNumber}")
|
136
|
+
return receipt
|
137
|
+
|
138
|
+
async def InitTokenCheque(self, token_address:str, amount, reciver:str, private_key:Optional[str] = None):
|
139
|
+
# collectedFes
|
140
|
+
|
141
|
+
erc20 = shadowPaySDK.ERC20Token(w3=self.w3)
|
142
|
+
erc20.set_params(token_address=token_address)
|
143
|
+
ensure_allowance = erc20.ensure_allowance(
|
144
|
+
private_key=self.private_key,
|
145
|
+
spender=self.contract.address,
|
146
|
+
amount=amount
|
147
|
+
)
|
148
|
+
print(f"Ensure allowance: {ensure_allowance}")
|
149
|
+
decimals = erc20.get_decimals()
|
150
|
+
estimated_gas = self.contract.functions.InitTokenCheque(
|
151
|
+
Web3.to_checksum_address(token_address),
|
152
|
+
int(amount * (10 ** decimals)),
|
153
|
+
Web3.to_checksum_address(reciver)
|
154
|
+
).estimate_gas({
|
155
|
+
'from': self.w3.eth.account.from_key(self.private_key).address,
|
156
|
+
'gasPrice': self.w3.eth.gas_price
|
157
|
+
})
|
158
|
+
txn = self.contract.functions.InitTokenCheque(
|
159
|
+
Web3.to_checksum_address(token_address),
|
160
|
+
int(amount * (10 ** decimals)),
|
161
|
+
Web3.to_checksum_address(reciver)
|
162
|
+
).build_transaction({
|
163
|
+
'from': self.w3.eth.account.from_key(self.private_key).address,
|
164
|
+
'nonce': self.w3.eth.get_transaction_count(self.w3.eth.account.from_key(self.private_key).address),
|
165
|
+
'gas': estimated_gas,
|
166
|
+
'gasPrice': self.w3.eth.gas_price
|
167
|
+
})
|
168
|
+
signed_txn = self.w3.eth.account.sign_transaction(txn, self.private_key)
|
169
|
+
txn_hash = self.w3.eth.send_raw_transaction(signed_txn.raw_transaction)
|
170
|
+
txn_receipt = self.w3.eth.wait_for_transaction_receipt(txn_hash)
|
171
|
+
|
172
|
+
logs = self.__get__id(txn_receipt)
|
173
|
+
if logs:
|
174
|
+
cheque_id = logs
|
175
|
+
else:
|
176
|
+
cheque_id = None
|
177
|
+
|
178
|
+
return {
|
179
|
+
"hash": txn_hash.hex(),
|
180
|
+
"chequeId": cheque_id,
|
181
|
+
}
|
182
|
+
|
183
|
+
async def CashOutTokenCheque(self, cheque_id: str, private_key: Optional[str] = None):
|
184
|
+
if private_key is None:
|
185
|
+
private_key = self.private_key
|
186
|
+
|
187
|
+
account = self.w3.eth.account.from_key(private_key)
|
188
|
+
|
189
|
+
|
190
|
+
|
191
|
+
# Строим транзакцию
|
192
|
+
estimated_gas = self.contract.functions.CashOutTokenCheque(
|
193
|
+
Web3.to_bytes(hexstr=cheque_id) # Преобразуем строку в bytes32
|
194
|
+
).estimate_gas({
|
195
|
+
'from': account.address,
|
196
|
+
'gasPrice': self.w3.eth.gas_price
|
197
|
+
})
|
198
|
+
txn = self.contract.functions.CashOutTokenCheque(
|
199
|
+
Web3.to_bytes(hexstr=cheque_id)
|
200
|
+
).build_transaction({
|
201
|
+
'from': account.address,
|
202
|
+
'nonce': self.w3.eth.get_transaction_count(account.address),
|
203
|
+
'gas': estimated_gas,
|
204
|
+
'gasPrice': self.w3.eth.gas_price,
|
205
|
+
})
|
206
|
+
|
207
|
+
# Подписываем и отправляем транзакцию
|
208
|
+
signed_txn = self.w3.eth.account.sign_transaction(txn, private_key=private_key)
|
209
|
+
tx_hash = self.w3.eth.send_raw_transaction(signed_txn.raw_transaction)
|
210
|
+
|
211
|
+
# Получаем подтверждение
|
212
|
+
receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash)
|
213
|
+
|
214
|
+
return {
|
215
|
+
"hash": tx_hash.hex(),
|
216
|
+
"status": receipt.status # 1 = success, 0 = fail
|
217
|
+
}
|
218
|
+
async def InitTokenChequeSwap(self, token_in:str, amount_in,token_out:str, amount_out, reciver:str, private_key:Optional[str] = None):
|
219
|
+
|
220
|
+
erc20 = shadowPaySDK.ERC20Token(w3=self.w3)
|
221
|
+
erc20.set_params(token_address=token_in)
|
222
|
+
ensure_allowance = erc20.approve(
|
223
|
+
private_key=self.private_key,
|
224
|
+
spender=self.contract.address,
|
225
|
+
amount=amount_in,
|
226
|
+
token=token_in
|
227
|
+
)
|
228
|
+
print(f"Ensure allowance: {ensure_allowance}")
|
229
|
+
decimals = erc20.get_decimals(token_in)
|
230
|
+
token_out_decinals = erc20.get_decimals(token_out)
|
231
|
+
estimated_gas = self.contract.functions.InitSwapCheque(
|
232
|
+
Web3.to_checksum_address(reciver),
|
233
|
+
Web3.to_checksum_address(token_in),
|
234
|
+
int(amount_in * (10 ** decimals)),
|
235
|
+
Web3.to_checksum_address(token_out),
|
236
|
+
int(amount_out * (10 ** token_out_decinals)),
|
237
|
+
).estimate_gas({
|
238
|
+
'from': self.w3.eth.account.from_key(self.private_key).address,
|
239
|
+
'gasPrice': self.w3.eth.gas_price
|
240
|
+
})
|
241
|
+
txn = self.contract.functions.InitSwapCheque(
|
242
|
+
Web3.to_checksum_address(reciver),
|
243
|
+
Web3.to_checksum_address(token_in),
|
244
|
+
int(amount_in * (10 ** decimals)),
|
245
|
+
Web3.to_checksum_address(token_out),
|
246
|
+
int(amount_out * (10 ** token_out_decinals))
|
247
|
+
).build_transaction({
|
248
|
+
'from': self.w3.eth.account.from_key(self.private_key).address,
|
249
|
+
'nonce': self.w3.eth.get_transaction_count(self.w3.eth.account.from_key(self.private_key).address),
|
250
|
+
'gas': estimated_gas,
|
251
|
+
'gasPrice': self.w3.eth.gas_price
|
252
|
+
})
|
253
|
+
signed_txn = self.w3.eth.account.sign_transaction(txn, self.private_key)
|
254
|
+
txn_hash = self.w3.eth.send_raw_transaction(signed_txn.raw_transaction)
|
255
|
+
txn_receipt = self.w3.eth.wait_for_transaction_receipt(txn_hash)
|
256
|
+
|
257
|
+
logs = self.__get__id(txn_receipt)
|
258
|
+
if logs:
|
259
|
+
cheque_id = logs
|
260
|
+
else:
|
261
|
+
cheque_id = None
|
262
|
+
return {
|
263
|
+
"hash": txn_hash.hex(),
|
264
|
+
"chequeId": cheque_id
|
265
|
+
}
|
266
|
+
async def getComunityPool(self):
|
267
|
+
# fee = self.contract.functions.getCollectedFee().call()
|
268
|
+
fee = 50000000000000
|
269
|
+
half_fee_eth = self.w3.from_wei(fee // 2, 'ether')
|
270
|
+
return half_fee_eth
|
271
|
+
async def getOwner(self):
|
272
|
+
return self.contract.functions.getOwner().call()
|
273
|
+
async def getTreasery(self):
|
274
|
+
return self.contract.functions.getTreasery().call()
|
275
|
+
async def getSwaoDetail(self, cheque_id: str):
|
276
|
+
cheque_id_bytes = Web3.to_bytes(hexstr=cheque_id)
|
277
|
+
return self.contract.functions.getSwapDetail(cheque_id_bytes).call()
|
278
|
+
class NFTcheque:
|
279
|
+
def __init__(self, w3:Web3, token:str, amount:int, spender:str):
|
280
|
+
self.w3 = w3
|
281
|
+
self.token = token
|
282
|
+
self.amount = amount
|
283
|
+
self.spender = spender
|
284
|
+
|
285
|
+
def InitNFTCheque(self):
|
286
|
+
pass
|
287
|
+
|
288
|
+
def CashOutNFTCheque(self):
|
289
|
+
pass
|
290
|
+
|
291
|
+
|
292
|
+
|
293
|
+
|
294
|
+
|
295
|
+
|
296
|
+
|
297
|
+
|
298
|
+
|
299
|
+
|
300
|
+
|
301
|
+
|
302
|
+
|
303
|
+
|
304
|
+
|
305
|
+
|
306
|
+
|
307
|
+
|
308
|
+
|
309
|
+
async def create_cheque(id, type, chain_id, receiver, sender):
|
310
|
+
async with httpx.AsyncClient() as client:
|
311
|
+
response = await client.post(
|
312
|
+
__CREATE__CHEQUE__,
|
313
|
+
json={
|
314
|
+
"cheque_id": id,
|
315
|
+
"chain_id":chain_id,
|
316
|
+
"receiver": receiver,
|
317
|
+
"type": type,
|
318
|
+
"sender":sender
|
319
|
+
}
|
320
|
+
)
|
321
|
+
if response.status_code == 200:
|
322
|
+
return response.json()
|
323
|
+
else:
|
324
|
+
print(f"Failed to create cheque: {response.text}")
|
325
|
+
return False
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
import anchorpy
|
3
|
+
from anchorpy import Idl, Provider, Wallet
|
4
|
+
from shadowPaySDK.interface.sol import SOL
|
5
|
+
from solders.keypair import Keypair
|
6
|
+
import solana.constants as constants
|
7
|
+
import solana.constants as sol_constants
|
8
|
+
import spl.token.constants as spl_constants
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
class SOLCheque:
|
13
|
+
def __init__(self, rpc_url: str = "https://api.mainnet-beta.solana.com", keystore: Wallet = None):
|
14
|
+
self.rpc_url = rpc_url
|
15
|
+
self.keystore = keystore
|
16
|
+
self.provider = Provider(self.rpc_url, self.keystore)
|
17
|
+
self.WRAPED_SOL = spl_constants.WRAPPED_SOL_MINT # wrapped SOL token mint address
|
18
|
+
# self.idl = Idl.from_json(sol_interface.Idl) # Load the IDL for the program
|
19
|
+
def get(self, keypair = None):
|
20
|
+
pubkey = SOL.get_pubkey(KEYPAIR=Keypair.from_base58_string(self.keystore))
|
21
|
+
|
22
|
+
return pubkey
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
|