Skip to content

Commit

Permalink
[TS SDK] Feature: Add account overload to signMessage (#4250)
Browse files Browse the repository at this point in the history
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR enhances the `signMessage` function in the `thirdweb` package by adding support to pass an account for signing messages, in addition to a private key.

### Detailed summary
- Added overload to `signMessage` to accept an account for signing messages
- Updated `signMessage` function to handle both private key and account options
- Updated tests to cover new account signing functionality

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
  • Loading branch information
gregfromstl committed Aug 23, 2024
1 parent 44e8e7b commit 41fbdaf
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 59 deletions.
13 changes: 13 additions & 0 deletions .changeset/fifty-lobsters-draw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"thirdweb": patch
---

Add overload to `signMessage` to pass an account rather than a private key

```ts
import { signMessage } from "thirdweb/utils";
await signMessage({
message: "Hello, world!",
account
});
```
128 changes: 78 additions & 50 deletions packages/thirdweb/src/utils/signatures/sign-message.test.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,85 @@
import { expect, test } from "vitest";
import { describe, expect, test } from "vitest";

import { ANVIL_PKEY_A } from "~test/test-wallets.js";
import { ANVIL_PKEY_A, TEST_ACCOUNT_A } from "~test/test-wallets.js";
import { signMessage } from "./sign-message.js";

test("default", async () => {
expect(
signMessage({
describe("signMessage", async () => {
test("privateKey", async () => {
expect(
signMessage({
message: "hello world",
privateKey: ANVIL_PKEY_A,
}),
).toMatchInlineSnapshot(
'"0xa461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b"',
);

expect(
signMessage({
message: "🤯",
privateKey: ANVIL_PKEY_A,
}),
).toMatchInlineSnapshot(
'"0xc0cd7599731c37aa4c0815a89dc8dcb4ce479f83df7ee8ffc606a9ef29323e814b54bb8935b56e7c690f1ee4c6290da5c2f6df6fc3443fbe96bb1846a2c4fefc1c"',
);

expect(
signMessage({
message: "0x787037Ba5b7eA8a8737627FfB67d35FdCaAd9A18",
privateKey: ANVIL_PKEY_A,
}),
).toMatchInlineSnapshot(
'"0x151436da0ef734f06ae71f4b907a062fa5683b40af4221e86dfe5f2fc9f09ffa40c90fee4a0e48311506b84dc6f20e513dc4dc434f0f70a03af6ff3e22c7b7591c"',
);
});

test("raw", async () => {
expect(
signMessage({
message: { raw: "0x68656c6c6f20776f726c64" },
privateKey: ANVIL_PKEY_A,
}),
).toMatchInlineSnapshot(
'"0xa461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b"',
);

expect(
signMessage({
message: {
raw: Uint8Array.from([
104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100,
]),
},
privateKey: ANVIL_PKEY_A,
}),
).toMatchInlineSnapshot(
'"0xa461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b"',
);
});

test("account", async () => {
const basicSignature = await signMessage({
message: "hello world",
privateKey: ANVIL_PKEY_A,
}),
).toMatchInlineSnapshot(
'"0xa461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b"',
);

expect(
signMessage({
account: TEST_ACCOUNT_A,
});
expect(basicSignature).toMatchInlineSnapshot(
'"0xa461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b"',
);

const emojiSignature = await signMessage({
message: "🤯",
privateKey: ANVIL_PKEY_A,
}),
).toMatchInlineSnapshot(
'"0xc0cd7599731c37aa4c0815a89dc8dcb4ce479f83df7ee8ffc606a9ef29323e814b54bb8935b56e7c690f1ee4c6290da5c2f6df6fc3443fbe96bb1846a2c4fefc1c"',
);

expect(
signMessage({
message: "0x787037Ba5b7eA8a8737627FfB67d35FdCaAd9A18",
privateKey: ANVIL_PKEY_A,
}),
).toMatchInlineSnapshot(
'"0x151436da0ef734f06ae71f4b907a062fa5683b40af4221e86dfe5f2fc9f09ffa40c90fee4a0e48311506b84dc6f20e513dc4dc434f0f70a03af6ff3e22c7b7591c"',
);
});
account: TEST_ACCOUNT_A,
});
expect(emojiSignature).toMatchInlineSnapshot(
'"0xc0cd7599731c37aa4c0815a89dc8dcb4ce479f83df7ee8ffc606a9ef29323e814b54bb8935b56e7c690f1ee4c6290da5c2f6df6fc3443fbe96bb1846a2c4fefc1c"',
);

test("raw", async () => {
expect(
signMessage({
message: { raw: "0x68656c6c6f20776f726c64" },
privateKey: ANVIL_PKEY_A,
}),
).toMatchInlineSnapshot(
'"0xa461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b"',
);

expect(
signMessage({
message: {
raw: Uint8Array.from([
104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100,
]),
},
privateKey: ANVIL_PKEY_A,
}),
).toMatchInlineSnapshot(
'"0xa461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b"',
);
const addressSignature = await signMessage({
message: "0x787037Ba5b7eA8a8737627FfB67d35FdCaAd9A18",
account: TEST_ACCOUNT_A,
});
expect(addressSignature).toMatchInlineSnapshot(
'"0x151436da0ef734f06ae71f4b907a062fa5683b40af4221e86dfe5f2fc9f09ffa40c90fee4a0e48311506b84dc6f20e513dc4dc434f0f70a03af6ff3e22c7b7591c"',
);
});
});
53 changes: 44 additions & 9 deletions packages/thirdweb/src/utils/signatures/sign-message.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import type { Account } from "../../wallets/interfaces/wallet.js";
import type { Hex } from "../encoding/hex.js";
import { hashMessage } from "../hashing/hashMessage.js";
import type { Prettify } from "../type-utils.js";
import { sign } from "./sign.js";
import { signatureToHex } from "./signature-to-hex.js";

type Message = Prettify<
| string
| {
raw: Hex | Uint8Array;
}
>;
export type SignMessageOptions = {
message: Prettify<
| string
| {
raw: Hex | Uint8Array;
}
>;
message: Message;
privateKey: Hex;
};

Expand All @@ -30,7 +32,40 @@ export type SignMessageOptions = {
* ```
* @utils
*/
export function signMessage({ message, privateKey }: SignMessageOptions): Hex {
const signature = sign({ hash: hashMessage(message), privateKey });
return signatureToHex(signature);
export function signMessage({ message, privateKey }: SignMessageOptions): Hex;

/**
* Signs a string message with a given account.
* @param options The options for signing.
* @param options.message The message to be signed as a string or object containing raw hex or bytes
* @param options.account The account to be used
* @returns The signature as a hex string
* @example
* ```ts
* import { signMessage } from "thirdweb/utils";
* await signMessage({
* message: "Hello, world!",
* account
* });
* ```
* @walletUtils
*/
export function signMessage({
message,
account,
}: { message: Message; account: Account }): Promise<Hex>;

export function signMessage(
options: SignMessageOptions | { message: Message; account: Account },
): Hex | Promise<Hex> {
if ("privateKey" in options) {
const { message, privateKey } = options;
const signature = sign({ hash: hashMessage(message), privateKey });
return signatureToHex(signature);
} else if ("account" in options) {
const { message, account } = options;
return account.signMessage({ message });
} else {
throw new Error("Either privateKey or account is required");
}

Check warning on line 70 in packages/thirdweb/src/utils/signatures/sign-message.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/utils/signatures/sign-message.ts#L69-L70

Added lines #L69 - L70 were not covered by tests
}

0 comments on commit 41fbdaf

Please sign in to comment.