feat: add @suite/yield-xyz package with generate API types & methods

This commit is contained in:
Jiří Čermák
2026-02-03 09:56:16 +01:00
committed by Jiří Čermák
parent fe2087328a
commit 5ad0acdf2e
35 changed files with 11302 additions and 258 deletions

View File

@@ -14,6 +14,8 @@ npmMinimalAgeGate: 20160
npmPreapprovedPackages:
- "@evolu/*"
- "@types/invity-api@*"
# orval@8.2.0 actually include fix of an vulnerability introduced in prev. versions https://github.com/orval-labs/orval/releases/tag/v8.2.0
- "orval@8.2.0"
plugins:
- checksum: 5e73a1acbb9741fce1e8335e243c9480ea2107b9b4b65ed7643785ddea9e3019aee254a92a853b1cd71023b16fff5b7d3afd5256fe57cd35a54f8785b8c30281

View File

@@ -77,3 +77,4 @@ yup
viem
@tanstack/react-query-devtools
@tanstack/react-query
orval

View File

@@ -0,0 +1,18 @@
# Earn API
## Yield XYZ API
1. OpenAPI spec is fetched by `scripts/fetchSpec.mjs`
2. Orval generates types and methods to `src/api`
3. A Trezor proxy service is deployed at `YIELD_XYZ_BASE_URL` (`config/index.ts`). So no need to manually provide API key.
## Yield opportunities
`useGetYieldOpportunities`: Fetch all enabled Yield XYZ opportunities.
## Enter a yield opportunity
1. Let Yield XYZ to generate transaction payloads: `useEnterYieldOpportunity`
2. Sign TX: handled without Yield XYZ
3. Broadcast TX: handle without Yield XYZ
4. Submit TX hash: `useSubmitTxHash`

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,80 @@
import { ClientGeneratorsBuilder, defineConfig } from 'orval';
import { resolve } from 'path';
const pascalCase = (value: string) =>
value
.replace(/[_-]+([a-z0-9])/g, (_, char: string) => char.toUpperCase())
.replace(/^[a-z]/, char => char.toUpperCase());
const camelCase = (value: string) => value.replace(/^[A-Z]/, char => char.toLowerCase());
const OUTPUT_DIR = resolve(import.meta.dirname, './src/api');
// eslint-disable-next-line import/no-default-export
export default defineConfig({
worker: {
input: {
target: resolve(import.meta.dirname, './openapi.yaml'),
},
output: {
mode: 'tags',
target: resolve(OUTPUT_DIR, 'index.ts'),
mock: false,
// Use our custom Prettier config
prettier: false,
clean: true,
tsconfig: './tsconfig.json',
packageJson: './package.json',
propertySortOrder: 'Specification',
client: clients => {
const fetchClient = clients.fetch;
return {
...fetchClient,
client: async (verbOptions, options, output) => {
const result = await fetchClient.client(verbOptions, options, output);
const methodName = camelCase(verbOptions.operationName);
return {
...result,
// Make sure the exported methods are in camelCase
implementation: result.implementation.replace(
// Exclude `async` too because there's some Eslint requiring await in async functions ignoring the given fn can return a promise
`export const ${verbOptions.operationName} = async`,
`export const ${methodName} =`,
),
};
},
} satisfies ClientGeneratorsBuilder;
},
// Prefer `fetch` over `axios`
httpClient: 'fetch',
indexFiles: true,
// Include response headers in the generated types and method results
headers: true,
workspace: OUTPUT_DIR,
override: {
useNamedParameters: true,
useTypeOverInterfaces: true,
enumGenerationType: 'const',
transformer: verb => {
const [prefix] = verb.operationId.split('_');
return {
...verb,
// Make TS types PascalCase and remove the group prefix
operationName: pascalCase(verb.operationName).replace(prefix, ''),
};
},
mutator: {
name: 'httpClient',
path: resolve(import.meta.dirname, './src/httpClient.ts'),
},
fetch: {
forceSuccessResponse: true,
},
},
},
},
});

View File

@@ -0,0 +1,25 @@
{
"name": "@suite-common/earn-api",
"version": "1.0.0",
"private": true,
"license": "See LICENSE.md in repo root",
"sideEffects": false,
"main": "src/index",
"scripts": {
"depcheck": "yarn g:depcheck",
"lint:js": "yarn g:eslint './**/*.{ts,mjs}'",
"type-check": "yarn g:tsc --build",
"format": "prettier --write \"**/*.{ts,yaml}\"",
"orval": "orval --config ./orval.config.ts",
"api:fetch": "node ./scripts/fetchSpec.mjs",
"api:generate": "yarn orval",
"api:update": "yarn api:fetch && yarn api:generate && yarn lint:js --fix && yarn format"
},
"devDependencies": {
"orval": "8.2.0",
"prettier": "3.7.4"
},
"dependencies": {
"@suite-common/react-query": "workspace:^"
}
}

View File

@@ -0,0 +1,30 @@
/* eslint-disable no-console */
// @ts-check
import { writeFile } from 'fs/promises';
import { join } from 'path';
async function fetchSpec() {
const response = await fetch('https://api.yield.xyz/docs.yaml', {
headers: {
Accept: 'application/yaml',
},
});
if (!response.ok) {
throw new Error(`Failed to fetch spec: ${response.statusText}`);
}
return await response.text();
}
async function updateSpec() {
console.log('⏳ Fetching Yield XYZ API spec...');
const specPath = join(process.cwd(), 'openapi.yaml');
const spec = await fetchSpec();
console.log('⏳ Saving Yield XYZ API spec to ', specPath);
await writeFile(specPath, spec, 'utf-8');
console.log('✅ Yield XYZ API spec updated successfully');
}
updateSpec().catch(console.error);

View File

