Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Allow network name for more functions #1698

Merged
merged 1 commit into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/network/src/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,13 @@ export function networkFromName(name: StacksNetworkName) {
}
}

/** @ignore */
export function networkFrom(network: StacksNetworkName | StacksNetwork) {
if (typeof network === 'string') return networkFromName(network);
return network;
}

/** @ignore */
export function deriveDefaultUrl(network?: StacksNetwork | StacksNetworkName) {
if (!network) return HIRO_MAINNET_URL; // default to mainnet if no network is given

Expand Down
11 changes: 8 additions & 3 deletions packages/stacking/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
intToBigInt,
isInstance,
} from '@stacks/common';
import { StacksNetwork } from '@stacks/network';
import { StacksNetwork, StacksNetworkName, networkFrom } from '@stacks/network';
import {
BurnchainRewardListResponse,
BurnchainRewardSlotHolderListResponse,
Expand Down Expand Up @@ -341,9 +341,14 @@ export class StackingClient {

public api: StacksNodeApi;

constructor(opts: { address: string; network: StacksNetwork; api?: StacksNodeApi | ApiOpts }) {
// todo: make more constructor opts optional
constructor(opts: {
address: string;
network: StacksNetworkName | StacksNetwork;
api?: StacksNodeApi | ApiOpts;
}) {
this.address = opts.address;
this.network = opts.network;
this.network = networkFrom(opts.network);
this.api = isInstance(opts.api, StacksNodeApi)
? opts.api
: new StacksNodeApi({ url: opts.api?.url, fetch: opts.api?.fetch, network: opts.network });
Expand Down
8 changes: 5 additions & 3 deletions packages/stacking/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
base58CheckEncode,
verifyMessageSignatureRsv,
} from '@stacks/encryption';
import { StacksNetwork, StacksNetworkName, StacksNetworks } from '@stacks/network';
import { StacksNetwork, StacksNetworkName, StacksNetworks, networkFrom } from '@stacks/network';
import {
BufferCV,
ClarityType,
Expand Down Expand Up @@ -317,6 +317,7 @@ export function poxAddressToBtcAddress(
network: StacksNetworkName
): string;
export function poxAddressToBtcAddress(...args: any[]): string {
// todo: allow these helpers to take a bitcoin network instead of a stacks network, once we have a concept of bitcoin networks in the codebase
if (typeof args[0] === 'number') return _poxAddressToBtcAddress_Values(args[0], args[1], args[2]);
return _poxAddressToBtcAddress_ClarityValue(args[0], args[1]);
}
Expand Down Expand Up @@ -411,7 +412,7 @@ export interface Pox4SignatureOptions {
rewardCycle: number;
/** lock period (in cycles) */
period: number;
network: StacksNetwork;
network: StacksNetworkName | StacksNetwork;
/** Maximum amount of uSTX that can be locked during this function call */
maxAmount: IntegerType;
/** Random integer to prevent signature re-use */
Expand Down Expand Up @@ -472,10 +473,11 @@ export function pox4SignatureMessage({
poxAddress,
rewardCycle,
period: lockPeriod,
network,
network: networkOrName,
maxAmount,
authId,
}: Pox4SignatureOptions) {
const network = networkFrom(networkOrName);
const message = tupleCV({
'pox-addr': poxAddressToTuple(poxAddress),
'reward-cycle': uintCV(rewardCycle),
Expand Down
26 changes: 18 additions & 8 deletions packages/wallet-sdk/src/derive.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
// https://github.com/paulmillr/scure-bip32
// Secure, audited & minimal implementation of BIP32 hierarchical deterministic (HD) wallets.
import { HDKey } from '@scure/bip32';
import { getNameInfo } from '@stacks/auth';
import { ApiParam, bytesToHex, defaultApiLike, utf8ToBytes } from '@stacks/common';
import { compressPrivateKey, createSha2Hash } from '@stacks/encryption';
import { STACKS_MAINNET, StacksNetwork, deriveDefaultUrl } from '@stacks/network';
import {
STACKS_MAINNET,
StacksNetwork,
StacksNetworkName,
deriveDefaultUrl,
networkFrom,
} from '@stacks/network';
import { getAddressFromPrivateKey } from '@stacks/transactions';
import { Account, HARDENED_OFFSET, WalletKeys } from './models/common';
import { fetchFirstName } from './usernames';
import { assertIsTruthy } from './utils';
import { getNameInfo } from '@stacks/auth';

const DATA_DERIVATION_PATH = `m/888'/0'`;
const WALLET_CONFIG_PATH = `m/44/5757'/0'/1`;
Expand Down Expand Up @@ -107,8 +113,10 @@ export const selectStxDerivation = async ({
username?: string;
rootNode: HDKey;
index: number;
network?: StacksNetwork;
network?: StacksNetworkName | StacksNetwork;
}): Promise<{ username: string | undefined; stxDerivationType: DerivationType }> => {
if (network) network = networkFrom(network);

if (username) {
// Based on username, determine the derivation path for the stx private key
const stxDerivationTypeForUsername = await selectDerivationTypeForUsername({
Expand All @@ -128,6 +136,7 @@ export const selectStxDerivation = async ({
}
};

/** @internal @ignore */
const selectDerivationTypeForUsername = async ({
username,
rootNode,
Expand All @@ -141,15 +150,15 @@ const selectDerivationTypeForUsername = async ({
}): Promise<DerivationType> => {
if (network) {
const nameInfo = await getNameInfo({ name: username });
let stxPrivateKey = deriveStxPrivateKey({ rootNode, index });
const stxPrivateKey = deriveStxPrivateKey({ rootNode, index });
let derivedAddress = getAddressFromPrivateKey(stxPrivateKey);
if (derivedAddress !== nameInfo.address) {
// try data private key
stxPrivateKey = deriveDataPrivateKey({
const dataPrivateKey = deriveDataPrivateKey({
rootNode,
index,
});
derivedAddress = getAddressFromPrivateKey(stxPrivateKey);
derivedAddress = getAddressFromPrivateKey(dataPrivateKey);
if (derivedAddress !== nameInfo.address) {
return DerivationType.Unknown;
} else {
Expand All @@ -164,6 +173,7 @@ const selectDerivationTypeForUsername = async ({
}
};

/** @internal @ignore */
const selectUsernameForAccount = async (
opts: {
rootNode: HDKey;
Expand Down Expand Up @@ -200,15 +210,15 @@ export const fetchUsernameForAccountByDerivationType = async (
rootNode: HDKey;
index: number;
derivationType: DerivationType.Wallet | DerivationType.Data;
network?: StacksNetwork;
network?: StacksNetworkName | StacksNetwork;
} & ApiParam
): Promise<{
username: string | undefined;
}> => {
const api = defaultApiLike({ ...{ url: deriveDefaultUrl(opts.network) }, ...opts.api });

// try to find existing usernames owned by given derivation path
const selectedNetwork = opts.network ?? STACKS_MAINNET;
const selectedNetwork = opts.network ? networkFrom(opts.network) : STACKS_MAINNET;
const privateKey = derivePrivateKeyByType(opts);
const address = getAddressFromPrivateKey(privateKey, selectedNetwork.transactionVersion);
const username = await fetchFirstName({ address, api });
Expand Down
Loading