Skip to content

Commit

Permalink
Merge branch 'main' into abi-upgrades
Browse files Browse the repository at this point in the history
  • Loading branch information
gregnazario authored Mar 26, 2024
2 parents cd056ca + 5376192 commit c55f110
Show file tree
Hide file tree
Showing 16 changed files with 382 additions and 72 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@
All notable changes to the Aptos TypeScript SDK will be captured in this file. This changelog is written by hand for now. It adheres to the format set out by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

# Unreleased

- Use indexer API via API Gateway
- Add support to allow setting per-backend (fullnode, indexer, faucet) configuration
- [`Breaking`] `AUTH_TOKEN` client config moved to be under `faucetConfig` property
- Handle `Unauthorized` server error
- Add function to create object address locally
- Add function to create token object address locally
- Add signers to entry function ABI for future signature count checking
- [`Breaking`] Add type-safe view functions with ABI support
- Turn off code splitting on CJS

# 1.10.0 (2024-03-11)

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ const modules = await aptos.getAccountModules({ accountAddress: "0x123" });
```ts
const account = Account.generate(); // defaults to Legacy Ed25519
const account = Account.generate({ scheme: SingingSchemeInput.Secp256k1 }); // Single Sender Secp256k1
const account = Account.generate({ scheme: SingingSchemeInput.Ed25519, legacy: false }); // Single Sender Ed25519
const account = Account.generate({ scheme: SigningSchemeInput.Secp256k1Ecdsa }); // Single Sender Secp256k1
const account = Account.generate({ scheme: SigningSchemeInput.Ed25519, legacy: false }); // Single Sender Ed25519
```
#### Derive from private key
Expand Down
27 changes: 25 additions & 2 deletions src/api/aptosConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@
// SPDX-License-Identifier: Apache-2.0

import aptosClient from "@aptos-labs/aptos-client";
import { AptosSettings, ClientConfig, Client } from "../types";
import { AptosSettings, ClientConfig, Client, FullNodeConfig, IndexerConfig, FaucetConfig } from "../types";
import { NetworkToNodeAPI, NetworkToFaucetAPI, NetworkToIndexerAPI, Network } from "../utils/apiEndpoints";
import { AptosApiType } from "../utils/const";

