Skip to content
Closed
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
5 changes: 5 additions & 0 deletions .changeset/yield-plus-pr03-yieldplus-infra.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@venusprotocol/evm": patch
---

add the Yield+ API, websocket, contract, and configuration plumbing required for the new position flows
75 changes: 49 additions & 26 deletions .claude/scripts/ui-interaction-test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import path from 'node:path';
import { type Page, chromium } from '@playwright/test';
import { chromium, type Page } from '@playwright/test';

// Shared utility - see .claude/scripts/utils/image.ts
import { downscaleIfNeeded } from './utils/image.js';
Expand Down Expand Up @@ -68,11 +68,11 @@ function parseArgs(args: string[]) {
} else if (arg === '--steps') {
stepsJson = args[++i] ?? '';
} else if (arg.startsWith('--width=')) {
width = Number.parseInt(arg.split('=')[1] ?? '1440', 10);
width = parseInt(arg.split('=')[1] ?? '1440', 10);
} else if (arg.startsWith('--height=')) {
height = Number.parseInt(arg.split('=')[1] ?? '900', 10);
height = parseInt(arg.split('=')[1] ?? '900', 10);
} else if (arg.startsWith('--max-width=')) {
maxWidth = Number.parseInt(arg.split('=')[1] ?? '1400', 10);
maxWidth = parseInt(arg.split('=')[1] ?? '1400', 10);
}
}

Expand All @@ -97,9 +97,11 @@ async function waitForStable(page: Page): Promise<void> {
}

async function main() {
const { url, output, steps, width, height, maxWidth } = parseArgs(process.argv.slice(2));
const { url, output, steps, width, height, maxWidth } = parseArgs(
process.argv.slice(2),
);

const targetUrl = `${DEV_SERVER_URL}${url.startsWith('/') ? url : `/${url}`}`;
const targetUrl = `${DEV_SERVER_URL}${url.startsWith('/') ? url : '/' + url}`;

// Check dev server
try {
Expand Down Expand Up @@ -198,7 +200,9 @@ async function main() {
});
await waitForStable(page);
await takeScreenshot(screenshotPath(''));
console.log(` viewport: ${step.width}x${step.height} -> ${screenshotPath('')}`);
console.log(
` viewport: ${step.width}x${step.height} -> ${screenshotPath('')}`,
);
break;
}

