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

Bugfixes and better type namespacing #4

Merged
merged 12 commits into from
Oct 16, 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
1 change: 1 addition & 0 deletions .github/workflows/ci-main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ jobs:
echo "//npm.pkg.github.com/:_authToken=$AUTH_TOKEN" >> .npmrc
bunx npm@latest publish --access=public --tag=latest
env:
# https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-npm-registry#authenticating-to-github-packages
AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1 change: 1 addition & 0 deletions .github/workflows/ci-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,5 @@ jobs:
echo "//npm.pkg.github.com/:_authToken=$AUTH_TOKEN" >> .npmrc
bunx npm@latest publish --access=public
env:
# https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-npm-registry#authenticating-to-github-packages
AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@secretkeylabs/stacks-tools",
"version": "0.3.0",
"version": "0.4.0",
"type": "module",
"files": [
"dist"
Expand Down
23 changes: 21 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,21 @@
export { stacksApi } from "./stacks-api/index.js";
export { queries } from "./queries/index.js";
import {
accounts,
blocks,
info,
proofOfTransfer,
smartContracts,
stackingPool,
transactions,
} from "./stacks-api/index.js";
export const stacksApi = {
accounts,
blocks,
info,
proofOfTransfer,
smartContracts,
stackingPool,
transactions,
};
export type * as StacksApi from "./stacks-api/index.js";

export * from "./utils/index.js";
2 changes: 1 addition & 1 deletion src/queries/get-signer-stacked-amount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export async function getSignerStackedAmount(
}
}

offset += limit + data.results.length;
offset += data.results.length;
hasMore = offset < data.total;
}

Expand Down
2 changes: 1 addition & 1 deletion src/queries/get-signer-total-locked.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export async function getSignerTotalLocked(
}
}

offset += limit + data.results.length;
offset += data.results.length;
hasMore = offset < data.total;
}

Expand Down
8 changes: 4 additions & 4 deletions src/stacks-api/accounts/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { balances } from "./balances.js";
export { balances } from "./balances.js";
export type * as Balances from "./balances.js";

export const accounts = {
balances,
};
export { latestNonce } from "./latest-nonce.js";
export type * as LatestNonce from "./latest-nonce.js";
74 changes: 74 additions & 0 deletions src/stacks-api/accounts/latest-nonce.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import {
error,
safePromise,
success,
type Result,
type SafeError,
} from "../../utils/safe.js";
import type { ApiRequestOptions } from "../types.js";
import * as v from "valibot";

export type Args = {
principal: string;
} & ApiRequestOptions;

export const responseSchema = v.object({
last_mempool_tx_nonce: v.nullable(v.number()),
last_executed_tx_nonce: v.nullable(v.number()),
possible_next_nonce: v.number(),
detected_missing_nonces: v.array(v.number()),
detected_mempool_nonces: v.array(v.number()),
});
export type Response = v.InferOutput<typeof responseSchema>;

export async function latestNonce(
opts: Args,
): Promise<
Result<
Response,
SafeError<"FetchLatestNonceError" | "ParseBodyError" | "ValidateDataError">
>
> {
const init: RequestInit = {};
if (opts.apiKeyConfig) {
init.headers = {
[opts.apiKeyConfig.header]: opts.apiKeyConfig.key,
};
}

const endpoint = `${opts.baseUrl}/extended/v1/address/${opts.principal}/nonces`;
const res = await fetch(endpoint, init);

if (!res.ok) {
return error({
name: "FetchLatestNonceError",
message: "Failed to fetch latest nonce.",
data: {
endpoint,
status: res.status,
statusText: res.statusText,
bodyParseResult: await safePromise(res.json()),
},
});
}

const [jsonError, data] = await safePromise(res.json());
if (jsonError) {
return error({
name: "ParseBodyError",
message: "Failed to parse response body as JSON.",
data: jsonError,
});
}

const validationResult = v.safeParse(responseSchema, data);
if (!validationResult.success) {
return error({
name: "ValidateDataError",
message: "Failed to validate data.",
data: validationResult,
});
}

return success(validationResult.output);
}
7 changes: 2 additions & 5 deletions src/stacks-api/blocks/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
import { getBlock } from "./get-block.js";

