Skip to content

Instantly share code, notes, and snippets.

@olegpetroveth
Last active August 7, 2024 16:58
Show Gist options
  • Save olegpetroveth/30bd051e40bf8f557521a575ed55696e to your computer and use it in GitHub Desktop.
Save olegpetroveth/30bd051e40bf8f557521a575ed55696e to your computer and use it in GitHub Desktop.
Ledger Protobuf
syntax = "proto3";
package ledger_swap;
enum ExtraDataParsingMode {
NATIVE = 0;
EVM_CALLDATA = 1;
OP_RETURN = 2;
}
message NewTransactionResponse {
string payin_address = 1;
string payin_extra_id = 2;
string refund_address = 3;
string refund_extra_id = 4;
string payout_address = 5;
string payout_extra_id = 6;
string currency_from = 7;
string currency_to = 8;
bytes amount_to_provider = 9;
bytes amount_to_wallet = 10;
string device_transaction_id = 11;
bytes device_transaction_id_ng = 12;
bytes payin_extra_data = 13;
}
// =:ETH.USDC-B48:0xFD74b46Fbf014342505628ed43820F03E995dC35:1335183482296:tr:0
// 3D 3A 45 54 48 2E 55 53 44 43 2D 42 34 38 3A 30 78 46 44 37 34 62 34 36 46 62 66 30 31 34 33 34 32 35 30 35 36 32 38 65 64 34 33 38 32 30 46 30 33 45 39 39 35 64 43 33 35 3A 31 33 33 35 31 38 33 34 38 32 32 39 36 3A 74 72 3A 30
// then add 0x01 for prefix
// 01 3D 3A 45 54 48 2E 55 53 44 43 2D 42 34 38 3A 30 78 46 44 37 34 62 34 36 46 62 66 30 31 34 33 34 32 35 30 35 36 32 38 65 64 34 33 38 32 30 46 30 33 45 39 39 35 64 43 33 35 3A 31 33 33 35 31 38 3A 34 38 32 32 39 36 3A 74 72 3A 30
import path from "path";
import type { LedgerMessageProtobuf } from "@thorswap/models";
import * as jose from "jose";
import * as protobuf from "protobufjs";
import { ErrorCode, SwapKitError } from "@thorswap/api-error";
import { logger } from "@thorswap/logger";
import { env } from "./env.mjs";
export const signLedgerMessage = async (
message: LedgerMessageProtobuf,
): Promise<{
payload: string;
signature: string;
}> => {
try {
const ecPrivateKey = await jose.importPKCS8(env.LEDGER_PRIVATE_KEY, "ES256");
// generateKeyPair();
// const keyPair = await _generateKeyPair();
// await _printPrivateKeyPKCS8(keyPair.privateKey);
// await _printPublicKeySPKI(keyPair.publicKey);
// return;
if (!CryptoKey) {
throw new SwapKitError({
code: ErrorCode.ledgerSignFailed,
args: ["Failed to import private key"],
});
}
const root = await new protobuf.Root().load(
path.join(__dirname, "ledger_swap_response.proto"),
{
keepCase: true,
},
);
const protobufMessageType = root.lookupType("NewTransactionResponse");
const errMsg = protobufMessageType.verify(message);
if (errMsg) {
throw new SwapKitError({
code: ErrorCode.ledgerSignFailed,
args: [errMsg],
});
}
const protoMessage = protobufMessageType.fromObject(message);
const byteArray = protobufMessageType.encode(protoMessage).finish();
const buffer = Buffer.from(byteArray);
const payloadBase64 = buffer.toString("base64url");
const jws = await new jose.FlattenedSign(new TextEncoder().encode(payloadBase64))
.setProtectedHeader({ alg: "ES256" })
.sign(ecPrivateKey);
return {
payload: payloadBase64,
signature: jws.signature,
};
} catch (e) {
logger.error(e);
return {
payload: "",
signature: "",
};
}
};
// async function _generateKeyPair() {
// const { publicKey, privateKey } = await jose.generateKeyPair("ES256", {
// extractable: true,
// });
// return { publicKey, privateKey };
// }
// async function _printPrivateKeyPKCS8(privateKey: jose.KeyLike) {
// const pkcs8 = await jose.exportPKCS8(privateKey);
// console.log("PKCS8 Private Key:", pkcs8);
// }
// async function _printPublicKeySPKI(publicKey: jose.KeyLike) {
// const spki = await jose.exportSPKI(publicKey);
// console.log("SPKI Public Key:", spki);
// }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment