Skip to content

Commit

Permalink
feat: add new api package
Browse files Browse the repository at this point in the history
  • Loading branch information
janniks committed Feb 5, 2024
1 parent 628015f commit b335ae8
Show file tree
Hide file tree
Showing 12 changed files with 286 additions and 0 deletions.
32 changes: 32 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions packages/api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# @stacks/api [![npm](https://img.shields.io/npm/v/@stacks/api?color=red)](https://www.npmjs.com/package/@stacks/api)

todo: one-liner

## Installation

```
npm install @stacks/api
```

## Overview

todo

## Todo
3 changes: 3 additions & 0 deletions packages/api/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const makeJestConfig = require('../../configs/jestConfig');

module.exports = makeJestConfig(__dirname);
53 changes: 53 additions & 0 deletions packages/api/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"name": "@stacks/api",
"version": "6.9.0",
"description": "Javascript library for interacting with the Stacks Blockchain Node and API.",
"license": "MIT",
"author": "Hiro Systems PBC (https://hiro.so)",
"contributors": [
"janniks"
],
"homepage": "https://hiro.so/stacks-js",
"scripts": {
"build": "npm run clean && npm run build:cjs && npm run build:esm && npm run build:umd",
"build:cjs": "tsc -b tsconfig.build.json",
"build:esm": "tsc -p tsconfig.build.json --module ES6 --outDir ./dist/esm",
"build:umd": "NODE_OPTIONS=--max-old-space-size=8192 webpack --config webpack.config.js",
"clean": "rimraf dist && tsc -b tsconfig.build.json --clean",
"pack": "npm pack",
"prepublishOnly": "npm run test && NODE_ENV=production npm run build",
"start": "tsc -b tsconfig.build.json --watch --verbose",
"test": "jest",
"test:watch": "jest --watch --coverage=false",
"typecheck": "tsc --noEmit",
"typecheck:watch": "npm run typecheck -- --watch"
},
"dependencies": {
"@stacks/common": "^6.10.0",
"@stacks/network": "^6.11.3",
"@stacks/transactions": "^6.9.0"
},
"devDependencies": {
"rimraf": "^3.0.2"
},
"sideEffects": false,
"publishConfig": {
"access": "public"
},
"typings": "dist/index.d.ts",
"main": "dist/index.js",
"module": "dist/esm/index.js",
"umd:main": "dist/umd/index.js",
"unpkg": "dist/umd/index.js",
"files": [
"dist",
"src"
],
"repository": {
"type": "git",
"url": "git+https://github.com/hirosystems/stacks.js.git"
},
"bugs": {
"url": "https://github.com/hirosystems/stacks.js/issues"
}
}
125 changes: 125 additions & 0 deletions packages/api/src/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { FetchFn, Hex, createFetchFn } from '@stacks/common';
import {
STACKS_MAINNET,
StacksNetwork,
StacksNetworkName,
TransactionVersion,
deriveDefaultUrl,
networkFrom,
} from '@stacks/network';
import {
ClarityAbi,
FeeEstimation,
StacksTransaction,
TxBroadcastResult,
broadcastTransaction,
estimateTransaction,
getAbi,
getNonce,
} from '@stacks/transactions';