export const blocks = {
getBlock,
};
export { getBlock } from "./get-block.js";
export type * as GetBlock from "./get-block.js";
52 changes: 37 additions & 15 deletions src/stacks-api/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,39 @@
import { accounts } from "./accounts/index.js";
import { blocks } from "./blocks/index.js";
import { info } from "./info/index.js";
import { proofOfTransfer } from "./proof-of-transfer/index.js";
import { smartContracts } from "./smart-contracts/index.js";
import { stackingPool } from "./stacking-pool/index.js";
import { transactions } from "./transactions/index.js";
import { balances, latestNonce } from "./accounts/index.js";
export const accounts = { balances, latestNonce };
export type * as Accounts from "./accounts/index.js";

export const stacksApi = {
accounts,
blocks,
info,
proofOfTransfer,
smartContracts,
stackingPool,
transactions,
import { getBlock } from "./blocks/index.js";
export const blocks = { getBlock };
export type * as Blocks from "./blocks/index.js";

import { coreApi, poxDetails } from "./info/index.js";
export const info = { coreApi, poxDetails };
export type * as Info from "./info/index.js";

import {
cycle,
cycles,
signerInCycle,
signersInCycle,
stackersForSignerInCycle,
} from "./proof-of-transfer/index.js";
export const proofOfTransfer = {
cycle,
cycles,
signerInCycle,
signersInCycle,
stackersForSignerInCycle,
};
export type * as ProofOfTransfer from "./proof-of-transfer/index.js";

import { readOnly } from "./smart-contracts/index.js";
export const smartContracts = { readOnly };
export type * as SmartContracts from "./smart-contracts/index.js";

import { members } from "./stacking-pool/index.js";
export const stackingPool = { members };
export type * as StackingPool from "./stacking-pool/index.js";

import { addressTransactions, getTransaction } from "./transactions/index.js";
export const transactions = { addressTransactions, getTransaction };
export type * as Transactions from "./transactions/index.js";
5 changes: 3 additions & 2 deletions src/stacks-api/info/core-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ const CoreApiResponseSchema = v.object({
stacks_tip_height: v.number(),
stacks_tip: v.string(),
stacks_tip_consensus_hash: v.string(),
unanchored_tip: v.string(),
exit_at_block_height: v.number(),
unanchored_tip: v.nullable(v.string()),
unanchored_seq: v.nullable(v.string()),
exit_at_block_height: v.nullable(v.number()),
});
export type CoreApiResponse = v.InferOutput<typeof CoreApiResponseSchema>;

Expand Down
10 changes: 4 additions & 6 deletions src/stacks-api/info/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { coreApi } from "./core-api.js";
import { poxDetails } from "./pox-details.js";
export { coreApi } from "./core-api.js";
export type * as CoreApi from "./core-api.js";

export const info = {
coreApi,
poxDetails,
};
export { poxDetails } from "./pox-details.js";
export type * as PoxDetails from "./pox-details.js";
27 changes: 14 additions & 13 deletions src/stacks-api/proof-of-transfer/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { cycle } from "./cycle.js";
import { cycles } from "./cycles.js";
import { signerInCycle } from "./signer-in-cycle.js";
import { signersInCycle } from "./signers-in-cycle.js";
import { stackersForSignerInCycle } from "./stackers-for-signer-in-cycle.js";

export const proofOfTransfer = {
cycle,
cycles,
signerInCycle,
signersInCycle,
stackersForSignerInCycle,
};
export { cycle } from "./cycle.js";
export type * as Cycle from "./cycle.js";

export { cycles } from "./cycles.js";
export type * as Cycles from "./cycles.js";

export { signerInCycle } from "./signer-in-cycle.js";
export type * as SignerInCycle from "./signer-in-cycle.js";

export { signersInCycle } from "./signers-in-cycle.js";
export type * as SignersInCycle from "./signers-in-cycle.js";

export { stackersForSignerInCycle } from "./stackers-for-signer-in-cycle.js";
export type * as StackersForSignerInCycle from "./stackers-for-signer-in-cycle.js";
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ export async function stackersForSignerInCycle(
};
}