@@ -0,0 +1,567 @@
/**
* Generated by orval v7.17.2 🍺
* Do not edit manually.
* Yield.xyz API
* API Documentation
* OpenAPI spec version: 1.0
*/
import type {
ActionDto,
ActionsControllerEnterYield400,
ActionsControllerEnterYield401,
ActionsControllerEnterYield403,
ActionsControllerEnterYield429,
ActionsControllerEnterYield500,
ActionsControllerExitYield400,
ActionsControllerExitYield401,
ActionsControllerExitYield403,
ActionsControllerExitYield429,
ActionsControllerExitYield500,
ActionsControllerGetAction400,
ActionsControllerGetAction401,
ActionsControllerGetAction429,
ActionsControllerGetAction500,
ActionsControllerGetActionPathParameters,
ActionsControllerGetActions200,
ActionsControllerGetActions400,
ActionsControllerGetActions401,
ActionsControllerGetActions429,
ActionsControllerGetActions500,
ActionsControllerGetActionsParams,
ActionsControllerManageYield400,
ActionsControllerManageYield401,
ActionsControllerManageYield403,
ActionsControllerManageYield429,
ActionsControllerManageYield500,
CreateActionDto,
CreateManageActionDto,
SubmitHashDto,
SubmitTransactionDto,
TransactionDto,
TransactionsControllerGetTransaction400,
TransactionsControllerGetTransaction401,
TransactionsControllerGetTransaction429,
TransactionsControllerGetTransaction500,
TransactionsControllerGetTransactionPathParameters,
TransactionsControllerSubmitTransaction401,
TransactionsControllerSubmitTransaction429,
TransactionsControllerSubmitTransaction500,
TransactionsControllerSubmitTransactionHash401,
TransactionsControllerSubmitTransactionHash429,
TransactionsControllerSubmitTransactionHash500,
TransactionsControllerSubmitTransactionHashPathParameters,
TransactionsControllerSubmitTransactionPathParameters,
} from './index.schemas';
import { httpClient } from '../httpClient';
/**
* Retrieve all actions performed by a user, with optional filtering by yield, status, category, etc. In the future, this may include personalized action recommendations.
* @summary Get user actions
*/
export type GetActionsResponse200 = {
data: ActionsControllerGetActions200;
status: 200;
};
export type GetActionsResponse400 = {
data: ActionsControllerGetActions400;
status: 400;
};
export type GetActionsResponse401 = {
data: ActionsControllerGetActions401;
status: 401;
};
export type GetActionsResponse429 = {
data: ActionsControllerGetActions429;
status: 429;
};
export type GetActionsResponse500 = {
data: ActionsControllerGetActions500;
status: 500;
};
export type GetActionsResponseSuccess = GetActionsResponse200 & {
headers: Headers;
};
export type GetActionsResponseError = (
| GetActionsResponse400
| GetActionsResponse401
| GetActionsResponse429
| GetActionsResponse500
) & {
headers: Headers;
};
export const getGetActionsUrl = (params: ActionsControllerGetActionsParams) => {
const normalizedParams = new URLSearchParams();
Object.entries(params || {}).forEach(([key, value]) => {
if (value !== undefined) {
normalizedParams.append(key, value === null ? 'null' : value.toString());
}
});
const stringifiedParams = normalizedParams.toString();
return stringifiedParams.length > 0 ? `/v1/actions?${stringifiedParams}` : `/v1/actions`;
};
export const getActions = (
params: ActionsControllerGetActionsParams,
options?: RequestInit,
): Promise<GetActionsResponseSuccess> =>
httpClient<GetActionsResponseSuccess>(getGetActionsUrl(params), {
...options,
method: 'GET',
});
/**
* Retrieve detailed information about a specific action including current status, transactions, and execution details.
* @summary Get action details
*/
export type GetActionResponse200 = {
data: ActionDto;
status: 200;
};
export type GetActionResponse400 = {
data: ActionsControllerGetAction400;
status: 400;
};
export type GetActionResponse401 = {
data: ActionsControllerGetAction401;
status: 401;
};
export type GetActionResponse404 = {
data: void;
status: 404;
};
export type GetActionResponse429 = {
data: ActionsControllerGetAction429;
status: 429;
};
export type GetActionResponse500 = {
data: ActionsControllerGetAction500;
status: 500;
};
export type GetActionResponseSuccess = GetActionResponse200 & {
headers: Headers;
};
export type GetActionResponseError = (
| GetActionResponse400
| GetActionResponse401
| GetActionResponse404
| GetActionResponse429
| GetActionResponse500
) & {
headers: Headers;
};
export const getGetActionUrl = ({ actionId }: ActionsControllerGetActionPathParameters) =>
`/v1/actions/${actionId}`;
export const getAction = (
{ actionId }: ActionsControllerGetActionPathParameters,
options?: RequestInit,
): Promise<GetActionResponseSuccess> =>
httpClient<GetActionResponseSuccess>(getGetActionUrl({ actionId }), {
...options,
method: 'GET',
});
/**
* Generate the transactions needed to enter a yield position with the provided parameters.
* @summary Enter a yield
*/
export type EnterYieldResponse201 = {
data: ActionDto;
status: 201;
};
export type EnterYieldResponse400 = {
data: ActionsControllerEnterYield400;
status: 400;
};
export type EnterYieldResponse401 = {
data: ActionsControllerEnterYield401;
status: 401;
};
export type EnterYieldResponse403 = {
data: ActionsControllerEnterYield403;
status: 403;
};
export type EnterYieldResponse404 = {
data: void;
status: 404;
};
export type EnterYieldResponse429 = {
data: ActionsControllerEnterYield429;
status: 429;
};
export type EnterYieldResponse500 = {
data: ActionsControllerEnterYield500;
status: 500;
};
export type EnterYieldResponseSuccess = EnterYieldResponse201 & {
headers: Headers;
};
export type EnterYieldResponseError = (
| EnterYieldResponse400
| EnterYieldResponse401
| EnterYieldResponse403
| EnterYieldResponse404
| EnterYieldResponse429
| EnterYieldResponse500
) & {
headers: Headers;
};
export const getEnterYieldUrl = () => `/v1/actions/enter`;
export const enterYield = (
createActionDto: CreateActionDto,
options?: RequestInit,
): Promise<EnterYieldResponseSuccess> =>
httpClient<EnterYieldResponseSuccess>(getEnterYieldUrl(), {
...options,
method: 'POST',
headers: { 'Content-Type': 'application/json', ...options?.headers },
body: JSON.stringify(createActionDto),
});
/**
* Generate the transactions needed to exit a yield position with the provided parameters.
* @summary Exit a yield
*/
export type ExitYieldResponse201 = {
data: ActionDto;
status: 201;
};
export type ExitYieldResponse400 = {
data: ActionsControllerExitYield400;
status: 400;
};
export type ExitYieldResponse401 = {
data: ActionsControllerExitYield401;
status: 401;
};
export type ExitYieldResponse403 = {
data: ActionsControllerExitYield403;
status: 403;
};
export type ExitYieldResponse404 = {
data: void;
status: 404;
};
export type ExitYieldResponse429 = {
data: ActionsControllerExitYield429;
status: 429;
};
export type ExitYieldResponse500 = {
data: ActionsControllerExitYield500;
status: 500;
};
export type ExitYieldResponseSuccess = ExitYieldResponse201 & {
headers: Headers;
};
export type ExitYieldResponseError = (
| ExitYieldResponse400
| ExitYieldResponse401
| ExitYieldResponse403
| ExitYieldResponse404
| ExitYieldResponse429
| ExitYieldResponse500
) & {
headers: Headers;
};
export const getExitYieldUrl = () => `/v1/actions/exit`;
export const exitYield = (
createActionDto: CreateActionDto,
options?: RequestInit,
): Promise<ExitYieldResponseSuccess> =>
httpClient<ExitYieldResponseSuccess>(getExitYieldUrl(), {
...options,
method: 'POST',
headers: { 'Content-Type': 'application/json', ...options?.headers },
body: JSON.stringify(createActionDto),
});
/**
* Generate the transactions needed to perform management actions on a yield position.
* @summary Manage a yield
*/
export type ManageYieldResponse201 = {
data: ActionDto;
status: 201;
};
export type ManageYieldResponse400 = {
data: ActionsControllerManageYield400;
status: 400;
};
export type ManageYieldResponse401 = {
data: ActionsControllerManageYield401;
status: 401;
};
export type ManageYieldResponse403 = {
data: ActionsControllerManageYield403;
status: 403;
};
export type ManageYieldResponse404 = {
data: void;
status: 404;
};
export type ManageYieldResponse429 = {
data: ActionsControllerManageYield429;
status: 429;
};
export type ManageYieldResponse500 = {
data: ActionsControllerManageYield500;
status: 500;
};
export type ManageYieldResponseSuccess = ManageYieldResponse201 & {
headers: Headers;
};
export type ManageYieldResponseError = (
| ManageYieldResponse400
| ManageYieldResponse401
| ManageYieldResponse403
| ManageYieldResponse404
| ManageYieldResponse429
| ManageYieldResponse500
) & {
headers: Headers;
};
export const getManageYieldUrl = () => `/v1/actions/manage`;
export const manageYield = (
createManageActionDto: CreateManageActionDto,
options?: RequestInit,
): Promise<ManageYieldResponseSuccess> =>
httpClient<ManageYieldResponseSuccess>(getManageYieldUrl(), {
...options,
method: 'POST',
headers: { 'Content-Type': 'application/json', ...options?.headers },
body: JSON.stringify(createManageActionDto),
});
/**
* Submit the transaction hash after broadcasting a transaction to the blockchain. This updates the transaction status and enables tracking.
* @summary Submit transaction hash
*/
export type SubmitTransactionHashResponse200 = {
data: TransactionDto;
status: 200;
};
export type SubmitTransactionHashResponse400 = {
data: void;
status: 400;
};
export type SubmitTransactionHashResponse401 = {
data: TransactionsControllerSubmitTransactionHash401;
status: 401;
};
export type SubmitTransactionHashResponse404 = {
data: void;
status: 404;
};
export type SubmitTransactionHashResponse429 = {
data: TransactionsControllerSubmitTransactionHash429;
status: 429;
};
export type SubmitTransactionHashResponse500 = {
data: TransactionsControllerSubmitTransactionHash500;
status: 500;
};
export type SubmitTransactionHashResponseSuccess = SubmitTransactionHashResponse200 & {
headers: Headers;
};
export type SubmitTransactionHashResponseError = (
| SubmitTransactionHashResponse400
| SubmitTransactionHashResponse401
| SubmitTransactionHashResponse404
| SubmitTransactionHashResponse429
| SubmitTransactionHashResponse500
) & {
headers: Headers;
};
export const getSubmitTransactionHashUrl = ({
transactionId,
}: TransactionsControllerSubmitTransactionHashPathParameters) =>
`/v1/transactions/${transactionId}/submit-hash`;
export const submitTransactionHash = (
{ transactionId }: TransactionsControllerSubmitTransactionHashPathParameters,
submitHashDto: SubmitHashDto,
options?: RequestInit,
): Promise<SubmitTransactionHashResponseSuccess> =>
httpClient<SubmitTransactionHashResponseSuccess>(
getSubmitTransactionHashUrl({ transactionId }),
{
...options,
method: 'PUT',
headers: { 'Content-Type': 'application/json', ...options?.headers },
body: JSON.stringify(submitHashDto),
},
);
/**
* Submit the transaction to the blockchain.
* @summary Submit transaction
*/
export type SubmitTransactionResponse200 = {
data: TransactionDto;
status: 200;
};
export type SubmitTransactionResponse400 = {
data: void;
status: 400;
};
export type SubmitTransactionResponse401 = {
data: TransactionsControllerSubmitTransaction401;
status: 401;
};
export type SubmitTransactionResponse404 = {
data: void;
status: 404;
};
export type SubmitTransactionResponse429 = {
data: TransactionsControllerSubmitTransaction429;
status: 429;
};
export type SubmitTransactionResponse500 = {
data: TransactionsControllerSubmitTransaction500;
status: 500;
};
export type SubmitTransactionResponseSuccess = SubmitTransactionResponse200 & {
headers: Headers;
};
export type SubmitTransactionResponseError = (
| SubmitTransactionResponse400
| SubmitTransactionResponse401
| SubmitTransactionResponse404
| SubmitTransactionResponse429
| SubmitTransactionResponse500
) & {
headers: Headers;
};
export const getSubmitTransactionUrl = ({
transactionId,
}: TransactionsControllerSubmitTransactionPathParameters) =>
`/v1/transactions/${transactionId}/submit`;
export const submitTransaction = (
{ transactionId }: TransactionsControllerSubmitTransactionPathParameters,
submitTransactionDto: SubmitTransactionDto,
options?: RequestInit,
): Promise<SubmitTransactionResponseSuccess> =>
httpClient<SubmitTransactionResponseSuccess>(getSubmitTransactionUrl({ transactionId }), {
...options,
method: 'POST',
headers: { 'Content-Type': 'application/json', ...options?.headers },
body: JSON.stringify(submitTransactionDto),
});
/**
* Retrieve detailed information about a specific transaction including current status, hash, and execution details.
* @summary Get transaction details
*/
export type GetTransactionResponse200 = {
data: TransactionDto;
status: 200;
};
export type GetTransactionResponse400 = {
data: TransactionsControllerGetTransaction400;
status: 400;
};
export type GetTransactionResponse401 = {
data: TransactionsControllerGetTransaction401;
status: 401;
};
export type GetTransactionResponse404 = {
data: void;
status: 404;
};
export type GetTransactionResponse429 = {
data: TransactionsControllerGetTransaction429;
status: 429;
};
export type GetTransactionResponse500 = {
data: TransactionsControllerGetTransaction500;
status: 500;
};
export type GetTransactionResponseSuccess = GetTransactionResponse200 & {
headers: Headers;
};
export type GetTransactionResponseError = (
| GetTransactionResponse400
| GetTransactionResponse401
| GetTransactionResponse404
| GetTransactionResponse429
| GetTransactionResponse500
) & {
headers: Headers;
};
export const getGetTransactionUrl = ({
transactionId,
}: TransactionsControllerGetTransactionPathParameters) => `/v1/transactions/${transactionId}`;
export const getTransaction = (
{ transactionId }: TransactionsControllerGetTransactionPathParameters,
options?: RequestInit,
): Promise<GetTransactionResponseSuccess> =>
httpClient<GetTransactionResponseSuccess>(getGetTransactionUrl({ transactionId }), {
...options,
method: 'GET',
});

