ECDSA-secp256k1 signatures

Use black-box signatures to sign any ECDSA-secp256k1 payload and enable support for chains that Fordefi does not yet support.

When certain chains are not yet supported, Blackbox signing allows you to add a chain where you will need to manage the blockchain integration and leverage Fordefi's MPC signing capabilities.

Examples

The following sample shows how to sign an transaction using a blackbox secp256k1 vault. The request should be inside the body, as demonstrated here.

import base64
import datetime
import hashlib
import ecdsa
import json
import requests

from eth_account._utils.legacy_transactions import serializable_unsigned_transaction_from_dict, encode_transaction


chain_id = 1  # mainnet

# Build the signature request
transaction_dict = {
    'to': '0x95524e2Ab866D3615F81C6921C6A8fb6e85fA823',
    'value': 1,
    'gas': 21000,
    'gasPrice': 500000000,
    'nonce': 0,
    'chainId': chain_id,
}

unsigned_transaction = serializable_unsigned_transaction_from_dict(transaction_dict)
payload_encoded = base64.b64encode(unsigned_transaction.hash()).decode()

request_json = {
    "vault_id": vault_id,
    "signer_type": "api_signer",
    "type": "black_box_signature",
    "details": {
        "format": "hash_binary",
        "hash_binary": payload_encoded,
    },
}

request_body = json.dumps(request_json)
private_key_file = "private.pem"
timestamp = datetime.datetime.now().strftime("%s")
payload = f"/api/v1/transactions|{timestamp}|{request_body}"

with open(private_key_file, "r") as f:
    signing_key = ecdsa.SigningKey.from_pem(f.read())

signature = signing_key.sign(data=payload.encode(), hashfunc=hashlib.sha256, sigencode=ecdsa.util.sigencode_der)

resp_tx = requests.post(
    f"https://{gateway_host}/api/v1/transactions",
    headers={
        "Authorization": f"Bearer {access_token}",
        "x-signature": base64.b64encode(signature),
        "x-timestamp": timestamp.encode(),
    },
    data=request_body,
).json()
transaction_id = resp_tx["id"]

# Obtain the signature result
signed_transaction = requests.get(
    f"https://{gateway_host}/api/v1/transactions/{transaction_id}",
    headers={
        "Authorization": f"Bearer {access_token}",
    }
).json()

r = int(signed_transaction["details"]["signature"]["r"], 16)
s = int(signed_transaction["details"]["signature"]["s"], 16)
v = signed_transaction["details"]["signature"]["v"] + 35 + 2 * chain_id

encoded_transaction = encode_transaction(unsigned_transaction, vrs=(v, r, s))
hex_to_send = "0x" + encoded_transaction.hex()