export class StacksNodeApi {
// TODO
bnsLookupUrl = 'https://stacks-node-api.mainnet.stacks.co';

public url: string;
public fetch: FetchFn;

public network: StacksNetwork;

constructor({
url,
fetch,
network = STACKS_MAINNET,
}: {
/** The base API/node URL for the network fetch calls */
url?: string;
/** Stacks network object (defaults to {@link STACKS_MAINNET}) */
network?: StacksNetworkName | StacksNetwork;
/** An optional custom fetch function to override default behaviors */
fetch?: FetchFn;
} = {}) {
this.url = url ?? deriveDefaultUrl(network);
this.fetch = fetch ?? createFetchFn();
this.network = networkFrom(network);
}

/** Returns `true` if the network is configured to 'mainnet', based on the TransactionVersion */
isMainnet = () => this.network.transactionVersion === TransactionVersion.Mainnet;

/**
* Broadcast a serialized transaction to a Stacks node (which will validate and forward to the network).
* @param transaction - The transaction to broadcast
* @param attachment - Optional attachment to include with the transaction
* @returns a Promise that resolves to a {@link TxBroadcastResult} object
*/
broadcastTransaction = async (
transaction: StacksTransaction,
attachment?: Uint8Array | string
): Promise<TxBroadcastResult> => {
// todo: should we use a opts object instead of positional args here?
return broadcastTransaction({ transaction, attachment, api: this });
};

/**
* Lookup the nonce for an address from a core node
* @param address - The Stacks address to look up the next nonce for
* @return A promise that resolves to a bigint of the next nonce
*/
getNonce = async (address: string): Promise<bigint> => {
return getNonce({ address, api: this });
};

/**
* Estimate the total transaction fee in microstacks for a Stacks transaction
* @param payload - The transaction to estimate fees for
* @param estimatedLength - Optional argument that provides the endpoint with an
* estimation of the final length (in bytes) of the transaction, including any post-conditions
* and signatures
* @return A promise that resolves to an array of {@link FeeEstimate}
*/
estimateTransaction = async (
payload: Hex,
estimatedLength?: number
): Promise<[FeeEstimation, FeeEstimation, FeeEstimation]> => {
return estimateTransaction({ payload, estimatedLength, api: this });
};

/**
* Fetch a contract's ABI
* @param contractAddress - The contracts address
* @param contractName - The contracts name
* @returns A promise that resolves to a ClarityAbi if the operation succeeds
*/
getAbi = async (contractAddress: string, contractName: string): Promise<ClarityAbi> => {
return getAbi({ contractAddress, contractName, api: this });
};

// todo: migrate to new api pattern
getNameInfo(fullyQualifiedName: string) {
/*
TODO: Update to v2 API URL for name lookups
*/
const nameLookupURL = `${this.bnsLookupUrl}/v1/names/${fullyQualifiedName}`;
return this.fetch(nameLookupURL)
.then((resp: any) => {
if (resp.status === 404) {
throw new Error('Name not found');
} else if (resp.status !== 200) {
throw new Error(`Bad response status: ${resp.status}`);
} else {
return resp.json();
}
})
.then((nameInfo: any) => {
// the returned address _should_ be in the correct network ---
// stacks node gets into trouble because it tries to coerce back to mainnet
// and the regtest transaction generation libraries want to use testnet addresses
if (nameInfo.address) {
return Object.assign({}, nameInfo, { address: nameInfo.address });
} else {
return nameInfo;
}
});
}
}
1 change: 1 addition & 0 deletions packages/api/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './api';
14 changes: 14 additions & 0 deletions packages/api/tests/api.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { DEVNET_URL, HIRO_MAINNET_URL, HIRO_TESTNET_URL } from '@stacks/common';
import { STACKS_DEVNET, STACKS_MAINNET, STACKS_TESTNET } from '@stacks/network';
import { StacksNodeApi } from '../src';

describe('setting StacksApi URL', () => {
test.each([
{ network: STACKS_MAINNET, url: HIRO_MAINNET_URL },
{ network: STACKS_TESTNET, url: HIRO_TESTNET_URL },
{ network: STACKS_DEVNET, url: DEVNET_URL },
])('the api class determines the correct url for each network object', ({ network, url }) => {
const api = new StacksNodeApi({ network });
expect(api.url).toEqual(url);
});
});
2 changes: 2 additions & 0 deletions packages/api/tests/setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const fetchMock = require('jest-fetch-mock');
fetchMock.enableFetchMocks();
22 changes: 22 additions & 0 deletions packages/api/tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"noEmit": false,
"outDir": "./dist",
"rootDir": "./src",
"tsBuildInfoFile": "./tsconfig.build.tsbuildinfo",
"composite": true
},
"references": [
{
"path": "../common/tsconfig.build.json"
},
{
"path": "../network/tsconfig.build.json"
},
{
"path": "../transactions/tsconfig.build.json"
}
],
"include": ["src/**/*"]
}
10 changes: 10 additions & 0 deletions packages/api/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"target": "ES2020"
},
"include": ["src/**/*", "tests/**/*"],
"typedocOptions": {
"entryPoints": ["src/index.ts"]
}
}
7 changes: 7 additions & 0 deletions packages/api/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const config = require('../../configs/webpack.config.js');

config.output.library.name = 'StacksApi';

config.resolve.fallback = {};

module.exports = config;
2 changes: 2 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@stacks/api": ["packages/api/src"],
"@stacks/auth": ["packages/auth/src"],
"@stacks/bns": ["packages/bns/src"],
"@stacks/cli": ["packages/cli/src"],
Expand All @@ -23,6 +24,7 @@
"entryPointStrategy": "packages",
"entryPoints": [
// "packages/*", without packages/cli
"packages/api",
"packages/auth",
"packages/encryption",
"packages/network",
Expand Down

0 comments on commit b335ae8

Please sign in to comment.