Skip to content

Commit

Permalink
feat(sdk): support signet (#184)
Browse files Browse the repository at this point in the history
* feat(sdk): support signet

* fix test name

* resolve comments
  • Loading branch information
kevzzsk authored May 24, 2024
1 parent 36aed16 commit a738d66
Show file tree
Hide file tree
Showing 18 changed files with 179 additions and 15 deletions.
34 changes: 34 additions & 0 deletions packages/sdk/src/addresses/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe("addresses", () => {
const MAINNET = "mainnet";
const TESTNET = "testnet";
const REGTEST = "regtest";
const SIGNET = "signet";

const INVALID_ADDRESS_ERROR = new OrditSDKError("Invalid address");

Expand All @@ -28,6 +29,14 @@ describe("addresses", () => {
"tb1p3gqcaq2xs0qzm5wvkht64xppcz9h5k0q2q97kf6n80gu7v037dksatsuhz",
p2wsh: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
},
[SIGNET]: {
legacy: "mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn",
"p2sh-p2wpkh": "2MzQwSSnBHWHqSAqtTVQ6v47XtaisrJa1Vc",
segwit: "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx",
taproot:
"tb1p3gqcaq2xs0qzm5wvkht64xppcz9h5k0q2q97kf6n80gu7v037dksatsuhz",
p2wsh: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
},
[REGTEST]: {
legacy: "mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn",
"p2sh-p2wpkh": "2MzQwSSnBHWHqSAqtTVQ6v47XtaisrJa1Vc",
Expand Down Expand Up @@ -106,6 +115,31 @@ describe("addresses", () => {
).not.toThrowError(INVALID_ADDRESS_ERROR);
});

test("should return correct address format for signet", () => {
const network = SIGNET;
expect(getAddressFormat(ADDRESSES[network].legacy, network)).toBe(
"legacy",
);
expect(getAddressFormat(ADDRESSES[network]["p2sh-p2wpkh"], network)).toBe(
"p2sh-p2wpkh",
);
expect(getAddressFormat(ADDRESSES[network].segwit, network)).toBe(
"segwit",
);
expect(getAddressFormat(ADDRESSES[network].taproot, network)).toBe(
"taproot",
);
expect(getAddressFormat(ADDRESSES[network].p2wsh, network)).toBe("p2wsh");

// non-bech32 addresses from regtest will work on testnet/signet
expect(() =>
getAddressFormat(ADDRESSES[REGTEST].legacy, network),
).not.toThrowError(INVALID_ADDRESS_ERROR);
expect(() =>
getAddressFormat(ADDRESSES[REGTEST]["p2sh-p2wpkh"], network),
).not.toThrowError(INVALID_ADDRESS_ERROR);
});

test("should throw an error if address format is not recognised for mainnet", () => {
expect(() => getAddressFormat("", MAINNET)).toThrowError(
INVALID_ADDRESS_ERROR,
Expand Down
7 changes: 6 additions & 1 deletion packages/sdk/src/addresses/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,12 @@ export function getAddressFormat(
return getAddressFormatForRegTest(address);
}

if (!validate(address, network as NetworkEnum)) {
if (
!validate(
address,
(network === "signet" ? "testnet" : network) as NetworkEnum,
)
) {
throw new OrditSDKError("Invalid address");
}

Expand Down
1 change: 1 addition & 0 deletions packages/sdk/src/api/jsonrpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,5 +115,6 @@ export const rpc = {
},
mainnet: new JsonRpc(getRpcUrl(API_CONFIG.apis.mainnet.batter)),
testnet: new JsonRpc(getRpcUrl(API_CONFIG.apis.testnet.batter)),
signet: new JsonRpc(getRpcUrl(API_CONFIG.apis.signet.batter)),
regtest: new JsonRpc(getRpcUrl(API_CONFIG.apis.regtest.batter)),
} as const;
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { BitcoinNetworkType } from "sats-connect";
import type { BrowserWalletNetwork } from "../../../config/types";

export const NETWORK_TO_BITCOIN_NETWORK_TYPE: Record<
BrowserWalletNetwork,
Extract<BrowserWalletNetwork, "mainnet" | "testnet">,
BitcoinNetworkType
> = {
mainnet: BitcoinNetworkType.Mainnet,
Expand Down
10 changes: 10 additions & 0 deletions packages/sdk/src/browser-wallets/internal/sats-connect/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ async function satsConnectWalletGetAddresses(
getProvider: () => Promise<BitcoinProvider>,
network: BrowserWalletNetwork = "mainnet",
): Promise<WalletAddress[]> {
if (network === "signet") {
throw new OrditSDKError("signet network is not supported");
}

const result: WalletAddress[] = [];

const handleOnFinish = (response: GetAddressResponse) => {
Expand Down Expand Up @@ -116,6 +120,9 @@ async function satsConnectWalletSignPsbt(
inputsToSign,
}: SatsConnectSignPSBTOptions = { network: "mainnet", inputsToSign: [] },
): Promise<BrowserWalletSignResponse> {
if (network === "signet") {
throw new OrditSDKError("signet network is not supported");
}
if (!finalize && extractTx) {
throw new BrowserWalletExtractTxFromNonFinalizedPsbtError();
}
Expand Down Expand Up @@ -213,6 +220,9 @@ async function satsConnectWalletSignMessage(
address: string,
network: BrowserWalletNetwork = "mainnet",
): Promise<BrowserWalletSignResponse> {
if (network === "signet") {
throw new OrditSDKError("signet network is not supported");
}
if (!message || !network || !address) {
throw new OrditSDKError("Invalid options provided");
}
Expand Down
56 changes: 56 additions & 0 deletions packages/sdk/src/browser-wallets/leather/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,62 @@ describe("Leather Wallet", () => {
expect(getAddresses(network)).resolves.toEqual(resolvedValue);
});

test("should return address from signet", () => {
const mockData = {
jsonrpc: "2.0",
id: "20b0fcf3-ad9a-4f32-8d7f-b6db6fb96207",
result: {
addresses: [
{
symbol: "BTC",
type: "p2wpkh",
address: "tb1qy89jvaya2dzfuagxl7h59pytjs74kxudslux25",
publicKey:
"0238427342c868536e9c181caf674d242ab8a3e381ee36692ba375e0b315234180",
derivationPath: "m/84'/1'/0'/0/0",
},
{
symbol: "BTC",
type: "p2tr",
address:
"tb1pgftv8z8re72kttnyt85k2ae6andngar4c59hasv2kp04kgmmgnnqmxg8uy",
publicKey:
"023ded01d3e800b07278c5bbc5deee1f3493ebd599ae843936d81a42625a5cfb84",
tweakedPublicKey:
"3ded01d3e800b07278c5bbc5deee1f3493ebd599ae843936d81a42625a5cfb84",
derivationPath: "m/86'/1'/0'/0/0",
},
{
symbol: "STX",
address: "ST3TJ35J2T3NCAD471DCN2MB0502Z2TVNPZHN1NEG",
},
],
},
};
const network = "signet";

const resolvedValue = [
{
publicKey:
"0238427342c868536e9c181caf674d242ab8a3e381ee36692ba375e0b315234180",
address: "tb1qy89jvaya2dzfuagxl7h59pytjs74kxudslux25",
format: "segwit",
},
{
publicKey:
"023ded01d3e800b07278c5bbc5deee1f3493ebd599ae843936d81a42625a5cfb84",
address:
"tb1pgftv8z8re72kttnyt85k2ae6andngar4c59hasv2kp04kgmmgnnqmxg8uy",
format: "taproot",
},
];

vi.stubGlobal("LeatherProvider", {
request: vi.fn().mockResolvedValue(mockData),
});
expect(getAddresses(network)).resolves.toEqual(resolvedValue);
});

test("should return error when the network mismatch", () => {
const mockData = {
jsonrpc: "2.0",
Expand Down
7 changes: 6 additions & 1 deletion packages/sdk/src/browser-wallets/leather/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ async function getAddresses(

// Hacky validation: there's no parameter to specify the network value when getting the address.
// TODO: Remove this if the wallet already supports that parameter.
if (getNetworkByAddress(addresses[0].address) !== network) {
const derivedNetwork = getNetworkByAddress(addresses[0].address);

if (
(network !== "signet" && derivedNetwork !== network) ||
(network === "signet" && derivedNetwork !== "testnet") // error if network is signet but derived network is not testnet (signet has same address format as testnet)
) {
throw new BrowserWalletNetworkMismatchError(
"Leather network mismatch, please switch it manually",
);
Expand Down
22 changes: 22 additions & 0 deletions packages/sdk/src/browser-wallets/okx/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,28 @@ describe("OKX Wallet", () => {
expect(getAddresses(network)).resolves.toEqual([mockData]);
});

test("should return address from signet", () => {
const mockData: WalletAddress = {
publicKey:
"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
address: "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx",
format: "segwit",
};
const mockXOnlyPubKey =
"79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
const network = "signet";

vi.stubGlobal("okxwallet", {
bitcoinSignet: {
connect: vi.fn().mockResolvedValue({
address: mockData.address,
publicKey: mockXOnlyPubKey,
}),
},
});
expect(getAddresses(network)).resolves.toEqual([mockData]);
});

test("should throw error when user rejects or cancels request", () => {
const mockData: WalletAddress = {
publicKey:
Expand Down
18 changes: 9 additions & 9 deletions packages/sdk/src/browser-wallets/okx/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,16 @@ function getOKXWalletProvider(
throw new BrowserWalletNotInstalledError("OKX Wallet not installed.");
}

const provider =
network === "mainnet"
? window.okxwallet.bitcoin
: window.okxwallet.bitcoinTestnet;

if (!provider) {
throw new OrditSDKError("Failed to get OKX Wallet provider.");
switch (network) {
case "mainnet":
return window.okxwallet.bitcoin;
case "testnet":
return window.okxwallet.bitcoinTestnet;
case "signet":
return window.okxwallet.bitcoinSignet;
default:
throw new OrditSDKError("Failed to get OKX Wallet provider.");
}

return provider;
}

async function getAddresses(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ describe("Unisat Wallet", () => {
expect(getAddresses("testnet")).resolves.toEqual([mockData]);
});

test("should return error from signet", () => {
expect(getAddresses("signet")).rejects.toThrowError(
"signet network is not supported",
);
});

test("should throw error when user rejects or cancels request", () => {
const mockData: WalletAddress = {
publicKey:
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/src/browser-wallets/unisat/constants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { BrowserWalletNetwork } from "../../config/types";

export const NETWORK_TO_UNISAT_NETWORK: Record<
BrowserWalletNetwork,
Extract<BrowserWalletNetwork, "mainnet" | "testnet">,
UnisatNetwork
> = {
mainnet: "livenet",
Expand Down
3 changes: 3 additions & 0 deletions packages/sdk/src/browser-wallets/unisat/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ async function getAddresses(
network: BrowserWalletNetwork = "mainnet",
readOnly?: boolean,
): Promise<WalletAddress[]> {
if (network === "signet") {
throw new OrditSDKError("signet network is not supported");
}
if (!isInstalled()) {
throw new BrowserWalletNotInstalledError("Unisat not installed");
}
Expand Down
11 changes: 11 additions & 0 deletions packages/sdk/src/browser-wallets/xverse/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,17 @@ describe("Xverse Wallet", () => {
expect(getAddresses("testnet")).resolves.toEqual(mockData);
});

test("should throw error on signet", () => {
vi.stubGlobal("window", {
XverseProviders: {
BitcoinProvider: {},
},
});
expect(getAddresses("signet")).rejects.toThrowError(
"signet network is not supported",
);
});

test("should throw error on user cancel", () => {
vi.stubGlobal("window", {
XverseProviders: {
Expand Down
3 changes: 3 additions & 0 deletions packages/sdk/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@ export const API_CONFIG = {
testnet: {
batter: "https://testnet.ordit.io/",
},
signet: {
batter: "https://signet.ordit.io/",
},
},
};
7 changes: 5 additions & 2 deletions packages/sdk/src/config/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
export type Network = "mainnet" | "testnet" | "regtest";
export type Network = "mainnet" | "testnet" | "regtest" | "signet";

export type BrowserWalletNetwork = Extract<Network, "mainnet" | "testnet">;
export type BrowserWalletNetwork = Extract<
Network,
"mainnet" | "testnet" | "signet"
>;
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ describe("PSBTBuilder", () => {
mainnet: mockJsonRpc,
testnet: mockJsonRpc,
regtest: mockJsonRpc,
signet: mockJsonRpc,
};
afterAll(() => {
vi.resetAllMocks();
Expand Down
1 change: 1 addition & 0 deletions packages/sdk/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ type OKXWalletProvider = {
type OKXWallet = {
bitcoin: OKXWalletProvider;
bitcoinTestnet: OKXWalletProvider;
bitcoinSignet: OKXWalletProvider;
};

declare module "buffer-reverse" {
Expand Down
3 changes: 3 additions & 0 deletions packages/sdk/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ export function getNetwork(value: Network) {
if (value === "mainnet") {
return networks.bitcoin;
}
if (value === "signet") {
return networks.testnet;
}

return networks[value];
}
Expand Down

0 comments on commit a738d66

Please sign in to comment.