Skip to content

Commit 5a2994e

Browse files
authored
Merge pull request #725 from Sifchain/realitySpiral/coinabseAdvancedTrading
feat: implement advanced coinbase trading
2 parents d492308 + 0c3a4a7 commit 5a2994e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+3663
-513
lines changed

agent/src/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
tradePlugin,
3535
tokenContractPlugin,
3636
webhookPlugin,
37+
advancedTradePlugin,
3738
} from "@ai16z/plugin-coinbase";
3839
import { confluxPlugin } from "@ai16z/plugin-conflux";
3940
import { imageGenerationPlugin } from "@ai16z/plugin-image-generation";
@@ -400,7 +401,7 @@ export function createAgent(
400401
: null,
401402
...(getSecret(character, "COINBASE_API_KEY") &&
402403
getSecret(character, "COINBASE_PRIVATE_KEY")
403-
? [coinbaseMassPaymentsPlugin, tradePlugin, tokenContractPlugin]
404+
? [coinbaseMassPaymentsPlugin, tradePlugin, tokenContractPlugin, advancedTradePlugin]
404405
: []),
405406
getSecret(character, "COINBASE_API_KEY") &&
406407
getSecret(character, "COINBASE_PRIVATE_KEY") &&
-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/** @type {import('eslint').Linter.Config} */
2+
module.exports = {
3+
parser: '@typescript-eslint/parser',
4+
extends: [
5+
'eslint:recommended',
6+
'plugin:@typescript-eslint/recommended',
7+
'prettier',
8+
'plugin:prettier/recommended',
9+
],
10+
plugins: ['prettier'],
11+
rules: {
12+
'prettier/prettier': 'error',
13+
'@typescript-eslint/explicit-module-boundary-types': 'off',
14+
'@typescript-eslint/no-explicit-any': 'off',
15+
},
16+
ignorePatterns: ['**/dist/**', '**/node_modules/**', '**/*.md'],
17+
env: {
18+
node: true, // Add this line to recognize Node.js globals
19+
es2021: true, // Optionally include modern JavaScript features
20+
},
21+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.env
2+
src/rest/main.ts
3+
dist/
4+
node_modules/
5+
.idea/
6+
package-lock.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"semi": true,
3+
"singleQuote": true,
4+
"trailingComma": "es5"
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Changelog
2+
3+
## [0.1.0] - 2024-SEP-06
4+
5+
### Added
6+
7+
- Support for all Coinbase Advanced API REST endpoints via central client
8+
- Custom Request and Response objects for endpoints
9+
- Custom error types
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Coinbase Advanced API TypeScript SDK
2+
3+
Welcome to the Coinbase Advanced API TypeScript SDK. This TypeScript project was created to allow developers to easily plug into the [Coinbase Advanced API](https://docs.cdp.coinbase.com/advanced-trade/docs/welcome).
4+
5+
Coinbase Advanced Trade offers a comprehensive API for traders, providing access to real-time market data, order management, and execution. Elevate your trading strategies and develop sophisticated solutions using our powerful tools and features.
6+
7+
For more information on all the available REST endpoints, see the [API Reference](https://docs.cdp.coinbase.com/advanced-trade/reference/).
8+
9+
---
10+
11+
## Installation
12+
13+
```bash
14+
npm install
15+
```
16+
17+
---
18+
19+
## Build and Use
20+
21+
To build the project, run the following command:
22+
23+
```bash
24+
npm run build
25+
```
26+
27+
_Note: To avoid potential issues, do not forget to build your project again after making any changes to it._
28+
29+
After building the project, each `.ts` file will have its `.js` counterpart generated.
30+
31+
To run a file, use the following command:
32+
33+
```
34+
node dist/{INSERT-FILENAME}.js
35+
```
36+
37+
For example, a `main.ts` file would be run like:
38+
39+
```bash
40+
node dist/main.js
41+
```
42+
43+
---
44+
45+
## Coinbase Developer Platform (CDP) API Keys
46+
47+
This SDK uses Cloud Developer Platform (CDP) API keys. To use this SDK, you will need to create a CDP API key and secret by following the instructions [here](https://docs.cdp.coinbase.com/advanced-trade/docs/getting-started).
48+
Make sure to save your API key and secret in a safe place. You will not be able to retrieve your secret again.
49+
50+
---
51+
52+
## Importing the RESTClient
53+
54+
All the REST endpoints are available directly from the client, therefore it's all you need to import.
55+
56+
```
57+
import { RESTClient } from './rest';
58+
```
59+
60+
---
61+
62+
## Authentication
63+
64+
Authentication of CDP API Keys is handled automatically by the SDK when making a REST request.
65+
66+
After creating your CDP API keys, store them using your desired method and simply pass them into the client during initialization like:
67+
68+
```
69+
const client = new RESTClient(API_KEY, API_SECRET);
70+
```
71+
72+
---
73+
74+
## Making Requests
75+
76+
Here are a few examples requests:
77+
78+
**[List Accounts](https://docs.cdp.coinbase.com/advanced-trade/reference/retailbrokerageapi_getaccounts)**
79+
80+
```
81+
client
82+
.listAccounts({})
83+
.then((result) => {
84+
console.log(result);
85+
})
86+
.catch((error) => {
87+
console.error(error.message);
88+
});
89+
```
90+
91+
**[Get Product](https://docs.cdp.coinbase.com/advanced-trade/reference/retailbrokerageapi_getproduct)**
92+
93+
```
94+
client
95+
.getProduct({productId: "BTC-USD"})
96+
.then((result) => {
97+
console.log(result);
98+
})
99+
.catch((error) => {
100+
console.error(error.message);
101+
});
102+
```
103+
104+
**[Create Order](https://docs.cdp.coinbase.com/advanced-trade/reference/retailbrokerageapi_postorder)**
105+
106+
_$10 Market Buy on BTC-USD_
107+
108+
```
109+
client
110+
.createOrder({
111+
clientOrderId: "00000001",
112+
productId: "BTC-USD",
113+
side: OrderSide.BUY,
114+
orderConfiguration:{
115+
market_market_ioc: {
116+
quote_size: "10"
117+
}
118+
}
119+
})
120+
.then((result) => {
121+
console.log(result);
122+
})
123+
.catch((error) => {
124+
console.error(error.message);
125+
});
126+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"name": "@coinbase-samples/advanced-sdk-ts",
3+
"version": "0.1.0",
4+
"main": "dist/main.js",
5+
"scripts": {
6+
"test": "echo \"Error: no test specified\" && exit 1",
7+
"build": "tsc",
8+
"lint": "eslint . --ext .js,.ts",
9+
"format": "prettier --write \"**/*.{js,ts,tsx,json,css,md}\""
10+
},
11+
"files": [
12+
"dist/"
13+
],
14+
"keywords": [],
15+
"author": "",
16+
"license": "ISC",
17+
"description": "",
18+
"dependencies": {
19+
"jsonwebtoken": "^9.0.2",
20+
"node-fetch": "^2.6.1"
21+
},
22+
"devDependencies": {
23+
"@types/jsonwebtoken": "^9.0.7",
24+
"@types/node-fetch": "^2.6.11",
25+
"@typescript-eslint/eslint-plugin": "^5.59.0",
26+
"@typescript-eslint/parser": "^5.59.0",
27+
"dotenv": "^16.4.5",
28+
"eslint": "^8.35.0",
29+
"eslint-config-prettier": "^8.5.0",
30+
"eslint-plugin-prettier": "^4.2.1",
31+
"prettier": "^2.8.8",
32+
"typescript": "^5.5.4"
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export const BASE_URL = 'api.coinbase.com';
2+
export const API_PREFIX = '/api/v3/brokerage';
3+
export const ALGORITHM = 'ES256';
4+
export const VERSION = '0.1.0';
5+
export const USER_AGENT = `coinbase-advanced-ts/${VERSION}`;
6+
export const JWT_ISSUER = 'cdp';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import jwt from 'jsonwebtoken';
2+
import { BASE_URL, ALGORITHM, JWT_ISSUER } from './constants';
3+
import crypto from 'crypto';
4+
5+
export function generateToken(
6+
requestMethod: string,
7+
requestPath: string,
8+
apiKey: string,
9+
apiSecret: string
10+
): string {
11+
const uri = `${requestMethod} ${BASE_URL}${requestPath}`;
12+
const payload = {
13+
iss: JWT_ISSUER,
14+
nbf: Math.floor(Date.now() / 1000),
15+
exp: Math.floor(Date.now() / 1000) + 120,
16+
sub: apiKey,
17+
uri,
18+
};
19+
20+
const header = {
21+
alg: ALGORITHM,
22+
kid: apiKey,
23+
nonce: crypto.randomBytes(16).toString('hex'),
24+
};
25+
const options: jwt.SignOptions = {
26+
algorithm: ALGORITHM as jwt.Algorithm,
27+
header: header,
28+
};
29+
30+
return jwt.sign(payload, apiSecret as string, options);
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { API_PREFIX } from '../constants';
2+
import { RESTBase } from './rest-base';
3+
import {
4+
GetAccountRequest,
5+
GetAccountResponse,
6+
ListAccountsRequest,
7+
ListAccountsResponse,
8+
} from './types/accounts-types';
9+
import { method } from './types/request-types';
10+
11+
// [GET] Get Account
12+
// Official Documentation: https://docs.cdp.coinbase.com/advanced-trade/reference/retailbrokerageapi_getaccount
13+
export function getAccount(
14+
this: RESTBase,
15+
{ accountUuid }: GetAccountRequest
16+
): Promise<GetAccountResponse> {
17+
return this.request({
18+
method: method.GET,
19+
endpoint: `${API_PREFIX}/accounts/${accountUuid}`,
20+
isPublic: false,
21+
});
22+
}
23+
24+
// [GET] List Accounts
25+
// Official Documentation: https://docs.cdp.coinbase.com/advanced-trade/reference/retailbrokerageapi_getaccounts
26+
export function listAccounts(
27+
this: RESTBase,
28+
requestParams: ListAccountsRequest
29+
): Promise<ListAccountsResponse> {
30+
return this.request({
31+
method: method.GET,
32+
endpoint: `${API_PREFIX}/accounts`,
33+
queryParams: requestParams,
34+
isPublic: false,
35+
});
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { API_PREFIX } from '../constants';
2+
import { RESTBase } from './rest-base';
3+
import {
4+
CommitConvertTradeRequest,
5+
CommitConvertTradeResponse,
6+
CreateConvertQuoteRequest,
7+
CreateConvertQuoteResponse,
8+
GetConvertTradeRequest,
9+
GetConvertTradeResponse,
10+
} from './types/converts-types';
11+
import { method } from './types/request-types';
12+
13+
// [POST] Create Convert Quote
14+
// Official Documentation: https://docs.cdp.coinbase.com/advanced-trade/reference/retailbrokerageapi_createconvertquote
15+
export function createConvertQuote(
16+
this: RESTBase,
17+
requestParams: CreateConvertQuoteRequest
18+
): Promise<CreateConvertQuoteResponse> {
19+
return this.request({
20+
method: method.POST,
21+
endpoint: `${API_PREFIX}/convert/quote`,
22+
bodyParams: requestParams,
23+
isPublic: false,
24+
});
25+
}
26+
27+
// [GET] Get Convert Trade
28+
// Official Documentation: https://docs.cdp.coinbase.com/advanced-trade/reference/retailbrokerageapi_getconverttrade
29+
export function getConvertTrade(
30+
this: RESTBase,
31+
{ tradeId, ...requestParams }: GetConvertTradeRequest
32+
): Promise<GetConvertTradeResponse> {
33+
return this.request({
34+
method: method.GET,
35+
endpoint: `${API_PREFIX}/convert/trade/${tradeId}`,
36+
queryParams: requestParams,
37+
isPublic: false,
38+
});
39+
}
40+
41+
// [POST] Commit Connvert Trade
42+
// https://docs.cdp.coinbase.com/advanced-trade/reference/retailbrokerageapi_commitconverttrade
43+
export function commitConvertTrade(
44+
this: RESTBase,
45+
{ tradeId, ...requestParams }: CommitConvertTradeRequest
46+
): Promise<CommitConvertTradeResponse> {
47+
return this.request({
48+
method: method.POST,
49+
endpoint: `${API_PREFIX}/convert/trade/${tradeId}`,
50+
bodyParams: requestParams,
51+
isPublic: false,
52+
});
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { API_PREFIX } from '../constants';
2+
import { RESTBase } from './rest-base';
3+
4+
import { method } from './types/request-types';
5+
import { GetAPIKeyPermissionsResponse } from './types/dataAPI-types';
6+
7+
// [GET] Get API Key Permissions
8+
// Official Documentation: https://docs.cdp.coinbase.com/advanced-trade/reference/retailbrokerageapi_getapikeypermissions
9+
export function getAPIKeyPermissions(
10+
this: RESTBase
11+
): Promise<GetAPIKeyPermissionsResponse> {
12+
return this.request({
13+
method: method.GET,
14+
endpoint: `${API_PREFIX}/key_permissions`,
15+
isPublic: false,
16+
});
17+
}

0 commit comments

Comments
 (0)