View File

@@ -0,0 +1,421 @@
/**
* Generated by orval v7.17.2 🍺
* Do not edit manually.
* Yield.xyz API
* API Documentation
* OpenAPI spec version: 1.0
*/
import type {
NetworkDto,
NetworksControllerGetNetworks400,
NetworksControllerGetNetworks401,
NetworksControllerGetNetworks429,
NetworksControllerGetNetworks500,
ProviderDto,
ProvidersControllerGetProvider400,
ProvidersControllerGetProvider401,
ProvidersControllerGetProvider429,
ProvidersControllerGetProvider500,
ProvidersControllerGetProviderPathParameters,
ProvidersControllerGetProviders200,
ProvidersControllerGetProviders400,
ProvidersControllerGetProviders401,
ProvidersControllerGetProviders429,
ProvidersControllerGetProviders500,
ProvidersControllerGetProvidersParams,
YieldDto,
YieldsControllerGetYield400,
YieldsControllerGetYield401,
YieldsControllerGetYield429,
YieldsControllerGetYield500,
YieldsControllerGetYieldPathParameters,
YieldsControllerGetYieldValidators200,
YieldsControllerGetYieldValidators400,
YieldsControllerGetYieldValidators401,
YieldsControllerGetYieldValidators429,
YieldsControllerGetYieldValidators500,
YieldsControllerGetYieldValidatorsParams,
YieldsControllerGetYieldValidatorsPathParameters,
YieldsControllerGetYields200,
YieldsControllerGetYields400,
YieldsControllerGetYields401,
YieldsControllerGetYields429,
YieldsControllerGetYields500,
YieldsControllerGetYieldsParams,
} from './index.schemas';
import { httpClient } from '../httpClient';
/**
* Retrieve a paginated list of available yield opportunities across all supported networks and protocols.
* @summary List all yield opportunities
*/
export type GetYieldsResponse200 = {
data: YieldsControllerGetYields200;
status: 200;
};
export type GetYieldsResponse400 = {
data: YieldsControllerGetYields400;
status: 400;
};
export type GetYieldsResponse401 = {
data: YieldsControllerGetYields401;
status: 401;
};
export type GetYieldsResponse429 = {
data: YieldsControllerGetYields429;
status: 429;
};
export type GetYieldsResponse500 = {
data: YieldsControllerGetYields500;
status: 500;
};
export type GetYieldsResponseSuccess = GetYieldsResponse200 & {
headers: Headers;
};
export type GetYieldsResponseError = (
| GetYieldsResponse400
| GetYieldsResponse401
| GetYieldsResponse429
| GetYieldsResponse500
) & {
headers: Headers;
};
export const getGetYieldsUrl = (params?: YieldsControllerGetYieldsParams) => {
const normalizedParams = new URLSearchParams();
Object.entries(params || {}).forEach(([key, value]) => {
const explodeParameters = ['yieldIds', 'types', 'inputTokens', 'providers'];
if (Array.isArray(value) && explodeParameters.includes(key)) {
value.forEach(v => {
normalizedParams.append(key, v === null ? 'null' : v.toString());
});
return;
}
if (value !== undefined) {
normalizedParams.append(key, value === null ? 'null' : value.toString());
}
});
const stringifiedParams = normalizedParams.toString();
return stringifiedParams.length > 0 ? `/v1/yields?${stringifiedParams}` : `/v1/yields`;
};
export const getYields = (
params?: YieldsControllerGetYieldsParams,
options?: RequestInit,
): Promise<GetYieldsResponseSuccess> =>
httpClient<GetYieldsResponseSuccess>(getGetYieldsUrl(params), {
...options,
method: 'GET',
});
/**
* Retrieve detailed information about a specific yield opportunity including APY, tokens, protocol details, and more.
* @summary Get yield metadata
*/
export type GetYieldResponse200 = {
data: YieldDto;
status: 200;
};
export type GetYieldResponse400 = {
data: YieldsControllerGetYield400;
status: 400;
};
export type GetYieldResponse401 = {
data: YieldsControllerGetYield401;
status: 401;
};
export type GetYieldResponse404 = {
data: void;
status: 404;
};
export type GetYieldResponse429 = {
data: YieldsControllerGetYield429;
status: 429;
};
export type GetYieldResponse500 = {
data: YieldsControllerGetYield500;
status: 500;
};
export type GetYieldResponseSuccess = GetYieldResponse200 & {
headers: Headers;
};
export type GetYieldResponseError = (
| GetYieldResponse400
| GetYieldResponse401
| GetYieldResponse404
| GetYieldResponse429
| GetYieldResponse500
) & {
headers: Headers;
};
export const getGetYieldUrl = ({ yieldId }: YieldsControllerGetYieldPathParameters) =>
`/v1/yields/${yieldId}`;
export const getYield = (
{ yieldId }: YieldsControllerGetYieldPathParameters,
options?: RequestInit,
): Promise<GetYieldResponseSuccess> =>
httpClient<GetYieldResponseSuccess>(getGetYieldUrl({ yieldId }), {
...options,
method: 'GET',
});
/**
* Retrieve a paginated list of validators available for staking or delegation for this yield opportunity.
* @summary Get yield validators
*/
export type GetYieldValidatorsResponse200 = {
data: YieldsControllerGetYieldValidators200;
status: 200;
};
export type GetYieldValidatorsResponse400 = {
data: YieldsControllerGetYieldValidators400;
status: 400;
};
export type GetYieldValidatorsResponse401 = {
data: YieldsControllerGetYieldValidators401;
status: 401;
};
export type GetYieldValidatorsResponse404 = {
data: void;
status: 404;
};
export type GetYieldValidatorsResponse429 = {
data: YieldsControllerGetYieldValidators429;
status: 429;
};
export type GetYieldValidatorsResponse500 = {
data: YieldsControllerGetYieldValidators500;
status: 500;
};
export type GetYieldValidatorsResponseSuccess = GetYieldValidatorsResponse200 & {
headers: Headers;
};
export type GetYieldValidatorsResponseError = (
| GetYieldValidatorsResponse400
| GetYieldValidatorsResponse401
| GetYieldValidatorsResponse404
| GetYieldValidatorsResponse429
| GetYieldValidatorsResponse500
) & {
headers: Headers;
};
export const getGetYieldValidatorsUrl = (
{ yieldId }: YieldsControllerGetYieldValidatorsPathParameters,
params?: YieldsControllerGetYieldValidatorsParams,
) => {
const normalizedParams = new URLSearchParams();
Object.entries(params || {}).forEach(([key, value]) => {
if (value !== undefined) {
normalizedParams.append(key, value === null ? 'null' : value.toString());
}
});
const stringifiedParams = normalizedParams.toString();
return stringifiedParams.length > 0
? `/v1/yields/${yieldId}/validators?${stringifiedParams}`
: `/v1/yields/${yieldId}/validators`;
};
export const getYieldValidators = (
{ yieldId }: YieldsControllerGetYieldValidatorsPathParameters,
params?: YieldsControllerGetYieldValidatorsParams,
options?: RequestInit,
): Promise<GetYieldValidatorsResponseSuccess> =>
httpClient<GetYieldValidatorsResponseSuccess>(getGetYieldValidatorsUrl({ yieldId }, params), {
...options,
method: 'GET',
});
/**
* Retrieve a list of all supported networks that can be used for filtering yields and other operations.
* @summary List all available networks
*/
export type GetNetworksResponse200 = {
data: NetworkDto[];
status: 200;
};
export type GetNetworksResponse400 = {
data: NetworksControllerGetNetworks400;
status: 400;
};
export type GetNetworksResponse401 = {
data: NetworksControllerGetNetworks401;
status: 401;
};
export type GetNetworksResponse429 = {
data: NetworksControllerGetNetworks429;
status: 429;
};
export type GetNetworksResponse500 = {
data: NetworksControllerGetNetworks500;
status: 500;
};
export type GetNetworksResponseSuccess = GetNetworksResponse200 & {
headers: Headers;
};
export type GetNetworksResponseError = (
| GetNetworksResponse400
| GetNetworksResponse401
| GetNetworksResponse429
| GetNetworksResponse500
) & {
headers: Headers;
};
export const getGetNetworksUrl = () => `/v1/networks`;
export const getNetworks = (options?: RequestInit): Promise<GetNetworksResponseSuccess> =>
httpClient<GetNetworksResponseSuccess>(getGetNetworksUrl(), {
...options,
method: 'GET',
});
/**
* Returns a paginated list of all providers, including both protocol and validator providers.
* @summary Get all providers
*/
export type GetProvidersResponse200 = {
data: ProvidersControllerGetProviders200;
status: 200;
};
export type GetProvidersResponse400 = {
data: ProvidersControllerGetProviders400;
status: 400;
};
export type GetProvidersResponse401 = {
data: ProvidersControllerGetProviders401;
status: 401;
};
export type GetProvidersResponse429 = {
data: ProvidersControllerGetProviders429;
status: 429;
};
export type GetProvidersResponse500 = {
data: ProvidersControllerGetProviders500;
status: 500;
};
export type GetProvidersResponseSuccess = GetProvidersResponse200 & {
headers: Headers;
};
export type GetProvidersResponseError = (
| GetProvidersResponse400
| GetProvidersResponse401
| GetProvidersResponse429
| GetProvidersResponse500
) & {
headers: Headers;
};
export const getGetProvidersUrl = (params?: ProvidersControllerGetProvidersParams) => {
const normalizedParams = new URLSearchParams();
Object.entries(params || {}).forEach(([key, value]) => {
if (value !== undefined) {
normalizedParams.append(key, value === null ? 'null' : value.toString());
}
});
const stringifiedParams = normalizedParams.toString();
return stringifiedParams.length > 0 ? `/v1/providers?${stringifiedParams}` : `/v1/providers`;
};
export const getProviders = (
params?: ProvidersControllerGetProvidersParams,
options?: RequestInit,
): Promise<GetProvidersResponseSuccess> =>
httpClient<GetProvidersResponseSuccess>(getGetProvidersUrl(params), {
...options,
method: 'GET',
});
/**
* Returns detailed information about a specific provider.
* @summary Get provider by ID
*/
export type GetProviderResponse200 = {
data: ProviderDto;
status: 200;
};
export type GetProviderResponse400 = {
data: ProvidersControllerGetProvider400;
status: 400;
};
export type GetProviderResponse401 = {
data: ProvidersControllerGetProvider401;
status: 401;
};
export type GetProviderResponse429 = {
data: ProvidersControllerGetProvider429;
status: 429;
};
export type GetProviderResponse500 = {
data: ProvidersControllerGetProvider500;
status: 500;
};
export type GetProviderResponseSuccess = GetProviderResponse200 & {
headers: Headers;
};
export type GetProviderResponseError = (
| GetProviderResponse400
| GetProviderResponse401
| GetProviderResponse429
| GetProviderResponse500
) & {
headers: Headers;
};
export const getGetProviderUrl = ({ providerId }: ProvidersControllerGetProviderPathParameters) =>
`/v1/providers/${providerId}`;
export const getProvider = (
{ providerId }: ProvidersControllerGetProviderPathParameters,
options?: RequestInit,
): Promise<GetProviderResponseSuccess> =>
httpClient<GetProviderResponseSuccess>(getGetProviderUrl({ providerId }), {
...options,
method: 'GET',
});