const endpoint = `${opts.baseUrl}/extended/v2/pox/cycles/${opts.cycleNumber}/signers/${opts.signerPublicKey}/stackers?${search}`;
const signerPublicKeyPathParam = opts.signerPublicKey.startsWith("0x")
? opts.signerPublicKey
: `0x${opts.signerPublicKey}`;
const endpoint = `${opts.baseUrl}/extended/v2/pox/cycles/${opts.cycleNumber}/signers/${signerPublicKeyPathParam}/stackers?${search}`;
const res = await fetch(endpoint, init);

if (!res.ok) {
Expand Down
7 changes: 2 additions & 5 deletions src/stacks-api/smart-contracts/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
import { readOnly } from "./read-only.js";

export const smartContracts = {
readOnly,
};
export { readOnly } from "./read-only.js";
export type * as ReadOnly from "./read-only.js";
38 changes: 23 additions & 15 deletions src/stacks-api/smart-contracts/read-only.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ import { error, safePromise, success, type Result } from "../../utils/safe.js";
import type { ApiRequestOptions } from "../types.js";
import * as v from "valibot";

export type Options = {
export type Args = {
sender: string;
arguments: string[];
contractAddress: string;
contractName: string;
functionName: string;
};
} & ApiRequestOptions;

export const readOnlyResponseSchema = v.variant("okay", [
v.object({
okay: v.literal(true),
/**
* A Clarity value as a hex-encoded string.
*/
result: v.string(),
}),
v.object({
Expand All @@ -22,21 +25,26 @@ export const readOnlyResponseSchema = v.variant("okay", [
]);
export type ReadOnlyResponse = v.InferOutput<typeof readOnlyResponseSchema>;

export async function readOnly(
opts: Options,
apiOpts: ApiRequestOptions,
): Promise<Result<ReadOnlyResponse>> {
const init: RequestInit = {};
if (apiOpts.apiKeyConfig) {
init.headers = {
[apiOpts.apiKeyConfig.header]: apiOpts.apiKeyConfig.key,
};
export async function readOnly(args: Args): Promise<Result<ReadOnlyResponse>> {
const headers: Record<string, string> = {
"Content-Type": "application/json",
};

if (args.apiKeyConfig) {
headers[args.apiKeyConfig.header] = args.apiKeyConfig.key;
}

const res = await fetch(
`${apiOpts.baseUrl}/v2/contracts/call-read/${opts.contractAddress}/${opts.contractName}/${opts.functionName}`,
init,
);
const init: RequestInit = {
method: "POST",
body: JSON.stringify({
sender: args.sender,
arguments: args.arguments,
}),
headers,
};

const endpoint = `${args.baseUrl}/v2/contracts/call-read/${args.contractAddress}/${args.contractName}/${args.functionName}`;
const res = await fetch(endpoint, init);

if (!res.ok) {
return error({
Expand Down
7 changes: 2 additions & 5 deletions src/stacks-api/stacking-pool/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
import { members } from "./members.js";

export const stackingPool = {
members,
};
export { members } from "./members.js";
export type * as Members from "./members.js";
12 changes: 6 additions & 6 deletions src/stacks-api/transactions/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { addressTransactions } from "./address-transactions.js";
import { getTransaction } from "./get-transaction.js";
export { addressTransactions } from "./address-transactions.js";
export type * as AddressTransactions from "./address-transactions.js";

export const transactions = {
addressTransactions,
getTransaction,
};
export { getTransaction } from "./get-transaction.js";
export type * as GetTransaction from "./get-transaction.js";

export type * as Common from "./schemas.js";
6 changes: 5 additions & 1 deletion src/stacks-api/transactions/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ export const baseTransactionSchema = v.object({
parent_burn_block_time_iso: v.string(),
canonical: v.boolean(),
tx_index: v.number(),
tx_status: v.string(),
tx_status: v.union([
v.literal("success"),
v.literal("abort_by_response"),
v.literal("abort_by_post_condition"),
]),
tx_result: v.object({
hex: v.string(),
repr: v.string(),
Expand Down
4 changes: 4 additions & 0 deletions src/stacks-api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import * as v from "valibot";

export type ApiKeyConfig = {
key: string;
/**
* The header to use for the API key. For example, the Hiro API uses the
* header `x-api-key`.
*/
header: string;
};

Expand Down
Loading