/**
* This class holds the config information for the SDK client instance.
*/
export class AptosConfig {
/** The Network that this SDK is associated with. Defaults to DEVNET */
/**
* The Network that this SDK is associated with. Defaults to DEVNET
*/
readonly network: Network;

/**
Expand All @@ -33,15 +35,36 @@ export class AptosConfig {
*/
readonly indexer?: string;

/**
* Optional client configurations
*/
readonly clientConfig?: ClientConfig;

/**
* Optional specific Fullnode configurations
*/
readonly fullnodeConfig?: FullNodeConfig;

/**
* Optional specific Indexer configurations
*/
readonly indexerConfig?: IndexerConfig;

/**
* Optional specific Faucet configurations
*/
readonly faucetConfig?: FaucetConfig;

constructor(settings?: AptosSettings) {
this.network = settings?.network ?? Network.DEVNET;
this.fullnode = settings?.fullnode;
this.faucet = settings?.faucet;
this.indexer = settings?.indexer;
this.client = settings?.client ?? { provider: aptosClient };
this.clientConfig = settings?.clientConfig ?? {};
this.fullnodeConfig = settings?.fullnodeConfig ?? {};
this.indexerConfig = settings?.indexerConfig ?? {};
this.faucetConfig = settings?.faucetConfig ?? {};
}

/**
Expand Down
14 changes: 8 additions & 6 deletions src/client/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,10 @@ export async function request<Req, Res>(options: ClientRequest<Req>, client: Cli
"content-type": contentType ?? MimeType.JSON,
};

// TODO - auth token is being used only for faucet, it breaks full node requests.
// Find a more sophisticated way than that but without the need to add the
// auth_token on every `aptos.fundAccount()` call
if (overrides?.AUTH_TOKEN && url.includes("faucet")) {
if (overrides?.AUTH_TOKEN) {
headers.Authorization = `Bearer ${overrides?.AUTH_TOKEN}`;
}
if (overrides?.API_KEY && !url.includes("faucet")) {
if (overrides?.API_KEY) {
headers.Authorization = `Bearer ${overrides?.API_KEY}`;
}

Expand Down Expand Up @@ -81,11 +78,16 @@ export async function aptosRequest<Req extends {}, Res extends {}>(
url: fullUrl,
};

// Handle case for `Unauthorized` error (i.e API_KEY error)
if (result.status === 401) {
throw new AptosApiError(options, result, `Error: ${result.data}`);
}

// to support both fullnode and indexer responses,
// check if it is an indexer query, and adjust response.data
if (aptosConfig.isIndexerRequest(url)) {
const indexerResponse = result.data as any;
// errors from indexer
// Handle Indexer general errors
if (indexerResponse.errors) {
throw new AptosApiError(
options,
Expand Down
13 changes: 12 additions & 1 deletion src/client/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,18 @@ export async function get<Req extends {}, Res extends {}>(
export async function getAptosFullNode<Req extends {}, Res extends {}>(
options: GetAptosRequestOptions,
): Promise<AptosResponse<Req, Res>> {
return get<Req, Res>({ ...options, type: AptosApiType.FULLNODE });
const { aptosConfig } = options;

return get<Req, Res>({
...options,
type: AptosApiType.FULLNODE,
overrides: {
...aptosConfig.clientConfig,
...aptosConfig.fullnodeConfig,
...options.overrides,
HEADERS: { ...aptosConfig.clientConfig?.HEADERS, ...aptosConfig.fullnodeConfig?.HEADERS },
},
});
}

/// This function is a helper for paginating using a function wrapping an API
Expand Down
52 changes: 45 additions & 7 deletions src/client/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,7 @@ export async function post<Req extends {}, Res extends {}>(
contentType,
acceptType,
params,
overrides: {
...aptosConfig.clientConfig,
...overrides,
},
overrides,
},
aptosConfig,
);
Expand All @@ -82,17 +79,58 @@ export async function post<Req extends {}, Res extends {}>(
export async function postAptosFullNode<Req extends {}, Res extends {}>(
options: PostAptosRequestOptions,
): Promise<AptosResponse<Req, Res>> {
return post<Req, Res>({ ...options, type: AptosApiType.FULLNODE });
const { aptosConfig } = options;

return post<Req, Res>({
...options,
type: AptosApiType.FULLNODE,
overrides: {
...aptosConfig.clientConfig,
...aptosConfig.fullnodeConfig,
...options.overrides,
HEADERS: { ...aptosConfig.clientConfig?.HEADERS, ...aptosConfig.fullnodeConfig?.HEADERS },
},
});
}

export async function postAptosIndexer<Req extends {}, Res extends {}>(
options: PostAptosRequestOptions,
): Promise<AptosResponse<Req, Res>> {
return post<Req, Res>({ ...options, type: AptosApiType.INDEXER });
const { aptosConfig } = options;

return post<Req, Res>({
...options,
type: AptosApiType.INDEXER,
overrides: {
...aptosConfig.clientConfig,
...aptosConfig.indexerConfig,
...options.overrides,
HEADERS: { ...aptosConfig.clientConfig?.HEADERS, ...aptosConfig.indexerConfig?.HEADERS },
},
});
}

export async function postAptosFaucet<Req extends {}, Res extends {}>(
options: PostAptosRequestOptions,
): Promise<AptosResponse<Req, Res>> {
return post<Req, Res>({ ...options, type: AptosApiType.FAUCET });
const { aptosConfig } = options;
// Faucet does not support API_KEY
// Create a new object with the desired modification
const modifiedAptosConfig = {
...aptosConfig,
clientConfig: { ...aptosConfig.clientConfig },
};
// Delete API_KEY config
delete modifiedAptosConfig?.clientConfig?.API_KEY;

return post<Req, Res>({
...options,
type: AptosApiType.FAUCET,
overrides: {
...modifiedAptosConfig.clientConfig,
...modifiedAptosConfig.faucetConfig,
...options.overrides,
HEADERS: { ...modifiedAptosConfig.clientConfig?.HEADERS, ...modifiedAptosConfig.faucetConfig?.HEADERS },
},
});
}
1 change: 1 addition & 0 deletions src/core/account/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./Ed25519Account";
export * from "./Account";
export * from "./SingleKeyAccount";
export * from "./utils";
39 changes: 39 additions & 0 deletions src/core/account/utils/address.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { sha3_256 } from "@noble/hashes/sha3";
import { AccountAddress } from "../../accountAddress";
import { DeriveScheme } from "../../../types";

/**
* Creates an object address from creator address and seed
*
* @param creatorAddress The object creator account address
* @param seed The seed in either Uint8Array | string type
*
* @returns The object account address
*/
export const createObjectAddress = (creatorAddress: AccountAddress, seed: Uint8Array | string): AccountAddress => {
const creatorBytes = creatorAddress.bcsToBytes();

const seedBytes = typeof seed === "string" ? Buffer.from(seed, "utf8") : seed;

const bytes = new Uint8Array([...creatorBytes, ...seedBytes, DeriveScheme.DeriveObjectAddressFromSeed]);

return new AccountAddress(sha3_256(bytes));
};

/**
* Creates a token object address from creator address, collection name and token name
*
* @param creatorAddress The token creator account address
* @param collectionName The collection name
* @param tokenName The token name
*
* @returns The token account address
*/
export const createTokenAddress = (
creatorAddress: AccountAddress,
collectionName: string,
tokenName: string,
): AccountAddress => {
const seed = `${collectionName}::${tokenName}`;
return createObjectAddress(creatorAddress, seed);
};
1 change: 1 addition & 0 deletions src/core/account/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./address";
46 changes: 40 additions & 6 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ export type AptosSettings = {
readonly clientConfig?: ClientConfig;

readonly client?: Client;

readonly fullnodeConfig?: FullNodeConfig;

readonly indexerConfig?: IndexerConfig;

readonly faucetConfig?: FaucetConfig;
};

/**
Expand Down Expand Up @@ -175,16 +181,44 @@ export interface WhereArg<T extends {}> {
/**
* A configuration object we can pass with the request to the server.
*
* @param AUTH_TOKEN - an auth token to send with a faucet request
* @param API_KEY - api key generated from developer portal {@link https://developers.aptoslabs.com/manage/api-keys}}
* @param HEADERS - extra headers we want to send with the request
* @param WITH_CREDENTIALS - whether to carry cookies. By default, it is set to true and cookies will be sent
*/
export type ClientConfig = {
AUTH_TOKEN?: string;
export type ClientConfig = ClientHeadersType & {
WITH_CREDENTIALS?: boolean;
API_KEY?: string;
};

/**
* A Fullnode only configuration object
*
* @param HEADERS - extra headers we want to send with the request
*/
export type FullNodeConfig = ClientHeadersType;

/**
* An Indexer only configuration object
*
* @param HEADERS - extra headers we want to send with the request
*/
export type IndexerConfig = ClientHeadersType;

/**
* A Faucet only configuration object
*
* @param HEADERS - extra headers we want to send with the request
* @param AUTH_TOKEN - an auth token to send with a faucet request
*/
export type FaucetConfig = ClientHeadersType & {
AUTH_TOKEN?: string;
};

/**
* General type definition for client HEADERS
*/
export type ClientHeadersType = {
HEADERS?: Record<string, string | number | boolean>;
WITH_CREDENTIALS?: boolean;
};

export interface ClientRequest<Req> {
Expand All @@ -193,7 +227,7 @@ export interface ClientRequest<Req> {
body?: Req;
contentType?: string;
params?: any;
overrides?: ClientConfig;
overrides?: ClientConfig & FullNodeConfig & IndexerConfig & FaucetConfig;
headers?: Record<string, any>;
}

Expand Down Expand Up @@ -233,7 +267,7 @@ export type AptosRequest = {
acceptType?: string;
params?: Record<string, string | AnyNumber | boolean | undefined>;
originMethod?: string;
overrides?: ClientConfig;
overrides?: ClientConfig & FullNodeConfig & IndexerConfig & FaucetConfig;
};

/**
Expand Down
2 changes: 2 additions & 0 deletions tests/e2e/api/digitalAsset.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ async function setupToken(): Promise<string> {
)[0].current_token_data?.token_data_id!;
}

jest.setTimeout(20000);

describe("DigitalAsset", () => {
let tokenAddress: string;

Expand Down
Loading

0 comments on commit c55f110

Please sign in to comment.