View File

@@ -0,0 +1,29 @@
/**
* Generated by orval v7.17.2 🍺
* Do not edit manually.
* Yield.xyz API
* API Documentation
* OpenAPI spec version: 1.0
*/
import type { HealthStatusDto } from './index.schemas';
import { httpClient } from '../httpClient';
/**
* Get the health status of the yield API with current timestamp
* @summary Health check
*/
export type HealthResponse200 = {
data: HealthStatusDto;
status: 200;
};
export type HealthResponseSuccess = HealthResponse200 & {
headers: Headers;
};
export const getHealthUrl = () => `/health`;
export const health = (options?: RequestInit): Promise<HealthResponseSuccess> =>
httpClient<HealthResponseSuccess>(getHealthUrl(), {
...options,
method: 'GET',
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
export * from './discovery';
export * from './index.schemas';
export * from './portfolio';
export * from './risk';
export * from './actions';
export * from './health';

View File

@@ -0,0 +1,140 @@
/**
* Generated by orval v7.17.2 🍺
* Do not edit manually.
* Yield.xyz API
* API Documentation
* OpenAPI spec version: 1.0
*/
import type {
BalancesRequestDto,
BalancesResponseDto,
YieldBalancesDto,
YieldBalancesRequestDto,
YieldsControllerGetAggregateBalances400,
YieldsControllerGetAggregateBalances401,
YieldsControllerGetAggregateBalances429,
YieldsControllerGetAggregateBalances500,
YieldsControllerGetYieldBalances400,
YieldsControllerGetYieldBalances401,
YieldsControllerGetYieldBalances429,
YieldsControllerGetYieldBalances500,
YieldsControllerGetYieldBalancesPathParameters,
} from './index.schemas';
import { httpClient } from '../httpClient';
/**
* Retrieve balances for multiple wallet addresses across different networks and yield opportunities. Send an array of balance requests - each request can specify a yieldId (optional for chain scanning), address, network, and custom arguments. This is the same format as the single yield balance endpoint but in array form. Duplicate requests (same yieldId + address + network) are automatically deduplicated, with specific yield requests taking precedence over chain scans.
* @summary Get balances across multiple yields and networks
*/
export type GetAggregateBalancesResponse200 = {
data: BalancesResponseDto;
status: 200;
};
export type GetAggregateBalancesResponse400 = {
data: YieldsControllerGetAggregateBalances400;
status: 400;
};
export type GetAggregateBalancesResponse401 = {
data: YieldsControllerGetAggregateBalances401;
status: 401;
};
export type GetAggregateBalancesResponse429 = {
data: YieldsControllerGetAggregateBalances429;
status: 429;
};
export type GetAggregateBalancesResponse500 = {
data: YieldsControllerGetAggregateBalances500;
status: 500;
};
export type GetAggregateBalancesResponseSuccess = GetAggregateBalancesResponse200 & {
headers: Headers;
};
export type GetAggregateBalancesResponseError = (
| GetAggregateBalancesResponse400
| GetAggregateBalancesResponse401
| GetAggregateBalancesResponse429
| GetAggregateBalancesResponse500
) & {
headers: Headers;
};
export const getGetAggregateBalancesUrl = () => `/v1/yields/balances`;
export const getAggregateBalances = (
balancesRequestDto: BalancesRequestDto,
options?: RequestInit,
): Promise<GetAggregateBalancesResponseSuccess> =>
httpClient<GetAggregateBalancesResponseSuccess>(getGetAggregateBalancesUrl(), {
...options,
method: 'POST',
headers: { 'Content-Type': 'application/json', ...options?.headers },
body: JSON.stringify(balancesRequestDto),
});
/**
* Retrieve all balances associated with a yield opportunity for a specific wallet address, including active, pending, claimable, and withdrawable balances. The network is automatically determined from the yield configuration.
* @summary Get balances for a specific yield
*/
export type GetYieldBalancesResponse200 = {
data: YieldBalancesDto;
status: 200;
};
export type GetYieldBalancesResponse400 = {
data: YieldsControllerGetYieldBalances400;
status: 400;
};
export type GetYieldBalancesResponse401 = {
data: YieldsControllerGetYieldBalances401;
status: 401;
};
export type GetYieldBalancesResponse404 = {
data: void;
status: 404;
};
export type GetYieldBalancesResponse429 = {
data: YieldsControllerGetYieldBalances429;
status: 429;
};
export type GetYieldBalancesResponse500 = {
data: YieldsControllerGetYieldBalances500;
status: 500;
};
export type GetYieldBalancesResponseSuccess = GetYieldBalancesResponse200 & {
headers: Headers;
};
export type GetYieldBalancesResponseError = (
| GetYieldBalancesResponse400
| GetYieldBalancesResponse401
| GetYieldBalancesResponse404
| GetYieldBalancesResponse429
| GetYieldBalancesResponse500
) & {
headers: Headers;
};
export const getGetYieldBalancesUrl = ({
yieldId,
}: YieldsControllerGetYieldBalancesPathParameters) => `/v1/yields/${yieldId}/balances`;
export const getYieldBalances = (
{ yieldId }: YieldsControllerGetYieldBalancesPathParameters,
yieldBalancesRequestDto: YieldBalancesRequestDto,
options?: RequestInit,
): Promise<GetYieldBalancesResponseSuccess> =>
httpClient<GetYieldBalancesResponseSuccess>(getGetYieldBalancesUrl({ yieldId }), {
...options,
method: 'POST',
headers: { 'Content-Type': 'application/json', ...options?.headers },
body: JSON.stringify(yieldBalancesRequestDto),
});

View File

@@ -0,0 +1,75 @@
/**
* Generated by orval v7.17.2 🍺
* Do not edit manually.
* Yield.xyz API
* API Documentation
* OpenAPI spec version: 1.0
*/
import type {
RiskParameterDto,
YieldsControllerGetYieldRisk400,
YieldsControllerGetYieldRisk401,
YieldsControllerGetYieldRisk429,
YieldsControllerGetYieldRisk500,
YieldsControllerGetYieldRiskPathParameters,
} from './index.schemas';
import { httpClient } from '../httpClient';
/**
* Retrieve risk metadata associated with a specific yield.
* @summary Get risk metadata for a yield
*/
export type GetYieldRiskResponse200 = {
data: RiskParameterDto[];
status: 200;
};
export type GetYieldRiskResponse400 = {
data: YieldsControllerGetYieldRisk400;
status: 400;
};
export type GetYieldRiskResponse401 = {
data: YieldsControllerGetYieldRisk401;
status: 401;
};
export type GetYieldRiskResponse404 = {
data: void;
status: 404;
};
export type GetYieldRiskResponse429 = {
data: YieldsControllerGetYieldRisk429;
status: 429;
};
export type GetYieldRiskResponse500 = {
data: YieldsControllerGetYieldRisk500;
status: 500;
};
export type GetYieldRiskResponseSuccess = GetYieldRiskResponse200 & {
headers: Headers;
};
export type GetYieldRiskResponseError = (
| GetYieldRiskResponse400
| GetYieldRiskResponse401
| GetYieldRiskResponse404
| GetYieldRiskResponse429
| GetYieldRiskResponse500
) & {
headers: Headers;
};
export const getGetYieldRiskUrl = ({ yieldId }: YieldsControllerGetYieldRiskPathParameters) =>
`/v1/yields/${yieldId}/risk`;
export const getYieldRisk = (
{ yieldId }: YieldsControllerGetYieldRiskPathParameters,
options?: RequestInit,
): Promise<GetYieldRiskResponseSuccess> =>
httpClient<GetYieldRiskResponseSuccess>(getGetYieldRiskUrl({ yieldId }), {
...options,
method: 'GET',
});

View File

@@ -0,0 +1,4 @@
/**
* A proxy service for yield.xyz API
*/
export const YIELD_XYZ_BASE_URL = 'https://services.trezor.io/earn/yieldxyz';

View File

@@ -0,0 +1,24 @@
import { desktopMutationKeys, useMutation } from '@suite-common/react-query';
import { CreateActionDto, EnterYieldResponseSuccess, enterYield } from '../api';
type EnterYieldOpportunityVariables = Pick<CreateActionDto, 'yieldId' | 'address'> & {
amount: string;
};
/**
* Generate the transactions needed to enter a yield position
* @url https://docs.yield.xyz/reference/actionscontroller_enteryield
*/
export function useEnterYieldOpportunity() {
return useMutation<EnterYieldResponseSuccess, Error, EnterYieldOpportunityVariables>({
mutationKey: desktopMutationKeys.enterYieldOpportunity,
mutationFn({ yieldId, address, amount }) {
return enterYield({
yieldId,
address,
arguments: { amount },
});
},
});
}

View File

@@ -0,0 +1,62 @@
import { type MutationOptions, desktopMutationKeys, useMutation } from '@suite-common/react-query';
import {
GetYieldResponseError,
GetYieldsResponseSuccess,
ProviderDto,
YieldsControllerGetYieldsSort,
YieldsControllerGetYieldsType,
getYields,
} from '../api';
interface GetYieldOpportunitiesVariables {
offset?: number;
limit?: number;
sort?: YieldsControllerGetYieldsSort;
}
export interface UseGetYieldOpportunitiesProps {
/**
* @url https://docs.yield.xyz/reference/providerscontroller_getproviders
*/
providers?: ProviderDto['id'][];
types?: YieldsControllerGetYieldsType[];
onSuccess?: MutationOptions<
GetYieldsResponseSuccess,
Error,
GetYieldOpportunitiesVariables
>['onSuccess'];
onError?: MutationOptions<
GetYieldResponseError,
Error,
GetYieldOpportunitiesVariables
>['onError'];
}
/**
* Paginated list of Yield opportunities
* @url https://docs.yield.xyz/reference/yieldscontroller_getyields
*/
export function useGetYieldOpportunities({
providers = ['morpho'],
types = ['vault'],
onError,
onSuccess,
}: UseGetYieldOpportunitiesProps) {
return useMutation<GetYieldsResponseSuccess, Error, GetYieldOpportunitiesVariables>({
mutationKey: desktopMutationKeys.getYieldOpportunities,
mutationFn: ({ offset = 0, limit = 20, sort = 'statusEnterDesc' }) =>
getYields({
offset,
limit,
providers,
types,
sort,
}),
onError,
onSuccess: (data, variables, onMutateResult, context) =>
onSuccess?.(data, variables, onMutateResult, context),
});
}

View File

@@ -0,0 +1,39 @@
import { MutationOptions, desktopMutationKeys, useMutation } from '@suite-common/react-query';
import {
SubmitTransactionHashResponseError,
SubmitTransactionHashResponseSuccess,
submitTransactionHash,
} from '../api';
type SubmitTxHashVariables = {
txId: string;
txHash: string;
};
interface UseSubmitTxHashProps {
onSuccess?: MutationOptions<
SubmitTransactionHashResponseSuccess,
Error,
SubmitTxHashVariables
>['onSuccess'];
onError?: MutationOptions<
SubmitTransactionHashResponseError,
Error,
SubmitTxHashVariables
>['onError'];
}
/**
* Submit the transaction hash after broadcasting a transaction to the blockchain. This updates the transaction status and enables tracking.
* @url https://docs.yield.xyz/reference/transactionscontroller_submittransactionhash
*/
export function useSubmitTxHash({ onSuccess, onError }: UseSubmitTxHashProps) {
return useMutation<SubmitTransactionHashResponseSuccess, Error, SubmitTxHashVariables>({
mutationKey: desktopMutationKeys.submitTxHash,
mutationFn: ({ txId, txHash }) =>
submitTransactionHash({ transactionId: txId }, { hash: txHash }),
onSuccess,
onError,
});
}

View File

@@ -0,0 +1,69 @@
import { YIELD_XYZ_BASE_URL } from './config';
type OrvalFetchOptions = RequestInit;
export class OrvalHttpError<T = unknown> extends Error {
info?: T;
status?: number;
response?: Response;
constructor(message: string, data?: T, status?: number, response?: Response) {
super(message);
this.name = 'OrvalHttpError';
this.info = data;
this.status = status;
this.response = response;
}
}
export const isOrvalHttpError = (error: unknown): error is OrvalHttpError =>
error instanceof OrvalHttpError;
const isJsonContentType = (contentType: string) =>
contentType.includes('application/json') || contentType.includes('+json');
const parseBody = async (res: Response): Promise<unknown> => {
// These statuses must not include a response body per HTTP spec.
if ([204, 205, 304].includes(res.status)) return null;
const contentType = (res.headers.get('content-type') ?? '').toLowerCase();
switch (true) {
case isJsonContentType(contentType):
return res.json();
case contentType.includes('text/'):
return res.text();
case contentType.includes('application/x-www-form-urlencoded'): {
const text = await res.text();
return new URLSearchParams(text);
}
case contentType.includes('multipart/form-data'):
return res.formData();
case contentType.includes('application/octet-stream') ||
contentType.startsWith('image/') ||
contentType.startsWith('audio/') ||
contentType.startsWith('video/'):
return res.blob();
default:
return res.text();
}
};
export const httpClient = async <T>(endpoint: string, init?: OrvalFetchOptions) => {
const [pathname, search = ''] = endpoint.split('?');
const url = new URL(YIELD_XYZ_BASE_URL);
url.search = search;
url.pathname = `${url.pathname}${pathname}`;
const req = new Request(url.toString(), init);
const res = await fetch(req);
const data = await parseBody(res);
if (!res.ok) {
throw new OrvalHttpError('Request failed', data, res.status, res);
}
return { data, status: res.status, headers: res.headers } as T;
};

View File

@@ -0,0 +1,4 @@
export * from './api';
export * from './hooks/useGetYieldOpportunities';
export * from './hooks/useEnterYieldOpportunity';
export * from './hooks/useSubmitTxHash';

View File

@@ -0,0 +1,5 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": { "outDir": "libDev" },
"references": [{ "path": "../react-query" }]
}

View File

@@ -11,7 +11,6 @@
"type-check": "yarn g:tsc --build"
},
"dependencies": {
"@suite-common/suite-utils": "workspace:^",
"@tanstack/react-query": "5.90.16",
"@tanstack/react-query-devtools": "5.91.2",
"react": "19.1.0"

View File

@@ -2,7 +2,7 @@ import { type PropsWithChildren, useMemo } from 'react';
import { MutationCache, QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { isDevEnv } from '@suite-common/suite-utils';
import { isDevEnv } from '../config';
/**
* Fail fast during development, retry in production

View File

@@ -2,7 +2,7 @@ import { PropsWithChildren, Suspense, lazy, useMemo } from 'react';
import { MutationCache, QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { isDevEnv } from '@suite-common/suite-utils';
import { isDevEnv } from '../config';
const Devtools = lazy(async () => {
const { ReactQueryDevtools } = await import('@tanstack/react-query-devtools');

View File

@@ -0,0 +1 @@
export const isDevEnv = process.env.NODE_ENV !== 'production';

View File

@@ -2,6 +2,11 @@ import { AllowedMutationKey } from '../types';
export const commonMutationKeys = {} as const satisfies Record<string, AllowedMutationKey>;
export const desktopMutationKeys = {} as const satisfies Record<string, AllowedMutationKey>;
export const desktopMutationKeys = {
getYieldOpportunities: ['get-yield-opportunities'],
enterYieldOpportunity: ['enter-yield-opportunity'],
submitTxHash: ['submit-tx-hash'],
exitYieldOpportunity: ['exit-yield-opportunity'],
} as const satisfies Record<string, AllowedMutationKey>;
export const mobileMutationKeys = {} as const satisfies Record<string, AllowedMutationKey>;

View File

@@ -9,6 +9,7 @@ export const desktopQueryKeys = {
defaultUrls: (symbol: string) => ['default-urls', symbol],
proxyImage: (src?: string) => ['proxy-image', src],
inactiveTokens: (symbol: string) => ['inactive-tokens', symbol],
yieldOpportunities: (pagination: any) => ['yield-opportunities', pagination],
} as const satisfies Record<string, AllowedQueryKey>;
export const mobileQueryKeys = {} as const satisfies Record<string, AllowedQueryKey>;

View File

@@ -1,4 +1,10 @@
export { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
export {
useQuery,
useMutation,
useQueryClient,
type MutationOptions,
type QueryOptions,
} from '@tanstack/react-query';
export * from './components/ReactQueryProvider';
export * from './components/ReactNativeQueryProvider';
export * from './constants/queryKeys';

View File

@@ -1,5 +1,5 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": { "outDir": "libDev" },
"references": [{ "path": "../suite-utils" }]
"references": []
}

View File

@@ -11,6 +11,7 @@
"type-check": "yarn g:tsc --build"
},
"dependencies": {
"@suite-common/earn-api": "workspace:*",
"@trezor/device-utils": "workspace:*",
"@trezor/type-utils": "workspace:*",
"@trezor/utils": "workspace:*"

View File

@@ -40,6 +40,7 @@ export const networks = {
coingeckoId: 'bitcoin',
tradeCryptoId: 'bitcoin',
caipId: 'bip122:000000000019d6689c085ae165831e93',
yieldXyzId: null,
},
eth: {
symbol: 'eth',
@@ -81,6 +82,7 @@ export const networks = {
coingeckoId: 'ethereum',
tradeCryptoId: 'ethereum',
caipId: 'eip155:1',
yieldXyzId: 'ethereum',
},
pol: {
symbol: 'pol',
@@ -115,6 +117,7 @@ export const networks = {
coingeckoId: 'polygon-pos',
tradeCryptoId: 'polygon-ecosystem-token',
caipId: 'eip155:137',
yieldXyzId: 'polygon',
},
bsc: {
symbol: 'bsc',
@@ -149,6 +152,7 @@ export const networks = {
coingeckoId: 'binance-smart-chain',
tradeCryptoId: 'binancecoin',
caipId: 'eip155:56',
yieldXyzId: 'binance',
},
arb: {
symbol: 'arb',
@@ -185,6 +189,7 @@ export const networks = {
coingeckoId: 'arbitrum-one',
tradeCryptoId: 'arbitrum-one--0x0000000000000000000000000000000000000000',
caipId: 'eip155:42161',
yieldXyzId: 'arbitrum',
},
base: {
symbol: 'base',
@@ -222,6 +227,7 @@ export const networks = {
tradeCryptoId: 'base--0x0000000000000000000000000000000000000000',
caipId: 'eip155:8453',
nativeTokenReserve: '0.0002',
yieldXyzId: 'base',
},
op: {
symbol: 'op',
@@ -258,6 +264,7 @@ export const networks = {
tradeCryptoId: 'optimistic-ethereum--0x0000000000000000000000000000000000000000',
caipId: 'eip155:10',
nativeTokenReserve: '0.0002',
yieldXyzId: 'optimism',
},
avax: {
symbol: 'avax',
@@ -292,6 +299,7 @@ export const networks = {
coingeckoId: 'avalanche',
tradeCryptoId: 'avalanche-2',
caipId: 'eip155:43114',
yieldXyzId: 'avalanche-c',
},
sol: {
symbol: 'sol',
@@ -323,6 +331,7 @@ export const networks = {
tradeCryptoId: 'solana',
caipId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
nativeTokenReserve: '0.003',
yieldXyzId: 'solana',
},
trx: {
symbol: 'trx',
@@ -346,6 +355,7 @@ export const networks = {
accountTypes: {},
coingeckoId: 'tron',
tradeCryptoId: 'tron',
yieldXyzId: 'tron',
},
ada: {
// icarus derivation
@@ -382,6 +392,7 @@ export const networks = {
},
coingeckoId: 'cardano',
tradeCryptoId: 'cardano',
yieldXyzId: 'cardano',
},
etc: {
symbol: 'etc',
@@ -398,6 +409,7 @@ export const networks = {
accountTypes: {},
coingeckoId: 'ethereum-classic',
tradeCryptoId: 'ethereum-classic',
yieldXyzId: null,
},
xrp: {
symbol: 'xrp',
@@ -413,6 +425,7 @@ export const networks = {
accountTypes: {},
coingeckoId: 'ripple',
tradeCryptoId: 'ripple',
yieldXyzId: null,
},
xlm: {
symbol: 'xlm',
@@ -428,6 +441,7 @@ export const networks = {
accountTypes: {},
coingeckoId: 'stellar',
tradeCryptoId: 'stellar',
yieldXyzId: 'stellar',
},
ltc: {
symbol: 'ltc',
@@ -453,6 +467,7 @@ export const networks = {
coingeckoId: 'litecoin',
tradeCryptoId: 'litecoin',
caipId: 'bip122:12a765e31ffd4059bada1e25190f6e98',
yieldXyzId: null,
},
bch: {
symbol: 'bch',
@@ -468,6 +483,7 @@ export const networks = {
accountTypes: {},
coingeckoId: 'bitcoin-cash',
tradeCryptoId: 'bitcoin-cash',
yieldXyzId: null,
},
doge: {
symbol: 'doge',
@@ -484,6 +500,7 @@ export const networks = {
coingeckoId: 'dogecoin',
tradeCryptoId: 'dogecoin',
caipId: 'bip122:1a91e3dace36e2be3bf030a65679fe82',
yieldXyzId: null,
},
zec: {
symbol: 'zec',
@@ -499,6 +516,7 @@ export const networks = {
accountTypes: {},
coingeckoId: 'zcash',
tradeCryptoId: 'zcash',
yieldXyzId: null,
},
// testnets
test: {
@@ -536,6 +554,7 @@ export const networks = {
coingeckoId: undefined,
tradeCryptoId: 'test-bitcoin', // fake, coingecko does not have testnets
caipId: 'bip122:000000000933ea01ad0ee984209779ba',
yieldXyzId: null,
},
regtest: {
symbol: 'regtest',
@@ -572,6 +591,7 @@ export const networks = {
isDebugOnlyNetwork: true,
coingeckoId: undefined,
tradeCryptoId: undefined,
yieldXyzId: null,
},
tsep: {
symbol: 'tsep',
@@ -588,6 +608,7 @@ export const networks = {
accountTypes: {},
coingeckoId: 'sepolia-test-ethereum', // fake, coingecko does not have testnets
tradeCryptoId: 'sepolia-test-ethereum', // fake, coingecko does not have testnets
yieldXyzId: 'ethereum-sepolia',
},
thod: {
symbol: 'thod',
@@ -613,6 +634,7 @@ export const networks = {
accountTypes: {},
coingeckoId: 'hoodi-test-ethereum', // fake, coingecko does not have testnets
tradeCryptoId: 'hoodi-test-ethereum', // fake, coingecko does not have testnets
yieldXyzId: 'ethereum-hoodi',
},
dsol: {
symbol: 'dsol',
@@ -636,6 +658,7 @@ export const networks = {
coingeckoId: undefined,
tradeCryptoId: undefined,
caipId: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1',
yieldXyzId: 'solana-devnet',
},
txrp: {
symbol: 'txrp',
@@ -651,6 +674,7 @@ export const networks = {
accountTypes: {},
coingeckoId: undefined,
tradeCryptoId: 'test-ripple', // fake, coingecko does not have testnets
yieldXyzId: null,
},
txlm: {
symbol: 'txlm',
@@ -666,6 +690,7 @@ export const networks = {
accountTypes: {},
coingeckoId: undefined,
tradeCryptoId: undefined,
yieldXyzId: 'stellar-testnet',
},
} as const satisfies Networks;

View File

@@ -1,3 +1,4 @@
import { NetworkDtoId } from '@suite-common/earn-api';
import { type DeviceModelInternal } from '@trezor/device-utils';
import { RequiredKey } from '@trezor/type-utils';
@@ -139,6 +140,11 @@ type NetworkWithSpecificKey<TKey extends NetworkSymbol> = {
tradeCryptoId?: string;
caipId?: string; // CAIP-2 chain id, used by WalletConnect
nativeTokenReserve?: string;
/**
* Network ID used by Yield.xyz
* @url https://yield.xyz
*/
yieldXyzId: NetworkDtoId | null;
};
export type Network = NetworkWithSpecificKey<NetworkSymbol>;

View File

@@ -1,3 +1,5 @@
import { NetworkDtoId } from '@suite-common/earn-api';
import { networks } from './networksConfig';
import {
type AccountType,
@@ -160,3 +162,6 @@ export const getNetworkDecimals = (symbol: NetworkSymbolExtended) => {
return undefined;
};
export const getNetworkByYieldXyzId = (yieldXyzId: NetworkDtoId) =>
networksCollection.find(n => n.yieldXyzId === yieldXyzId) ?? null;

View File

@@ -2,6 +2,7 @@
"extends": "../../tsconfig.base.json",
"compilerOptions": { "outDir": "libDev" },
"references": [
{ "path": "../earn-api" },
{ "path": "../../packages/device-utils" },
{ "path": "../../packages/type-utils" },
{ "path": "../../packages/utils" }

968
yarn.lock

File diff suppressed because it is too large Load Diff