I'm trying to reproduce a signature that a contract verifies but I'm unable to do it on web3py. To verify I'm producing a signature correctly I'm going to look at an already produced signature and verify that the address is correct. First here's my code:
hash = Web3.solidity_keccak(['address', 'uint256', 'uint256', 'uint256'], ["0xf7FA3C8C9Ba3FfCFA1d5f0ca5C9294Afd5970aE7", 1, 59144, 1])
message = defunct_hash_message(hash)
address = w3.eth.account._recover_hash(message, signature=HexBytes("0x599f3172abf3bf5029ee5ea53b5119fa2c9d5de3fa434fd81d46209fb0ab1d230a6c5a0946b59942f94e1b352d325db1bf938a608eb13cbc89ce7184e2d6112b1c"))
print(address)
The output is 0x784aD8676Ade4DEE288fd3f36e2F2EbDfdF70765
but should be 0xf7FA3C8C9Ba3FfCFA1d5f0ca5C9294Afd5970aE7
This is the contract and specifically, I'm looking at newTicket
function. Specifically if you look at the code here, LotteryMaster.sol#126
you can see this is being done in solidity:
keccak256(
abi.encodePacked(to, txHashes.length, block.chainid, sessionIdx))
); // include session index so the signature only affect only for this session
require(isValidSignature(toAddressHash, _signature), "Mismatch signature.");
If you look at this successful transaction here it has the full signature. Now I want to be able to recover the address like they do in the code. But for that I need to hash the message correctly. If you look at their code you can determine the message parameters by looking at the transaction itself, and so should be able to create the hash that would return the address using the signature. But I can't seem to do that. What am I doing wrong?
EDIT
Another example using an open private key: Take a look at this TX. The code if you go according to the example would be:
private_key = b"\xb2\\}\xb3\x1f\xee\xd9\x12''\xbf\t9\xdcv\x9a\x96VK-\xe4\xc4rm\x03[6\xec\xf1\xe5\xb3d"
wallet_address = '0x5ce9454909639D2D17A3F753ce7d93fa0b9aB12E'
_hash = w3.keccak(encode_packed(['address', 'uint256', 'uint256'], [wallet_address, 113, 200]))
signer = w3.eth.account.from_key(private_key)
signed = signer.signHash(_hash.hex())
print(signed)
r = requests.post('https://ape.ankr.com/api/v2/linea/getSign', json={'address': wallet_address, 'boxId': 113, 'continue': True}).json()
print(r['data']['sign'])
The above two don't match. The latter api is just a helper function that produces the same signature that is verified on the smart contract. As you can see I don't pass a private key, so the API can't sign it, but it is verified on the smart contract. I'm confused as to how it works.