This is the error that I receive whenever I try to execute the script
(node:18654) UnhandledPromiseRejectionWarning: Error: Network request error. Received status 400: TransactionPool.Remember: transaction UCZU3QSWKMIPOCSDWM3CPQHJAMZOWV3HJ[quote="fabrice, post:23, topic:7300, full:true"]
Can you provide the message/signature/signer you have been testing the script on?
Have you tested the message/signature/signer are all working properly on Ethereum?
[/quote]
35OYOU2VZLYZWQUMNGQ: logic eval error: assert failed pc=246. Details: pc=246, opcodes=pushint 65
==
assert
This is what my entire code looks like:
from pyteal import *
# has_value = Keccak256 message hash
# signature = eth generated signature from signer
signer = Bytes("signer")
hash = Bytes("hash")
signature = Bytes("signature")
def approval_program():
@Subroutine(TealType.bytes)
def eth_ecdsa_recover(hash_value, signature):
# """
# Equivalent of OpenZeppelin ECDSA.recover for long 65-byte Ethereum signatures
# https://docs.openzeppelin.com/contracts/2.x/api/cryptography#ECDSA-recover-bytes32-bytes-
# Short 64-byte Ethereum signatures require some changes to the code
# Return a 20-byte Ethereum address
# Note: Unless compatibility with Ethereum or another system is necessary, we highly recommend using
# ed25519_verify instead of ecdsa on Algorand
# WARNING: This code has NOT been audited
# DO NOT USE IN PRODUCTION
# """
opup = OpUp(OpUpMode.OnCall) # we need more budget to be able to run
r = Extract(signature, Int(0), Int(32))
s = Extract(signature, Int(32), Int(32))
# The recovery ID is shifted by 27 on Ethereum
# For non-Ethereum signatures, remove the -27 on the line below
v = Btoi(Extract(signature, Int(64), Int(1))) - Int(27)
return Seq(
Assert(Len(signature) == Int(65)),
Assert(Len(hash_value) == Int(32)),
opup.ensure_budget(Int(2500)), # need 2000 for EcdsaRecover, adding a bit more for margin
# The following two asserts are to prevent malleability
# like in
# https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fbf494511fd522b931f7f92e2df87d671ea8b0b/contracts/utils/cryptography/ECDSA.sol#L153
Assert(BytesLe(s, Bytes("base16", "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0"))),
Assert(Or(v == Int(0), v == Int(1))),
EcdsaRecover(EcdsaCurve.Secp256k1, hash_value, v, r, s).outputReducer(
# Ethereum concatenate the x and y part of the public key
# and then applies Keccak256 and take the last 20 bytes
lambda x, y: Extract(Keccak256(Concat(x, y)), Int(12), Int(20))
)
)
# CONSTRUCTOR
hash = Txn.application_args[0]
on_creation = Seq(
Assert(Global.group_size() == Int(1)),
App.globalPut(hash, hash),
Approve(),
)
hash = Bytes("fc0b3a47ab582027c585043ccaa62b0800f38f061cd454ae7e28897a7cf4397b")
signature = Bytes("5272dc4f0e7fdb721d08bce261b3e3fb7fc0315b7ddc8fd4b46e8ca0298c705d5077c1a1ccc488f4f4516eaf0f149f713caba91b9e7e1e9d9d0788d0298577751c")
on_ecdsa_recover = Seq([
App.globalPut(hash, hash),
App.globalPut(signer, eth_ecdsa_recover(hash, signature)),
Approve(),
])
on_call_method = Txn.application_args[0]
on_call = Cond(
# Owner Only operations
[on_call_method == Bytes("ecdsa-recover"), on_ecdsa_recover],
)
on_delete = Seq([
Approve(),
])
on_update = Seq([
Reject(),
])
program = Cond(
[Txn.application_id() == Int(0), on_creation],
# All General Application calls will be routed here.
[Txn.on_completion() == OnComplete.NoOp, on_call],
# Reject DELETE and UPDATE Application Calls.
[Txn.on_completion() == OnComplete.UpdateApplication, on_update],
[Txn.on_completion() == OnComplete.DeleteApplication, on_delete]
)
return compileTeal(program, Mode.Application, version=6)
print(approval_program())