Expand Down Expand Up @@ -235,7 +239,9 @@ async function main() {
await locator.fill(step.value);
await waitForStable(page);
await takeScreenshot(screenshotPath(''));
console.log(` fill: "${step.value}" into ${step.selector} -> ${screenshotPath('')}`);
console.log(
` fill: "${step.value}" into ${step.selector} -> ${screenshotPath('')}`,
);
}
break;
}
Expand All @@ -245,14 +251,15 @@ async function main() {
if ((await trigger.count()) === 0) {
await takeScreenshot(screenshotPath('-NOTFOUND'));
console.log(
` select-option: trigger not found "${step.selector}" -> ${screenshotPath(
'-NOTFOUND',
)}`,
` select-option: trigger not found "${step.selector}" -> ${screenshotPath('-NOTFOUND')}`,
);
} else {
await trigger.click();
await waitForStable(page);
const option = page.locator('[role="option"]').filter({ hasText: step.value }).first();
const option = page
.locator('[role="option"]')
.filter({ hasText: step.value })
.first();

if ((await option.count()) === 0) {
await takeScreenshot(screenshotPath('-NOTFOUND'));
Expand All @@ -275,19 +282,21 @@ async function main() {
const locator = page.locator(step.selector).first();
if ((await locator.count()) === 0) {
await takeScreenshot(screenshotPath('-FAIL'));
console.log(` assert-text: FAIL - selector not found "${step.selector}"`);
console.log(
` assert-text: FAIL - selector not found "${step.selector}"`,
);
process.exitCode = 1;
} else {
const text = (await locator.textContent()) ?? '';
if (text.includes(step.expected)) {
await takeScreenshot(screenshotPath('-PASS'));
console.log(` assert-text: PASS - "${step.expected}" found in ${step.selector}`);
console.log(
` assert-text: PASS - "${step.expected}" found in ${step.selector}`,
);
} else {
await takeScreenshot(screenshotPath('-FAIL'));
console.log(
` assert-text: FAIL - expected "${step.expected}" in ${
step.selector
}, got "${text.slice(0, 100)}"`,
` assert-text: FAIL - expected "${step.expected}" in ${step.selector}, got "${text.slice(0, 100)}"`,
);
process.exitCode = 1;
}
Expand All @@ -299,7 +308,9 @@ async function main() {
const locator = page.locator(step.selector).first();
if ((await locator.count()) === 0) {
await takeScreenshot(screenshotPath('-FAIL'));
console.log(` assert-visible: FAIL - selector not found "${step.selector}"`);
console.log(
` assert-visible: FAIL - selector not found "${step.selector}"`,
);
process.exitCode = 1;
} else {
const visible = await locator.isVisible();
Expand All @@ -308,7 +319,9 @@ async function main() {
console.log(` assert-visible: PASS - ${step.selector} is visible`);
} else {
await takeScreenshot(screenshotPath('-FAIL'));
console.log(` assert-visible: FAIL - ${step.selector} exists but not visible`);
console.log(
` assert-visible: FAIL - ${step.selector} exists but not visible`,
);
process.exitCode = 1;
}
}
Expand All @@ -319,7 +332,9 @@ async function main() {
const locator = page.locator(step.selector).first();
if ((await locator.count()) === 0) {
await takeScreenshot(screenshotPath('-FAIL'));
console.log(` assert-value: FAIL - selector not found "${step.selector}"`);
console.log(
` assert-value: FAIL - selector not found "${step.selector}"`,
);
process.exitCode = 1;
} else {
const value = await locator.inputValue();
Expand All @@ -345,7 +360,9 @@ async function main() {
console.log(' check-console: PASS - no console errors');
} else {
await takeScreenshot(screenshotPath('-FAIL'));
console.log(` check-console: FAIL - ${consoleErrors.length} error(s):`);
console.log(
` check-console: FAIL - ${consoleErrors.length} error(s):`,
);
for (const err of consoleErrors) {
console.log(` ${err.slice(0, 200)}`);
}
Expand All @@ -362,10 +379,14 @@ async function main() {
timeout,
});
await takeScreenshot(screenshotPath('-PASS'));
console.log(` wait-for: PASS - ${step.selector} visible within ${timeout}ms`);
console.log(
` wait-for: PASS - ${step.selector} visible within ${timeout}ms`,
);
} catch {
await takeScreenshot(screenshotPath('-TIMEOUT'));
console.log(` wait-for: TIMEOUT - ${step.selector} not visible after ${timeout}ms`);
console.log(
` wait-for: TIMEOUT - ${step.selector} not visible after ${timeout}ms`,
);
process.exitCode = 1;
}
break;
Expand All @@ -374,10 +395,12 @@ async function main() {
}

await browser.close();
console.log(`Interaction test complete.${process.exitCode ? ' (FAILURES DETECTED)' : ''}`);
console.log(
`Interaction test complete.${process.exitCode ? ' (FAILURES DETECTED)' : ''}`,
);
}

main().catch(err => {
main().catch((err) => {
console.error(err);
process.exit(1);
});
});
15 changes: 7 additions & 8 deletions .claude/scripts/ui-screenshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ function parseArgs(args: string[]) {

for (const arg of args.slice(2)) {
if (arg.startsWith('--width=')) {
width = Number.parseInt(arg.split('=')[1] ?? '1440', 10);
width = parseInt(arg.split('=')[1] ?? '1440', 10);
} else if (arg.startsWith('--height=')) {
height = Number.parseInt(arg.split('=')[1] ?? '900', 10);
height = parseInt(arg.split('=')[1] ?? '900', 10);
} else if (arg.startsWith('--max-width=')) {
maxWidth = Number.parseInt(arg.split('=')[1] ?? '1400', 10);
maxWidth = parseInt(arg.split('=')[1] ?? '1400', 10);
} else if (arg === '--full-page') {
fullPage = true;
}
Expand All @@ -59,11 +59,10 @@ function parseArgs(args: string[]) {
}

async function main() {
const { routePath, outputPath, width, height, fullPage, maxWidth } = parseArgs(
process.argv.slice(2),
);
const { routePath, outputPath, width, height, fullPage, maxWidth } =
parseArgs(process.argv.slice(2));

const url = `${DEV_SERVER_URL}${routePath.startsWith('/') ? routePath : `/${routePath}`}`;
const url = `${DEV_SERVER_URL}${routePath.startsWith('/') ? routePath : '/' + routePath}`;

// Check if dev server is running
try {
Expand Down Expand Up @@ -103,7 +102,7 @@ async function main() {
await browser.close();
}

main().catch(err => {
main().catch((err) => {
console.error(err);
process.exit(1);
});
2 changes: 1 addition & 1 deletion .claude/scripts/utils/image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function downscaleIfNeeded(filePath: string, maxW: number): void {
stdio: ['ignore', 'pipe', 'ignore'],
});
const match = info.match(/pixelWidth:\s*(\d+)/);
const currentWidth = match ? Number.parseInt(match[1] ?? '0', 10) : 0;
const currentWidth = match ? parseInt(match[1] ?? '0', 10) : 0;
if (currentWidth > maxW) {
execFileSync('sips', ['--resampleWidth', String(maxW), filePath, '--out', filePath], {
stdio: 'pipe',
Expand Down
8 changes: 4 additions & 4 deletions apps/evm/src/config/apiUrls.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { Network } from 'types';

export const apiUrls: {
export const apiHosts: {
[key in Network]: string;
} = {
testnet: 'https://testnetapi.venus.io',
mainnet: 'https://api.venus.io',
'mainnet-preview': 'https://api-preview.venus.io',
testnet: 'testnetapi.venus.io',
mainnet: 'api.venus.io',
'mainnet-preview': 'api-preview.venus.io',
};
8 changes: 6 additions & 2 deletions apps/evm/src/config/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { ChainId, Environment, Network } from 'types';

import { apiUrls } from './apiUrls';
import { apiHosts } from './apiUrls';
import { envVariables } from './envVariables';
import { rpcUrls } from './rpcUrls';
import { getGovernanceSubgraphUrls } from './subgraphUrls';
Expand All @@ -10,6 +10,7 @@ export interface Config {
network: Network;
isSafeApp: boolean;
apiUrl: string;
wsApiUrl: string;
rpcUrls: {
[chainId in ChainId]: string[];
};
Expand All @@ -29,7 +30,9 @@ export interface Config {
const environment: Environment = envVariables.VITE_ENV || 'preview';
const network: Network = envVariables.VITE_NETWORK || 'mainnet';

const apiUrl = apiUrls[network];
const apiHost = apiHosts[network];
const apiUrl = `https://${apiHost}`;
const wsApiUrl = `wss://${apiHost}/ws`;

const keys = {
nodeRealApiKey: envVariables.VITE_NODE_REAL_API_KEY,
Expand All @@ -45,6 +48,7 @@ const config: Config = {
network,
isSafeApp,
apiUrl,
wsApiUrl,
rpcUrls,
governanceSubgraphUrls,
sentryDsn: envVariables.VITE_SENTRY_DSN || '',
Expand Down
4 changes: 4 additions & 0 deletions apps/evm/src/constants/functionKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ enum FunctionKey {
GET_IS_ADDRESS_AUTHORIZED = 'GET_IS_ADDRESS_AUTHORIZED',
GET_BLOCK_NUMBER = 'GET_BLOCK_NUMBER',
GET_VAI_TREASURY_PERCENTAGE = 'GET_VAI_TREASURY_PERCENTAGE',
GET_PROPORTIONAL_CLOSE_TOLERANCE_PERCENTAGE = 'GET_PROPORTIONAL_CLOSE_TOLERANCE_PERCENTAGE',
GET_DSA_V_TOKENS = 'GET_DSA_V_TOKENS',
GET_MARKET_HISTORY = 'GET_MARKET_HISTORY',
GET_VENUS_VAI_STATE = 'GET_VENUS_VAI_STATE',
GET_PENDING_REWARDS = 'GET_PENDING_REWARDS',
Expand Down Expand Up @@ -74,6 +76,8 @@ enum FunctionKey {
GET_PROPOSAL_COUNT = 'GET_PROPOSAL_COUNT',
GET_MARKETS_TVL = 'GET_MARKETS_TVL',
GET_TOP_MARKETS = 'GET_TOP_MARKETS',
GET_RAW_YIELD_PLUS_POSITIONS = 'GET_RAW_YIELD_PLUS_POSITIONS',
GET_TOKEN_PAIR_K_LINE_CANDLES = 'GET_TOKEN_PAIR_K_LINE_CANDLES',
GET_FIXED_RATED_VAULTS = 'GET_FIXED_RATED_VAULTS',
}

Expand Down
10 changes: 10 additions & 0 deletions apps/evm/src/constants/klineCandles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { ApiOhlcInterval } from 'types';

export interface ChartPeriod {
span: number;
type: 'millisecond' | 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year';
}

export const INTERVAL: ApiOhlcInterval = '1h';

export const CHART_PERIOD: ChartPeriod = { span: 1, type: 'hour' };
3 changes: 3 additions & 0 deletions apps/evm/src/constants/time.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
export const ONE_HOUR_MS = 60 * 60 * 1000;
export const ONE_DAY_MS = ONE_HOUR_MS * 24;

export const MONTHS_PER_YEAR = 12;
export const DAYS_PER_YEAR = 365;
export const SECONDS_PER_DAY = 60 * 60 * 24;
Expand Down
Loading
Loading