shadowPaySDK 0.2.1__py3-none-any.whl → 16.7.2025__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 +1 -3
- shadowPaySDK/const.py +15 -3
- shadowPaySDK/interface/__init__.py +2 -2
- shadowPaySDK/interface/erc20.py +29 -18
- shadowPaySDK/interface/sol.py +101 -33
- shadowPaySDK/types/EVMcheque.py +166 -74
- shadowPaySDK/types/SOLcheque.py +266 -9
- {shadowpaysdk-0.2.1.dist-info → shadowpaysdk-16.7.2025.dist-info}/METADATA +20 -7
- shadowpaysdk-16.7.2025.dist-info/RECORD +17 -0
- shadowpaysdk-0.2.1.dist-info/RECORD +0 -17
- {shadowpaysdk-0.2.1.dist-info → shadowpaysdk-16.7.2025.dist-info}/WHEEL +0 -0
- {shadowpaysdk-0.2.1.dist-info → shadowpaysdk-16.7.2025.dist-info}/licenses/LICENSE +0 -0
- {shadowpaysdk-0.2.1.dist-info → shadowpaysdk-16.7.2025.dist-info}/top_level.txt +0 -0
shadowPaySDK/__init__.py
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
import json
|
2
2
|
from shadowPaySDK.interface.erc20 import ERC20Token
|
3
3
|
from shadowPaySDK.interface.erc721 import ERC721Token
|
4
|
-
from shadowPaySDK.interface.sol import
|
5
|
-
from shadowPaySDK.interface.sol import SOL
|
4
|
+
from shadowPaySDK.interface.sol import SOL as sol
|
6
5
|
from shadowPaySDK.types.EVMcheque import Cheque
|
7
6
|
from shadowPaySDK.types.SOLcheque import SOLCheque
|
8
7
|
from shadowPaySDK.const import __ERC20_ABI__, __SHADOWPAY_ABI__ERC20__,__ALLOW_CHAINS__, __SHADOWPAY_CONTRACT_ADDRESS__ERC20__
|
9
|
-
from shadowPaySDK.api import __MAIN__URL__, __CREATE__CHEQUE__, get_my_cheques, create_cheque
|
10
8
|
|
11
9
|
|
12
10
|
# from shadowPaySDK.utils import parse_tx as PARSE_TX
|
shadowPaySDK/const.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import json
|
2
|
-
|
2
|
+
from solders.pubkey import Pubkey
|
3
3
|
__ALLOW_CHAINS__ = [
|
4
4
|
56, # BSC Mainnet
|
5
5
|
97, # BSC Testnet
|
@@ -11,6 +11,9 @@ __ALLOW_CHAINS__ = [
|
|
11
11
|
0xa
|
12
12
|
]
|
13
13
|
|
14
|
+
|
15
|
+
|
16
|
+
|
14
17
|
__VERSION__ = "0.1.2"
|
15
18
|
|
16
19
|
|
@@ -27,7 +30,7 @@ __ERC20_ABI__ = json.loads("""[
|
|
27
30
|
]""")
|
28
31
|
|
29
32
|
__SHADOWPAY_CONTRACT_ADDRESS__ERC20__ = {
|
30
|
-
97: "
|
33
|
+
97: "0x5487C0DdCbD5465F26B446c6CAB88D8d6F7DF23b"
|
31
34
|
}
|
32
35
|
|
33
36
|
__SHADOWPAY_ABI__ERC20__= json.loads("""[
|
@@ -543,4 +546,13 @@ __SHADOWPAY_ABI__ERC20__= json.loads("""[
|
|
543
546
|
__SHADOWPAY_ABI__ERC721__ = json.loads("""[]""")
|
544
547
|
__SHADOWPAY_CONTRACT_ADDRESS__ERC721__ = {
|
545
548
|
"0x1": "0x3c5b8d6f2e"
|
546
|
-
}
|
549
|
+
}
|
550
|
+
|
551
|
+
SOLANA_SYSTEM_PROGRAMM = "11111111111111111111111111111111"
|
552
|
+
LAMPORTS_PER_SOL = 1_000_000_000
|
553
|
+
WRAPED_SOL = "So11111111111111111111111111111111111111112"
|
554
|
+
TOKEN_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
|
555
|
+
NATIVE_DECIMALS: int = 9
|
556
|
+
PROGRAM_ID = Pubkey.from_string("CrfYLvU4FdVjkBno2rRi6u5U6nGCykpQnQKSBg3uVXTw")
|
557
|
+
|
558
|
+
CONFIG_PDA=Pubkey.find_program_address([b"config"], PROGRAM_ID)
|
shadowPaySDK/interface/erc20.py
CHANGED
@@ -6,9 +6,10 @@ from shadowPaySDK.const import __ERC20_ABI__
|
|
6
6
|
|
7
7
|
|
8
8
|
class ERC20Token:
|
9
|
-
def __init__(self, w3:Web3, explorer: Optional[str] = None):
|
9
|
+
def __init__(self, w3: Optional[Web3] = None, explorer: Optional[str] = None):
|
10
10
|
self.web3 = w3
|
11
11
|
self.explorer = explorer
|
12
|
+
|
12
13
|
self.address = None
|
13
14
|
self.contract = None
|
14
15
|
|
@@ -21,7 +22,7 @@ class ERC20Token:
|
|
21
22
|
|
22
23
|
def _ensure_contract(self):
|
23
24
|
if not self.contract:
|
24
|
-
raise ValueError("Token address is not set. Use
|
25
|
+
raise ValueError("Token address is not set. Use set_params first.")
|
25
26
|
|
26
27
|
def _format_tx(self, tx_hash: str) -> str:
|
27
28
|
if self.explorer:
|
@@ -30,10 +31,9 @@ class ERC20Token:
|
|
30
31
|
def gen_wallet(self) -> str:
|
31
32
|
account = self.web3.eth.account.create()
|
32
33
|
return account
|
33
|
-
def get_decimals(self
|
34
|
+
def get_decimals(self) -> int:
|
34
35
|
self._ensure_contract()
|
35
|
-
|
36
|
-
self.set_params(token_address=token)
|
36
|
+
|
37
37
|
return self.contract.functions.decimals().call()
|
38
38
|
|
39
39
|
def get_symbol(self) -> str:
|
@@ -45,21 +45,21 @@ class ERC20Token:
|
|
45
45
|
raw = self.contract.functions.balanceOf(Web3.to_checksum_address(wallet_address)).call()
|
46
46
|
return raw / (10 ** self.get_decimals())
|
47
47
|
|
48
|
-
def allowance(self, owner: str, spender: str
|
48
|
+
def allowance(self, owner: str, spender: str) -> float:
|
49
49
|
self._ensure_contract()
|
50
50
|
raw = self.contract.functions.allowance(
|
51
51
|
Web3.to_checksum_address(owner),
|
52
52
|
Web3.to_checksum_address(spender)
|
53
53
|
).call()
|
54
|
-
return raw / (10 ** self.get_decimals(
|
54
|
+
return raw / (10 ** self.get_decimals())
|
55
55
|
|
56
|
-
def ensure_allowance(self, private_key: str, spender: str, amount
|
56
|
+
def ensure_allowance(self, private_key: str, spender: str, amount) -> Union[bool, str]:
|
57
57
|
self._ensure_contract()
|
58
58
|
account = self.web3.eth.account.from_key(private_key)
|
59
|
-
current = self.allowance(account.address, spender
|
59
|
+
current = self.allowance(account.address, spender)
|
60
60
|
if current == amount:
|
61
61
|
return True
|
62
|
-
return self.approve(private_key, spender, amount
|
62
|
+
return self.approve(private_key, spender, amount)
|
63
63
|
|
64
64
|
def transfer(self, private_key: str, to: str, amount: float) -> str:
|
65
65
|
self._ensure_contract()
|
@@ -87,28 +87,39 @@ class ERC20Token:
|
|
87
87
|
tx_hash = self.web3.eth.send_raw_transaction(signed.raw_transaction)
|
88
88
|
return self._format_tx(self.web3.to_hex(tx_hash))
|
89
89
|
|
90
|
-
def approve(self,
|
90
|
+
def approve(self, spender: str, amount: float,address:Optional[str] = None, private_key: Optional[str] = None, build_tx: bool = False) -> str:
|
91
|
+
|
91
92
|
self._ensure_contract()
|
92
|
-
|
93
|
-
|
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")
|
102
|
+
|
103
|
+
decimals = self.get_decimals()
|
94
104
|
amount = int(amount * (10 ** decimals))
|
95
105
|
|
96
106
|
txn = self.contract.functions.approve(
|
97
107
|
Web3.to_checksum_address(spender),
|
98
108
|
amount
|
99
109
|
).build_transaction({
|
100
|
-
'from':
|
101
|
-
'nonce': self.web3.eth.get_transaction_count(
|
110
|
+
'from': address,
|
111
|
+
'nonce': self.web3.eth.get_transaction_count(address),
|
102
112
|
'gas': 60000,
|
103
113
|
|
104
114
|
'gasPrice': self.web3.eth.gas_price,
|
105
115
|
})
|
116
|
+
if build_tx:
|
117
|
+
return txn
|
106
118
|
|
107
|
-
signed = self.web3.eth.account.sign_transaction(txn,
|
119
|
+
signed = self.web3.eth.account.sign_transaction(txn, key)
|
108
120
|
tx_hash = self.web3.eth.send_raw_transaction(signed.raw_transaction)
|
109
121
|
tx_receipt = self.web3.eth.wait_for_transaction_receipt(tx_hash)
|
110
122
|
if tx_receipt.status != 1:
|
111
123
|
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))}"
|
124
|
+
return f"{self._format_tx(self.web3.to_hex(tx_hash))}"
|
114
125
|
|
shadowPaySDK/interface/sol.py
CHANGED
@@ -1,17 +1,29 @@
|
|
1
1
|
import asyncio
|
2
|
+
import solana
|
2
3
|
from solana.rpc.async_api import AsyncClient, GetTokenAccountsByOwnerResp
|
4
|
+
from solders.transaction import Transaction
|
5
|
+
from solders.system_program import TransferParams as p
|
3
6
|
import spl
|
4
7
|
import spl.token
|
5
8
|
import spl.token.constants
|
6
|
-
from spl.token.instructions import get_associated_token_address, create_associated_token_account, transfer, close_account
|
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
|
7
12
|
from spl.token.constants import TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID
|
8
|
-
from solana.constants import *
|
9
13
|
from solana.rpc.types import TxOpts, TokenAccountOpts
|
10
14
|
from solana.rpc.types import TxOpts
|
11
15
|
import solders
|
12
|
-
from solders.
|
13
|
-
|
14
|
-
from 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
|
15
27
|
import anchorpy
|
16
28
|
from anchorpy import Provider, Wallet, Idl
|
17
29
|
from typing import Optional, Union
|
@@ -20,44 +32,40 @@ import httpx
|
|
20
32
|
import base64
|
21
33
|
import re
|
22
34
|
|
23
|
-
|
24
|
-
|
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)
|
35
|
+
|
36
|
+
LAMPORTS_PER_SOL = 1_000_000_000 # 1 SOL = 1,000,000,000 lamports
|
33
37
|
|
34
38
|
class SOL:
|
35
|
-
|
36
|
-
def __init__(self, rpc_url = "https://api.mainnet-beta.solana.com", KEYPAIR: Optional[Union[str, Keypair]] = None):
|
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):
|
37
40
|
self.rpc_url = rpc_url
|
41
|
+
|
38
42
|
self.client = AsyncClient(rpc_url)
|
39
43
|
self.KEYPAIR = None
|
40
|
-
|
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
|
41
47
|
if KEYPAIR:
|
42
48
|
self.set_keypair(KEYPAIR)
|
43
49
|
|
44
|
-
def set_keypair(self, KEYPAIR: Union[str, Keypair]):
|
50
|
+
def set_keypair(self, KEYPAIR: Union[str, solders.keypair.Keypair]):
|
45
51
|
if isinstance(KEYPAIR, str):
|
46
52
|
try:
|
47
|
-
self.KEYPAIR = Keypair.from_base58_string(KEYPAIR)
|
53
|
+
self.KEYPAIR = solders.keypair.Keypair.from_base58_string(KEYPAIR)
|
48
54
|
except Exception as e:
|
49
55
|
raise ValueError(f"Invalid Keypair string: {e}")
|
50
|
-
elif isinstance(KEYPAIR, Keypair):
|
56
|
+
elif isinstance(KEYPAIR, solders.keypair.Keypair):
|
51
57
|
self.KEYPAIR = KEYPAIR
|
52
58
|
else:
|
53
59
|
raise ValueError("KEYPAIR must be a Keypair instance or a base58 encoded string.")
|
54
60
|
|
55
|
-
def set_params(self, rpc_url: Optional[str] = None, KEYPAIR: Optional[Union[str, Keypair]] = None):
|
61
|
+
def set_params(self, rpc_url: Optional[str] = None, KEYPAIR: Optional[Union[str, solders.keypair.Keypair]] = None,TOKEN_MINT: Optional[str] = None):
|
56
62
|
if rpc_url:
|
57
63
|
self.rpc_url = rpc_url
|
58
64
|
self.client = AsyncClient(rpc_url)
|
59
65
|
if KEYPAIR:
|
60
66
|
self.set_keypair(KEYPAIR)
|
67
|
+
if TOKEN_MINT:
|
68
|
+
self.TOKEN_MINT = TOKEN_MINT
|
61
69
|
|
62
70
|
def get_pubkey(self, returnString: Optional[bool] = None):
|
63
71
|
|
@@ -72,7 +80,7 @@ class SOL:
|
|
72
80
|
raise ValueError("Keypair not set")
|
73
81
|
|
74
82
|
def gen_wallet(self):
|
75
|
-
return Keypair()
|
83
|
+
return solders.keypair.Keypair()
|
76
84
|
async def get_balance(self):
|
77
85
|
resp = await self.client.get_balance(self.get_pubkey())
|
78
86
|
lamports = resp.value
|
@@ -107,9 +115,9 @@ class SOL:
|
|
107
115
|
ui_amount = parsed["tokenAmount"]["uiAmount"]
|
108
116
|
token_data[mint] = {"amount": ui_amount}
|
109
117
|
|
110
|
-
|
118
|
+
|
111
119
|
|
112
|
-
return
|
120
|
+
return token_data
|
113
121
|
async def is_connected(self):
|
114
122
|
return await self.client.is_connected()
|
115
123
|
|
@@ -117,14 +125,14 @@ class SOL:
|
|
117
125
|
await self.client.close()
|
118
126
|
|
119
127
|
async def fetch_metadata_raw(self,mint_address: str):
|
120
|
-
METADATA_PROGRAM_ID = Pubkey.from_string("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s")
|
121
|
-
mint = Pubkey.from_string(mint_address)
|
128
|
+
METADATA_PROGRAM_ID = solders.pubkey.Pubkey.from_string("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s")
|
129
|
+
mint = solders.pubkey.Pubkey.from_string(mint_address)
|
122
130
|
seeds = [
|
123
131
|
b"metadata",
|
124
132
|
bytes(METADATA_PROGRAM_ID),
|
125
133
|
bytes(mint),
|
126
134
|
]
|
127
|
-
pda, _ = Pubkey.find_program_address(seeds, METADATA_PROGRAM_ID)
|
135
|
+
pda, _ = solders.pubkey.Pubkey.find_program_address(seeds, METADATA_PROGRAM_ID)
|
128
136
|
|
129
137
|
payload = {
|
130
138
|
"jsonrpc": "2.0",
|
@@ -137,7 +145,7 @@ class SOL:
|
|
137
145
|
}
|
138
146
|
|
139
147
|
async with httpx.AsyncClient() as client:
|
140
|
-
r = await client.post(
|
148
|
+
r = await client.post(self.rpc_url, json=payload)
|
141
149
|
data = r.json()
|
142
150
|
|
143
151
|
if not data["result"]["value"]:
|
@@ -151,12 +159,72 @@ class SOL:
|
|
151
159
|
return {
|
152
160
|
"mint": mint_address,
|
153
161
|
"name": name,
|
154
|
-
|
162
|
+
|
155
163
|
|
164
|
+
}
|
165
|
+
async def transfer_token(self, to: str, amount: float):
|
166
|
+
|
167
|
+
if not self.TOKEN_MINT:
|
168
|
+
raise ValueError("not set TOKEN_MINT.")
|
169
|
+
if not self.KEYPAIR:
|
170
|
+
raise ValueError("not set KEYPAIR.")
|
171
|
+
|
172
|
+
sender_pubkey = self.get_pubkey()
|
173
|
+
receiver_pubkey = solders.pubkey.Pubkey.from_string(to)
|
174
|
+
token_pubkey = solders.pubkey.Pubkey.from_string(self.TOKEN_MINT)
|
175
|
+
|
176
|
+
token = AsyncToken(self.client, token_pubkey, TOKEN_PROGRAM_ID, self.KEYPAIR)
|
177
|
+
sender_ata = get_associated_token_address(sender_pubkey, token_pubkey)
|
178
|
+
receiver_ata = get_associated_token_address(receiver_pubkey, token_pubkey)
|
179
|
+
|
180
|
+
tx = Transaction()
|
181
|
+
|
182
|
+
res = await self.client.get_account_info(receiver_ata)
|
183
|
+
if res.value is None:
|
184
|
+
tx.add(
|
185
|
+
create_associated_token_account(
|
186
|
+
payer=sender_pubkey,
|
187
|
+
owner=receiver_pubkey,
|
188
|
+
mint=token_pubkey
|
189
|
+
)
|
190
|
+
)
|
191
|
+
|
192
|
+
decimals = (await token.get_mint_info()).decimals
|
193
|
+
real_amount = int(amount * (10 ** decimals))
|
194
|
+
params = TransferParams(
|
195
|
+
program_id=TOKEN_PROGRAM_ID,
|
196
|
+
source=sender_ata,
|
197
|
+
dest=receiver_ata,
|
198
|
+
owner=sender_pubkey,
|
199
|
+
amount=real_amount
|
200
|
+
)
|
201
|
+
|
202
|
+
tx.add(transfer(params))
|
203
|
+
|
204
|
+
resp = await self.client.send_transaction(tx, self.KEYPAIR, opts=TxOpts(skip_preflight=True, preflight_commitment=Confirmed))
|
205
|
+
return resp.value
|
206
|
+
|
207
|
+
|
208
|
+
async def transfer_native(self, to:str, amount: int):
|
209
|
+
if not self.KEYPAIR:
|
210
|
+
raise ValueError("not set KEYPAIR.")
|
211
|
+
|
212
|
+
sender_pubkey = self.get_pubkey()
|
213
|
+
receiver_pubkey = solders.pubkey.Pubkey.from_string(to)
|
214
|
+
ixns = [
|
215
|
+
ts(tsf(
|
216
|
+
from_pubkey=sender_pubkey,
|
217
|
+
to_pubkey=receiver_pubkey,
|
218
|
+
lamports=int(amount * LAMPORTS_PER_SOL)
|
219
|
+
))
|
220
|
+
]
|
221
|
+
msg = Message(ixns, self.get_pubkey())
|
222
|
+
latest_blockhash_resp = await self.client.get_latest_blockhash()
|
156
223
|
|
224
|
+
blockhash_str = latest_blockhash_resp.value.blockhash
|
225
|
+
tx = Transaction([self.KEYPAIR], msg, blockhash_str)
|
226
|
+
resp = await self.client.send_transaction(tx)
|
227
|
+
return resp.value
|
157
228
|
|
158
229
|
|
159
230
|
|
160
|
-
if __name__ == "__main__":
|
161
|
-
newKeypair = Keypair()
|
162
|
-
print("New Keypair:", newKeypair)
|
shadowPaySDK/types/EVMcheque.py
CHANGED
@@ -7,20 +7,27 @@ import httpx
|
|
7
7
|
|
8
8
|
|
9
9
|
class Cheque:
|
10
|
-
def __init__(self, w3:Web3,private_key:str, ABI = __SHADOWPAY_ABI__ERC20__, allowed_chains = __ALLOW_CHAINS__):
|
10
|
+
def __init__(self, w3:Optional[Web3] = None,private_key:Optional[str] = None, ABI = __SHADOWPAY_ABI__ERC20__, allowed_chains = __ALLOW_CHAINS__, retunrn_build_tx:bool = False,address:Optional[str] = None):
|
11
11
|
self.w3 = w3
|
12
|
-
|
13
|
-
print(f"allowed chains", allowed_chains)
|
12
|
+
|
14
13
|
self.amount = None
|
15
14
|
self.token = None
|
16
15
|
self.private_key = private_key
|
17
16
|
self.ABI = ABI
|
18
|
-
|
17
|
+
self.address = address
|
18
|
+
self.return_build_tx = retunrn_build_tx
|
19
19
|
self.allowed_chains = allowed_chains
|
20
|
-
if self.
|
21
|
-
|
20
|
+
if self.w3 != None:
|
21
|
+
self.__allow__()
|
22
|
+
|
23
|
+
def get_id(self, tx):
|
24
|
+
if isinstance(tx, str):
|
25
|
+
try:
|
26
|
+
tx = self.w3.eth.wait_for_transaction_receipt(tx)
|
27
|
+
except Exception as e:
|
28
|
+
print(f"Failed to get transaction receipt: {str(e)}")
|
29
|
+
return False
|
22
30
|
|
23
|
-
def __get__id(self, tx):
|
24
31
|
try:
|
25
32
|
logs = self.contract.events.ChequeCreated().process_receipt(tx)
|
26
33
|
cheque_id = logs[0]["args"]["id"]
|
@@ -40,17 +47,15 @@ class Cheque:
|
|
40
47
|
def get_contract_for_chain(self,chain_id: str):
|
41
48
|
c = None
|
42
49
|
for chain in __SHADOWPAY_CONTRACT_ADDRESS__ERC20__ :
|
43
|
-
print(f"Checking chain {chain} against {self.w3.eth.chain_id}")
|
44
50
|
if str(chain) == str(chain_id):
|
45
51
|
c = __SHADOWPAY_CONTRACT_ADDRESS__ERC20__[chain_id]
|
46
|
-
print(f"Contract address: {c}, type {type(c)} ")
|
47
52
|
contract_address = Web3.to_checksum_address(c)
|
48
53
|
contract = self.w3.eth.contract(address=contract_address, abi=__SHADOWPAY_ABI__ERC20__)
|
49
54
|
self.contract = contract
|
50
55
|
return contract
|
51
56
|
raise ValueError(f"Chain {chain_id} is not supported. Supported chains are: {list(__SHADOWPAY_CONTRACT_ADDRESS__ERC20__.keys())}")
|
52
57
|
|
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):
|
58
|
+
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,address:Optional[str] = None):
|
54
59
|
if w3:
|
55
60
|
self.w3 = w3
|
56
61
|
self.get_contract_for_chain(chain_id=chain_id or self.w3.eth.chain_id)
|
@@ -60,38 +65,63 @@ class Cheque:
|
|
60
65
|
self.private_key = private_key
|
61
66
|
if token:
|
62
67
|
self.token = token
|
68
|
+
if address:
|
69
|
+
self.address = address
|
70
|
+
|
63
71
|
def __convert__(self):
|
64
72
|
return self.w3.to_wei(self.amount, 'ether')
|
65
73
|
|
66
74
|
async def InitCheque(self, amount, receiver:list, private_key:Optional[str] = None):
|
67
75
|
if not isinstance(receiver,list):
|
68
76
|
raise ValueError("Receiver must be a list of addresses, [""0x1234...5678", "0x2345...6789""]")
|
77
|
+
|
78
|
+
key = private_key or self.private_key
|
79
|
+
|
80
|
+
if key:
|
81
|
+
address = Web3.to_checksum_address(self.w3.eth.account.from_key(key).address)
|
82
|
+
print("InitCheque", amount, receiver, key)
|
69
83
|
|
84
|
+
elif self.address:
|
85
|
+
address = Web3.to_checksum_address(self.address)
|
86
|
+
else:
|
87
|
+
raise ValueError("No private key or address provided")
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
|
70
93
|
receiver = [Web3.to_checksum_address(addr) for addr in receiver]
|
71
94
|
estimated_gas = self.contract.functions.InitCheque(receiver).estimate_gas({
|
72
|
-
'from':
|
95
|
+
'from': address,
|
73
96
|
'value': self.w3.to_wei(amount, 'ether'),
|
74
97
|
'gasPrice': self.w3.eth.gas_price
|
75
98
|
})
|
76
99
|
txn = self.contract.functions.InitCheque(receiver).build_transaction({
|
77
|
-
'from':
|
100
|
+
'from': address,
|
78
101
|
'value': self.w3.to_wei(amount, 'ether'),
|
79
102
|
'nonce': self.w3.eth.get_transaction_count(
|
80
|
-
|
103
|
+
address
|
81
104
|
),
|
82
105
|
'gas': estimated_gas,
|
83
106
|
'gasPrice': self.w3.eth.gas_price,
|
84
107
|
'chainId': self.w3.eth.chain_id
|
85
108
|
})
|
86
|
-
|
109
|
+
if self.return_build_tx:
|
110
|
+
return {
|
111
|
+
"build_tx": txn
|
112
|
+
}
|
113
|
+
|
114
|
+
signed_txn = self.w3.eth.account.sign_transaction(txn, key)
|
87
115
|
txn_hash = self.w3.eth.send_raw_transaction(signed_txn.raw_transaction)
|
88
116
|
txn_receipt = self.w3.eth.wait_for_transaction_receipt(txn_hash)
|
89
117
|
insert_to_dn = None
|
90
|
-
logs = self.
|
118
|
+
logs = self.get_id(txn_receipt)
|
91
119
|
if logs:
|
92
120
|
cheque_id = logs
|
93
121
|
else:
|
94
122
|
cheque_id = None
|
123
|
+
if txn_receipt.status != 1:
|
124
|
+
return False
|
95
125
|
return {
|
96
126
|
"hash": txn_hash.hex(),
|
97
127
|
"chequeId": cheque_id,
|
@@ -110,49 +140,63 @@ class Cheque:
|
|
110
140
|
|
111
141
|
|
112
142
|
account = self.w3.eth.account.from_key(private_key)
|
113
|
-
sender_address = account.address
|
143
|
+
sender_address = account.address or self.address
|
114
144
|
|
115
145
|
|
116
|
-
|
117
|
-
nonce = self.eth.get_transaction_count(sender_address)
|
146
|
+
nonce = self.w3.eth.get_transaction_count(sender_address)
|
118
147
|
|
119
148
|
txn = self.contract.functions.CashOutCheque(
|
120
149
|
Web3.to_bytes(hexstr=cheque_id)).build_transaction({
|
121
150
|
'from': sender_address,
|
122
151
|
'nonce': nonce,
|
123
|
-
'gas': 300_000,
|
152
|
+
'gas': 300_000,
|
124
153
|
'gasPrice': self.w3.to_wei('5', 'gwei'),
|
125
154
|
})
|
155
|
+
if self.return_build_tx:
|
156
|
+
return {
|
157
|
+
"build_tx": txn
|
158
|
+
}
|
126
159
|
|
127
|
-
# подписываем
|
128
160
|
signed_txn = self.w3.eth.account.sign_transaction(txn, private_key=private_key)
|
129
161
|
|
130
|
-
|
162
|
+
|
131
163
|
tx_hash = self.w3.eth.send_raw_transaction(signed_txn.raw_transaction)
|
132
164
|
|
133
|
-
print(f"⏳ Transaction sent: {tx_hash.hex()}")
|
134
165
|
receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash)
|
135
|
-
|
136
|
-
|
166
|
+
if receipt.status != 1:
|
167
|
+
return False
|
168
|
+
return {
|
169
|
+
"hash": tx_hash.hex()
|
170
|
+
}
|
137
171
|
|
138
172
|
async def InitTokenCheque(self, token_address:str, amount, reciver:str, private_key:Optional[str] = None):
|
139
|
-
|
173
|
+
key = private_key or self.private_key
|
174
|
+
|
175
|
+
if key:
|
176
|
+
address = Web3.to_checksum_address(self.w3.eth.account.from_key(key).address)
|
177
|
+
|
178
|
+
elif self.address:
|
179
|
+
address = Web3.to_checksum_address(self.address)
|
180
|
+
else:
|
181
|
+
raise ValueError("No private key or address provided")
|
182
|
+
|
183
|
+
|
184
|
+
|
185
|
+
|
140
186
|
|
141
187
|
erc20 = shadowPaySDK.ERC20Token(w3=self.w3)
|
142
188
|
erc20.set_params(token_address=token_address)
|
143
|
-
|
144
|
-
|
189
|
+
decimals = erc20.get_decimals()
|
190
|
+
erc20.allowance(
|
145
191
|
spender=self.contract.address,
|
146
|
-
|
192
|
+
owner=address,
|
147
193
|
)
|
148
|
-
print(f"Ensure allowance: {ensure_allowance}")
|
149
|
-
decimals = erc20.get_decimals()
|
150
194
|
estimated_gas = self.contract.functions.InitTokenCheque(
|
151
195
|
Web3.to_checksum_address(token_address),
|
152
196
|
int(amount * (10 ** decimals)),
|
153
197
|
Web3.to_checksum_address(reciver)
|
154
198
|
).estimate_gas({
|
155
|
-
'from':
|
199
|
+
'from': address,
|
156
200
|
'gasPrice': self.w3.eth.gas_price
|
157
201
|
})
|
158
202
|
txn = self.contract.functions.InitTokenCheque(
|
@@ -160,21 +204,26 @@ class Cheque:
|
|
160
204
|
int(amount * (10 ** decimals)),
|
161
205
|
Web3.to_checksum_address(reciver)
|
162
206
|
).build_transaction({
|
163
|
-
'from':
|
164
|
-
'nonce': self.w3.eth.get_transaction_count(
|
207
|
+
'from': address,
|
208
|
+
'nonce': self.w3.eth.get_transaction_count(address),
|
165
209
|
'gas': estimated_gas,
|
166
210
|
'gasPrice': self.w3.eth.gas_price
|
167
211
|
})
|
168
|
-
|
212
|
+
if self.return_build_tx:
|
213
|
+
return {
|
214
|
+
"build_tx": txn
|
215
|
+
}
|
216
|
+
signed_txn = self.w3.eth.account.sign_transaction(txn, key)
|
169
217
|
txn_hash = self.w3.eth.send_raw_transaction(signed_txn.raw_transaction)
|
170
218
|
txn_receipt = self.w3.eth.wait_for_transaction_receipt(txn_hash)
|
171
219
|
|
172
|
-
logs = self.
|
220
|
+
logs = self.get_id(txn_receipt)
|
173
221
|
if logs:
|
174
222
|
cheque_id = logs
|
175
223
|
else:
|
176
224
|
cheque_id = None
|
177
|
-
|
225
|
+
if txn_receipt.status != 1:
|
226
|
+
return False
|
178
227
|
return {
|
179
228
|
"hash": txn_hash.hex(),
|
180
229
|
"chequeId": cheque_id,
|
@@ -188,46 +237,51 @@ class Cheque:
|
|
188
237
|
|
189
238
|
|
190
239
|
|
191
|
-
# Строим транзакцию
|
192
240
|
estimated_gas = self.contract.functions.CashOutTokenCheque(
|
193
|
-
Web3.to_bytes(hexstr=cheque_id)
|
241
|
+
Web3.to_bytes(hexstr=cheque_id)
|
194
242
|
).estimate_gas({
|
195
|
-
'from': account.address,
|
243
|
+
'from': account.address or self.address,
|
196
244
|
'gasPrice': self.w3.eth.gas_price
|
197
245
|
})
|
198
246
|
txn = self.contract.functions.CashOutTokenCheque(
|
199
247
|
Web3.to_bytes(hexstr=cheque_id)
|
200
248
|
).build_transaction({
|
201
|
-
'from': account.address,
|
202
|
-
'nonce': self.w3.eth.get_transaction_count(account.address),
|
249
|
+
'from': account.address or self.address,
|
250
|
+
'nonce': self.w3.eth.get_transaction_count(account.address or self.address),
|
203
251
|
'gas': estimated_gas,
|
204
252
|
'gasPrice': self.w3.eth.gas_price,
|
205
253
|
})
|
254
|
+
if self.return_build_tx:
|
255
|
+
return {
|
256
|
+
"build_tx": txn
|
257
|
+
}
|
206
258
|
|
207
|
-
# Подписываем и отправляем транзакцию
|
208
259
|
signed_txn = self.w3.eth.account.sign_transaction(txn, private_key=private_key)
|
209
260
|
tx_hash = self.w3.eth.send_raw_transaction(signed_txn.raw_transaction)
|
210
261
|
|
211
|
-
# Получаем подтверждение
|
212
262
|
receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash)
|
213
263
|
|
264
|
+
if receipt.status != 1:
|
265
|
+
return False
|
214
266
|
return {
|
215
267
|
"hash": tx_hash.hex(),
|
216
268
|
"status": receipt.status # 1 = success, 0 = fail
|
217
269
|
}
|
218
270
|
async def InitTokenChequeSwap(self, token_in:str, amount_in,token_out:str, amount_out, reciver:str, private_key:Optional[str] = None):
|
219
|
-
|
271
|
+
key = private_key or self.private_key
|
272
|
+
if key:
|
273
|
+
address = Web3.to_checksum_address(self.w3.eth.account.from_key(key).address)
|
274
|
+
elif self.address:
|
275
|
+
address = Web3.to_checksum_address(self.address)
|
220
276
|
erc20 = shadowPaySDK.ERC20Token(w3=self.w3)
|
221
277
|
erc20.set_params(token_address=token_in)
|
222
|
-
|
223
|
-
private_key=self.private_key,
|
278
|
+
approve = erc20.allowance(
|
224
279
|
spender=self.contract.address,
|
225
|
-
|
226
|
-
token=token_in
|
280
|
+
owner=address,
|
227
281
|
)
|
228
|
-
|
229
|
-
|
230
|
-
token_out_decinals = erc20.get_decimals(
|
282
|
+
decimals = erc20.get_decimals()
|
283
|
+
erc20.set_params(token_address=token_out)
|
284
|
+
token_out_decinals = erc20.get_decimals()
|
231
285
|
estimated_gas = self.contract.functions.InitSwapCheque(
|
232
286
|
Web3.to_checksum_address(reciver),
|
233
287
|
Web3.to_checksum_address(token_in),
|
@@ -235,7 +289,7 @@ class Cheque:
|
|
235
289
|
Web3.to_checksum_address(token_out),
|
236
290
|
int(amount_out * (10 ** token_out_decinals)),
|
237
291
|
).estimate_gas({
|
238
|
-
'from':
|
292
|
+
'from': address,
|
239
293
|
'gasPrice': self.w3.eth.gas_price
|
240
294
|
})
|
241
295
|
txn = self.contract.functions.InitSwapCheque(
|
@@ -245,24 +299,75 @@ class Cheque:
|
|
245
299
|
Web3.to_checksum_address(token_out),
|
246
300
|
int(amount_out * (10 ** token_out_decinals))
|
247
301
|
).build_transaction({
|
248
|
-
'from':
|
249
|
-
'nonce': self.w3.eth.get_transaction_count(
|
302
|
+
'from': address,
|
303
|
+
'nonce': self.w3.eth.get_transaction_count(address),
|
250
304
|
'gas': estimated_gas,
|
251
305
|
'gasPrice': self.w3.eth.gas_price
|
252
306
|
})
|
253
|
-
|
307
|
+
if self.return_build_tx:
|
308
|
+
return {
|
309
|
+
"build_tx": txn
|
310
|
+
}
|
311
|
+
signed_txn = self.w3.eth.account.sign_transaction(txn, key)
|
254
312
|
txn_hash = self.w3.eth.send_raw_transaction(signed_txn.raw_transaction)
|
255
313
|
txn_receipt = self.w3.eth.wait_for_transaction_receipt(txn_hash)
|
256
314
|
|
257
|
-
logs = self.
|
315
|
+
logs = self.get_id(txn_receipt)
|
258
316
|
if logs:
|
259
317
|
cheque_id = logs
|
260
318
|
else:
|
261
319
|
cheque_id = None
|
320
|
+
if txn_receipt.status != 1:
|
321
|
+
return False
|
262
322
|
return {
|
263
323
|
"hash": txn_hash.hex(),
|
264
324
|
"chequeId": cheque_id
|
265
325
|
}
|
326
|
+
|
327
|
+
async def CashOutSwapCheque(self, cheque_id: str, private_key: Optional[str] = None):
|
328
|
+
swapDetail = await self.getSwaoDetail(cheque_id)
|
329
|
+
print(swapDetail)
|
330
|
+
if private_key is None:
|
331
|
+
private_key = self.private_key
|
332
|
+
token_out = swapDetail["tokenOut"]
|
333
|
+
amount_out = swapDetail["amountOut"]
|
334
|
+
erc20 = shadowPaySDK.ERC20Token(w3=self.w3)
|
335
|
+
erc20.set_params(token_address=token_out)
|
336
|
+
encure_allowance = erc20.ensure_allowance(
|
337
|
+
private_key=private_key,
|
338
|
+
spender=self.contract.address,
|
339
|
+
amount=amount_out,
|
340
|
+
)
|
341
|
+
estimated_gas = self.contract.functions.CashOutSwapCheque(
|
342
|
+
Web3.to_bytes(hexstr=cheque_id)
|
343
|
+
).estimate_gas({
|
344
|
+
'from': self.w3.eth.account.from_key(private_key).address,
|
345
|
+
'gasPrice': self.w3.eth.gas_price
|
346
|
+
})
|
347
|
+
swa = self.contract.functions.CashOutSwapCheque(
|
348
|
+
Web3.to_bytes(hexstr=cheque_id)
|
349
|
+
).build_transaction({
|
350
|
+
'from': self.w3.eth.account.from_key(private_key).address,
|
351
|
+
'nonce': self.w3.eth.get_transaction_count(self.w3.eth.account.from_key(private_key).address),
|
352
|
+
'gas': 300_000,
|
353
|
+
'gasPrice': self.w3.eth.gas_price
|
354
|
+
})
|
355
|
+
if self.return_build_tx:
|
356
|
+
return {
|
357
|
+
"build_tx": swa
|
358
|
+
}
|
359
|
+
signed_txn = self.w3.eth.account.sign_transaction(swa, private_key=private_key)
|
360
|
+
tx_hash = self.w3.eth.send_raw_transaction(signed_txn.raw_transaction)
|
361
|
+
receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash)
|
362
|
+
if receipt.status != 1:
|
363
|
+
return False
|
364
|
+
return {
|
365
|
+
"hash": tx_hash.hex(),
|
366
|
+
}
|
367
|
+
|
368
|
+
|
369
|
+
|
370
|
+
|
266
371
|
async def getComunityPool(self):
|
267
372
|
# fee = self.contract.functions.getCollectedFee().call()
|
268
373
|
fee = 50000000000000
|
@@ -274,7 +379,11 @@ class Cheque:
|
|
274
379
|
return self.contract.functions.getTreasery().call()
|
275
380
|
async def getSwaoDetail(self, cheque_id: str):
|
276
381
|
cheque_id_bytes = Web3.to_bytes(hexstr=cheque_id)
|
277
|
-
|
382
|
+
s = self.contract.functions.getSwapDetail(cheque_id_bytes).call()
|
383
|
+
return{
|
384
|
+
"tokenOut": s[0],
|
385
|
+
"amountOut": s[1],
|
386
|
+
}
|
278
387
|
class NFTcheque:
|
279
388
|
def __init__(self, w3:Web3, token:str, amount:int, spender:str):
|
280
389
|
self.w3 = w3
|
@@ -306,20 +415,3 @@ class NFTcheque:
|
|
306
415
|
|
307
416
|
|
308
417
|
|
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
|
shadowPaySDK/types/SOLcheque.py
CHANGED
@@ -1,27 +1,284 @@
|
|
1
1
|
|
2
2
|
import anchorpy
|
3
3
|
from anchorpy import Idl, Provider, Wallet
|
4
|
+
import solders
|
4
5
|
from shadowPaySDK.interface.sol import SOL
|
5
|
-
|
6
|
-
import solana.constants as constants
|
7
|
-
import solana.constants as sol_constants
|
6
|
+
import solders
|
8
7
|
import spl.token.constants as spl_constants
|
8
|
+
from solana.rpc.api import Client
|
9
|
+
|
10
|
+
import asyncio
|
11
|
+
import solana
|
12
|
+
from solana.rpc.async_api import AsyncClient, GetTokenAccountsByOwnerResp
|
13
|
+
from solders.transaction import Transaction
|
14
|
+
from solders.system_program import TransferParams as p
|
15
|
+
from solders.instruction import Instruction, AccountMeta
|
16
|
+
from solders.rpc.config import RpcSendTransactionConfig
|
17
|
+
from solders.message import Message
|
18
|
+
import spl
|
19
|
+
import spl.token
|
20
|
+
import spl.token.constants
|
21
|
+
from spl.token.instructions import get_associated_token_address, create_associated_token_account,TransferCheckedParams, transfer_checked, transfer, close_account, TransferParams
|
22
|
+
from solders.system_program import transfer as ts
|
23
|
+
from solders.system_program import TransferParams as tsf
|
24
|
+
from solders.pubkey import Pubkey
|
25
|
+
import os
|
26
|
+
from spl.token.constants import TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID
|
27
|
+
from solana.rpc.types import TxOpts, TokenAccountOpts
|
28
|
+
from solana.rpc.types import TxOpts
|
29
|
+
import solders
|
30
|
+
from solders.message import Message
|
31
|
+
from solders.system_program import create_account,CreateAccountParams
|
32
|
+
|
33
|
+
# from solders.pubkey import Pubkey
|
34
|
+
# from solders.keypair import Keypair
|
35
|
+
# from solders.signature import Signature
|
36
|
+
# from solders.transaction import Transaction
|
37
|
+
from spl.token.async_client import AsyncToken
|
38
|
+
|
39
|
+
|
40
|
+
from solana.rpc.commitment import Confirmed
|
41
|
+
from solana.rpc.async_api import AsyncClient
|
42
|
+
import anchorpy
|
43
|
+
from anchorpy import Provider, Wallet, Idl
|
44
|
+
import pprint
|
45
|
+
import httpx
|
46
|
+
import base64
|
47
|
+
import re
|
48
|
+
import struct
|
49
|
+
from shadowPaySDK.const import LAMPORTS_PER_SOL, PROGRAM_ID, CONFIG_PDA
|
9
50
|
|
10
51
|
|
11
52
|
|
12
53
|
class SOLCheque:
|
13
|
-
def __init__(self, rpc_url: str = "https://api.mainnet-beta.solana.com",
|
54
|
+
def __init__(self, rpc_url: str = "https://api.mainnet-beta.solana.com", key: Wallet = None):
|
14
55
|
self.rpc_url = rpc_url
|
15
|
-
|
16
|
-
|
56
|
+
if key:
|
57
|
+
self.key = solders.keypair.Keypair.from_base58_string(key)
|
58
|
+
self.provider = Client(rpc_url)
|
17
59
|
self.WRAPED_SOL = spl_constants.WRAPPED_SOL_MINT # wrapped SOL token mint address
|
18
60
|
# self.idl = Idl.from_json(sol_interface.Idl) # Load the IDL for the program
|
19
61
|
def get(self, keypair = None):
|
20
|
-
pubkey = SOL.get_pubkey(KEYPAIR=Keypair.from_base58_string(self.keystore))
|
62
|
+
pubkey = SOL.get_pubkey(KEYPAIR=solders.keypair.Keypair.from_base58_string(self.keystore))
|
21
63
|
|
22
64
|
return pubkey
|
23
|
-
|
65
|
+
def get_config(self):
|
66
|
+
program_id = PROGRAM_ID
|
67
|
+
config_pda, _ = Pubkey.find_program_address([b"config"], program_id)
|
68
|
+
|
69
|
+
response = self.provider.get_account_info(config_pda)
|
70
|
+
if response.value is None:
|
71
|
+
print("❌ Config PDA not found.")
|
72
|
+
return None
|
73
|
+
|
74
|
+
# 🧠 У тебя data — это list[int], его нужно превратить в bytes
|
75
|
+
raw = bytes(response.value.data)
|
76
|
+
|
77
|
+
if len(raw) < 89:
|
78
|
+
print("❌ Invalid config data length.")
|
79
|
+
return None
|
80
|
+
|
81
|
+
admin = Pubkey.from_bytes(raw[0:32])
|
82
|
+
treasury = Pubkey.from_bytes(raw[32:64])
|
83
|
+
fee_bps = struct.unpack("<Q", raw[64:72])[0]
|
84
|
+
token_in_bps = struct.unpack("<Q", raw[72:80])[0]
|
85
|
+
token_out_bps = struct.unpack("<Q", raw[80:88])[0]
|
86
|
+
initialized = bool(raw[88])
|
87
|
+
|
88
|
+
|
89
|
+
return {
|
90
|
+
"pda": str(config_pda),
|
91
|
+
"admin": str(admin),
|
92
|
+
"treasury": str(treasury),
|
93
|
+
"fee_bps": fee_bps,
|
94
|
+
"token_in_bps": token_in_bps,
|
95
|
+
"token_out_bps": token_out_bps,
|
96
|
+
"initialized": initialized,
|
97
|
+
}
|
98
|
+
def set_params(self, rpc_url = None, key = None):
|
99
|
+
if rpc_url:
|
100
|
+
self.rpc_url = rpc_url
|
101
|
+
self.provider = Client(rpc_url)
|
102
|
+
if key:
|
103
|
+
self.key = solders.keypair.Keypair.from_base58_string(key)
|
104
|
+
# init_cheque & claim_cheque status on 15.07.2025 work
|
105
|
+
|
106
|
+
def init_cheque(self, cheque_amount, recipient: str, SPACE: int = 100, build_tx: bool = False):
|
107
|
+
"""
|
108
|
+
Initialize a cheque withc the specified amount and recipient.
|
109
|
+
"""
|
110
|
+
# if not self.key:
|
111
|
+
# raise ValueError("Keypair is not set. Please set the keypair before initializing a cheque.")
|
112
|
+
CHEQUE_PDA_SIGNATURE = None
|
113
|
+
CHEQUE_SPACE = SPACE
|
114
|
+
CHEQUE_RENT = self.provider.get_minimum_balance_for_rent_exemption(CHEQUE_SPACE)
|
115
|
+
sol = SOL(
|
116
|
+
KEYPAIR=self.key
|
117
|
+
)
|
118
|
+
payer = self.key
|
119
|
+
pubkey = self.key.pubkey()
|
120
|
+
newAcc = solders.keypair.Keypair()
|
121
|
+
newAccPubkey = newAcc.pubkey()
|
122
|
+
ix_create = create_account(
|
123
|
+
params=CreateAccountParams(
|
124
|
+
from_pubkey=pubkey,
|
125
|
+
to_pubkey=newAccPubkey,
|
126
|
+
lamports=CHEQUE_RENT.value,
|
127
|
+
space=CHEQUE_SPACE,
|
128
|
+
owner=PROGRAM_ID
|
129
|
+
)
|
130
|
+
)
|
131
|
+
recent_blockhash = self.provider.get_latest_blockhash().value.blockhash
|
132
|
+
message = Message(instructions=[ix_create], payer=pubkey)
|
133
|
+
|
134
|
+
t = Transaction(message=message, from_keypairs=[payer, newAcc], recent_blockhash=recent_blockhash)
|
135
|
+
|
136
|
+
r = self.provider.send_transaction(t,opts=TxOpts())
|
137
|
+
CHEQUE_PDA_SIGNATURE = r.value
|
138
|
+
CHEQUE_PDA = newAccPubkey
|
139
|
+
|
140
|
+
|
141
|
+
|
142
|
+
total_lamports = int(cheque_amount * LAMPORTS_PER_SOL)
|
143
|
+
|
144
|
+
|
145
|
+
r = Pubkey.from_string(recipient)
|
146
|
+
|
147
|
+
data = bytes([0]) + bytes(r) + struct.pack("<Q", total_lamports)
|
148
|
+
|
149
|
+
cfg = self.get_config()
|
150
|
+
tresury = cfg["treasury"]
|
151
|
+
instruction = Instruction(
|
152
|
+
program_id=PROGRAM_ID,
|
153
|
+
data=data,
|
154
|
+
accounts=[
|
155
|
+
AccountMeta(pubkey=pubkey, is_signer=True, is_writable=True), # payer
|
156
|
+
AccountMeta(pubkey=CHEQUE_PDA, is_signer=False, is_writable=True), # cheque PDA
|
157
|
+
AccountMeta(pubkey=Pubkey.from_string("11111111111111111111111111111111"), is_signer=False, is_writable=False),
|
158
|
+
AccountMeta(pubkey=Pubkey.from_string(tresury), is_signer=False, is_writable=True), # treasury
|
159
|
+
|
160
|
+
]
|
161
|
+
)
|
162
|
+
|
163
|
+
recent_blockhash = self.provider.get_latest_blockhash().value.blockhash
|
164
|
+
message = Message(instructions=[instruction], payer=pubkey)
|
165
|
+
tx = Transaction(message=message, from_keypairs=[payer], recent_blockhash=recent_blockhash)
|
166
|
+
response = self.provider.send_transaction(tx,opts=TxOpts(skip_preflight=True))
|
167
|
+
confirm = self.provider.confirm_transaction(response.value)
|
168
|
+
|
169
|
+
data = {
|
170
|
+
"cheque_pda": str(CHEQUE_PDA),
|
171
|
+
"signature": str(response.value),
|
172
|
+
"create_signature": str(CHEQUE_PDA_SIGNATURE),
|
173
|
+
"cheque_amount": cheque_amount,
|
174
|
+
"pda_rent_sol": CHEQUE_RENT.value / LAMPORTS_PER_SOL,
|
175
|
+
}
|
176
|
+
return data
|
177
|
+
|
178
|
+
def claim_cheque(self, pda_acc: str ):
|
179
|
+
instruction_data = bytes([1])
|
180
|
+
payer = self.key
|
181
|
+
payer_pubkey = payer.pubkey()
|
182
|
+
cfg = self.get_config()
|
183
|
+
tressary = cfg["treasury"]
|
184
|
+
|
185
|
+
|
186
|
+
ix = Instruction(
|
187
|
+
program_id=PROGRAM_ID,
|
188
|
+
data=instruction_data,
|
189
|
+
accounts = [
|
190
|
+
AccountMeta(pubkey=payer_pubkey, is_signer=True, is_writable=True),
|
191
|
+
AccountMeta(pubkey=Pubkey.from_string(pda_acc), is_signer=False, is_writable=True),
|
192
|
+
AccountMeta(pubkey=CONFIG_PDA[0], is_signer=False, is_writable=True), # rent receiver
|
193
|
+
AccountMeta(pubkey=Pubkey.from_string(tressary), is_signer=False, is_writable=True) # treasury
|
194
|
+
]
|
195
|
+
)
|
196
|
+
|
197
|
+
recent_blockhash = self.provider.get_latest_blockhash().value.blockhash
|
198
|
+
message = Message(instructions=[ix], payer=payer_pubkey)
|
199
|
+
tx = Transaction(message=message, from_keypairs=[payer], recent_blockhash=recent_blockhash)
|
200
|
+
response = self.provider.send_transaction(tx,opts=TxOpts(skip_preflight=True))
|
201
|
+
return {
|
202
|
+
"signature": str(response.value),
|
203
|
+
"pda_account": pda_acc,
|
204
|
+
}
|
205
|
+
|
206
|
+
# init_token_cheque need fix...
|
207
|
+
|
208
|
+
def init_token_cheque(self, token_mint: str, token_amount,token_decimals, recipient: str, treasury: str, CHEQUE_SPACE: int = 105):
|
209
|
+
if not self.key:
|
210
|
+
raise ValueError("Keypair not set")
|
211
|
+
|
212
|
+
payer = self.key
|
213
|
+
payer_pubkey = payer.pubkey()
|
214
|
+
token_mint_pubkey = Pubkey.from_string(token_mint)
|
215
|
+
recipient_pubkey = Pubkey.from_string(recipient)
|
216
|
+
treasury_pubkey = Pubkey.from_string(treasury)
|
217
|
+
|
218
|
+
cheque_acc = solders.keypair.Keypair()
|
219
|
+
cheque_pda = cheque_acc.pubkey()
|
220
|
+
|
221
|
+
rent = self.provider.get_minimum_balance_for_rent_exemption(CHEQUE_SPACE).value
|
222
|
+
|
223
|
+
create_cheque_acc = create_account(
|
224
|
+
CreateAccountParams(
|
225
|
+
from_pubkey=payer_pubkey,
|
226
|
+
to_pubkey=cheque_pda,
|
227
|
+
lamports=rent,
|
228
|
+
space=CHEQUE_SPACE,
|
229
|
+
owner=PROGRAM_ID
|
230
|
+
)
|
231
|
+
)
|
232
|
+
|
233
|
+
tx1 = Transaction(
|
234
|
+
message=Message(instructions=[create_cheque_acc], payer=payer_pubkey),
|
235
|
+
recent_blockhash=self.provider.get_latest_blockhash().value.blockhash,
|
236
|
+
from_keypairs=[payer, cheque_acc]
|
237
|
+
)
|
238
|
+
self.provider.send_transaction(tx1, opts=TxOpts(skip_preflight=True))
|
239
|
+
|
240
|
+
sender_ata = get_associated_token_address(payer_pubkey, token_mint_pubkey)
|
241
|
+
cheque_ata = get_associated_token_address(cheque_pda, token_mint_pubkey)
|
242
|
+
treasury_ata = get_associated_token_address(treasury_pubkey, token_mint_pubkey)
|
243
|
+
|
244
|
+
ix_create_ata = create_associated_token_account(payer_pubkey, cheque_pda, token_mint_pubkey)
|
245
|
+
|
246
|
+
amount = int(token_amount * (10 ** token_decimals))
|
247
|
+
|
248
|
+
|
249
|
+
|
250
|
+
data = bytes([2]) + struct.pack("<Q", amount)
|
251
|
+
|
252
|
+
ix_program = Instruction(
|
253
|
+
program_id=PROGRAM_ID,
|
254
|
+
data=data,
|
255
|
+
accounts=[
|
256
|
+
AccountMeta(payer_pubkey, is_signer=True, is_writable=True),
|
257
|
+
AccountMeta(cheque_pda, is_signer=True, is_writable=True),
|
258
|
+
AccountMeta(token_mint_pubkey, is_signer=False, is_writable=True),
|
259
|
+
AccountMeta(sender_ata, is_signer=False, is_writable=True),
|
260
|
+
AccountMeta(cheque_ata, is_signer=False, is_writable=True),
|
261
|
+
AccountMeta(treasury_ata, is_signer=False, is_writable=True),
|
262
|
+
AccountMeta(Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"), is_signer=False, is_writable=False),
|
263
|
+
]
|
264
|
+
)
|
24
265
|
|
266
|
+
# === 6. Собираем и отправляем всё в одном tx ===
|
267
|
+
print("Accounts (ix_program):")
|
268
|
+
for i, acc in enumerate(ix_program.accounts):
|
269
|
+
print(f"[{i}] {acc.pubkey} | signer={acc.is_signer} | writable={acc.is_writable}")
|
25
270
|
|
271
|
+
tx2 = Transaction(
|
272
|
+
message=Message(instructions=[ix_create_ata, ix_program], payer=payer_pubkey),
|
273
|
+
recent_blockhash=self.provider.get_latest_blockhash().value.blockhash,
|
274
|
+
from_keypairs=[payer, cheque_acc]
|
275
|
+
)
|
26
276
|
|
27
|
-
|
277
|
+
sig = self.provider.send_transaction(tx2, opts=TxOpts(skip_preflight=True)).value
|
278
|
+
return {
|
279
|
+
"cheque_pda": str(cheque_pda),
|
280
|
+
"signature": str(sig),
|
281
|
+
"amount": token_amount
|
282
|
+
}
|
283
|
+
def claim_token_cheque(self, pda_acc: str):
|
284
|
+
pass
|
@@ -1,8 +1,8 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: shadowPaySDK
|
3
|
-
Version:
|
3
|
+
Version: 16.7.2025
|
4
4
|
Summary: ShadowPay SDK for ERC20/ERC721 and P2P smart contract interaction
|
5
|
-
Author: dazarius_
|
5
|
+
Author: dazay(aka dazarius_)
|
6
6
|
Author-email: your@email.com
|
7
7
|
License: MIT
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
@@ -11,10 +11,10 @@ Classifier: Operating System :: OS Independent
|
|
11
11
|
Requires-Python: >=3.9
|
12
12
|
Description-Content-Type: text/markdown
|
13
13
|
License-File: LICENSE
|
14
|
-
Requires-Dist: web3
|
15
|
-
Requires-Dist: requests
|
16
|
-
Requires-Dist: solana
|
17
|
-
Requires-Dist: anchorpy
|
14
|
+
Requires-Dist: web3
|
15
|
+
Requires-Dist: requests
|
16
|
+
Requires-Dist: solana
|
17
|
+
Requires-Dist: anchorpy
|
18
18
|
Requires-Dist: solders
|
19
19
|
Requires-Dist: httpx==0.28.1
|
20
20
|
Dynamic: author
|
@@ -28,11 +28,24 @@ Dynamic: requires-dist
|
|
28
28
|
Dynamic: requires-python
|
29
29
|
Dynamic: summary
|
30
30
|
|
31
|
-
#
|
31
|
+
# shadowPaySdk
|
32
32
|
|
33
33
|
```bash
|
34
34
|
pip3 install shadowPaySDK
|
35
|
+
pip3 install --break-system-packages git+https://github.com/dazarius/SDK.git
|
35
36
|
```
|
37
|
+
```example to use cheque
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
import shadowPaySDK
|
44
|
+
|
45
|
+
|
46
|
+
EVMcheque = shadowPaySDK.Cheque(
|
47
|
+
retunrn_build_tx=True
|
48
|
+
)
|
36
49
|
|
37
50
|
|
38
51
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
shadowPaySDK/__init__.py,sha256=CMwAuP_6hJN-WueU-XlTNta9Oyd28sFo8OojdgD_pxA,681
|
2
|
+
shadowPaySDK/api.py,sha256=cv5Z171cOh-Idi-lMA4AORzeGDPPrk8BCQ9e5V9MAaM,1461
|
3
|
+
shadowPaySDK/const.py,sha256=dIifSDi2SEW7W3e-Z1nG3TwpAqPNnXvnFipGP0cgPwE,10318
|
4
|
+
shadowPaySDK/interface/__init__.py,sha256=ggSZCV22udnzXm_Wv_3x6VN3hNIAEiwgwHZc2Jwc688,146
|
5
|
+
shadowPaySDK/interface/erc20.py,sha256=7p8eU5LzhI2MsH80PZhq6IRhbfMGlNYucGl3OtyS9SI,4669
|
6
|
+
shadowPaySDK/interface/erc721.py,sha256=4AlWfDjrvl85wFocnN93j-oM54kTsLLwv9SdtcLj4eM,3094
|
7
|
+
shadowPaySDK/interface/sol.py,sha256=TDp62OtQkR8Wy9I4UBVmL_K_FQeMVS--Lojgbvq5T2E,8146
|
8
|
+
shadowPaySDK/types/EVMcheque.py,sha256=8M1EzpZGqf4uidrd9yDKiR7BvIl85p93A_9AMZtshSs,14570
|
9
|
+
shadowPaySDK/types/SOLcheque.py,sha256=h1u-VaIhdb5hFWScdePCQDeDhIyyFhKgtZWmZ8vckh4,11991
|
10
|
+
shadowPaySDK/types/__init__.py,sha256=sG6pNZfKGvENXqsnv6MrQtKrJ898fAXkMvAZY1k1-Qg,97
|
11
|
+
shadowPaySDK/utils/__init__.py,sha256=aja3iYO4rT-ptMM-pzw0GRFTziBdXdcEi-4kE84zH64,61
|
12
|
+
shadowPaySDK/utils/utils.py,sha256=g4bGvLDdjhNGsAj1eaZnNWFNaiN-cVhhM-5PrnG5aIQ,720
|
13
|
+
shadowpaysdk-16.7.2025.dist-info/licenses/LICENSE,sha256=EG13vNmyBfkG3oKj40oOYfUGLKko8OouU6PfO6MlAk4,1066
|
14
|
+
shadowpaysdk-16.7.2025.dist-info/METADATA,sha256=tQhhhmL8EhfnqO_BkjBfAGFmKVccigApYJaVNJ8wZL8,1044
|
15
|
+
shadowpaysdk-16.7.2025.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
16
|
+
shadowpaysdk-16.7.2025.dist-info/top_level.txt,sha256=RSJc73GEf31NMdZp9KovEduzfhm10eQ2t5GTZ44aN1U,13
|
17
|
+
shadowpaysdk-16.7.2025.dist-info/RECORD,,
|
@@ -1,17 +0,0 @@
|
|
1
|
-
shadowPaySDK/__init__.py,sha256=f3O3u7UX-WTEuy1DPS6vQ8w672nzR1ZbVMu8hciqxM8,821
|
2
|
-
shadowPaySDK/api.py,sha256=cv5Z171cOh-Idi-lMA4AORzeGDPPrk8BCQ9e5V9MAaM,1461
|
3
|
-
shadowPaySDK/const.py,sha256=WC560zlT9MlG9QKlJb8Ww6ITfL4xR6vRH4kcGzVHFRI,9893
|
4
|
-
shadowPaySDK/interface/__init__.py,sha256=QceU3dWteSgwvMnR3JDVdmS8OgdRPjvl9JzRs7IsA74,152
|
5
|
-
shadowPaySDK/interface/erc20.py,sha256=rsdfjIrPNxC_xHbUT9FQbNhURdIqZHcylxTbskPHu1k,4453
|
6
|
-
shadowPaySDK/interface/erc721.py,sha256=4AlWfDjrvl85wFocnN93j-oM54kTsLLwv9SdtcLj4eM,3094
|
7
|
-
shadowPaySDK/interface/sol.py,sha256=xgJZsg4xE-_dRctGUW_mHuGj_o_0OlKNp4Gr7IXvTEc,5586
|
8
|
-
shadowPaySDK/types/EVMcheque.py,sha256=lmPvHlt-ERkaYx2DTYwGmbF_TI1B_ZTT3G_FIQPBm_o,12466
|
9
|
-
shadowPaySDK/types/SOLcheque.py,sha256=gmivsCK4hm_6pzQ9whPGuQ_f7qfcUfiJfQgb5ZsJYDo,884
|
10
|
-
shadowPaySDK/types/__init__.py,sha256=sG6pNZfKGvENXqsnv6MrQtKrJ898fAXkMvAZY1k1-Qg,97
|
11
|
-
shadowPaySDK/utils/__init__.py,sha256=aja3iYO4rT-ptMM-pzw0GRFTziBdXdcEi-4kE84zH64,61
|
12
|
-
shadowPaySDK/utils/utils.py,sha256=g4bGvLDdjhNGsAj1eaZnNWFNaiN-cVhhM-5PrnG5aIQ,720
|
13
|
-
shadowpaysdk-0.2.1.dist-info/licenses/LICENSE,sha256=EG13vNmyBfkG3oKj40oOYfUGLKko8OouU6PfO6MlAk4,1066
|
14
|
-
shadowpaysdk-0.2.1.dist-info/METADATA,sha256=oVHKTeuCSJ64v1EKXBhslX7U97X2VP68Cdgpn9LWwCw,868
|
15
|
-
shadowpaysdk-0.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
16
|
-
shadowpaysdk-0.2.1.dist-info/top_level.txt,sha256=RSJc73GEf31NMdZp9KovEduzfhm10eQ2t5GTZ44aN1U,13
|
17
|
-
shadowpaysdk-0.2.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|