diff --git a/src/Managing.Api/ADMIN_FEATURE.md b/src/Managing.Api/ADMIN_FEATURE.md deleted file mode 100644 index aeee3c5f..00000000 --- a/src/Managing.Api/ADMIN_FEATURE.md +++ /dev/null @@ -1,80 +0,0 @@ -# Admin Feature Documentation - -## Overview - -The admin feature allows specific users to manage all bots in the system, regardless of ownership. Admin users can start, stop, delete, and modify any bot without owning the associated account. - -## How It Works - -Admin privileges are granted through environment variables, making it secure and environment-specific. The system checks if a user is an admin by comparing their username against a comma-separated list of admin usernames configured in the environment. - -## Configuration - -### Environment Variable -Set the `AdminUsers` environment variable with a comma-separated list of usernames: - -```bash -AdminUsers=admin1,superuser,john.doe -``` - -### CapRover Configuration -In your CapRover dashboard: -1. Go to your app's settings -2. Navigate to "Environment Variables" -3. Add a new environment variable: - - Key: `AdminUsers` - - Value: `admin1,superuser,john.doe` (replace with actual admin usernames) - -### Local Development -For local development, you can set this in your `appsettings.Development.json`: - -```json -{ - "AdminUsers": "admin1,superuser,john.doe" -} -``` - -## Admin Capabilities - -Admin users can perform all bot operations without ownership restrictions: - -- **Start/Save Bot**: Create and start bots for any account -- **Stop Bot**: Stop any running bot -- **Delete Bot**: Delete any bot -- **Restart Bot**: Restart any bot -- **Open/Close Positions**: Manually open or close positions for any bot -- **Update Configuration**: Modify any bot's configuration -- **View Bot Configuration**: Access any bot's configuration details - -## Security Notes - -1. **Environment-Based**: Admin users are configured via environment variables, not through the API -2. **No Privilege Escalation**: Regular users cannot grant themselves admin access -3. **Audit Logging**: All admin actions are logged with the admin user's context -4. **Case-Insensitive**: Username matching is case-insensitive for convenience - -## Implementation Details - -The admin feature is implemented using: -- `IAdminConfigurationService`: Checks if a user is an admin -- Updated `UserOwnsBotAccount` method: Returns true for admin users -- Dependency injection: Service is registered as a singleton -- Configuration reading: Reads from `AdminUsers` environment variable - -## Example Usage - -1. **Set Admin Users**: - ```bash - AdminUsers=alice,bob,charlie - ``` - -2. **Admin Operations**: - - Alice, Bob, or Charlie can now manage any bot in the system - - They can use all existing bot endpoints without ownership restrictions - - All operations are logged with their username for audit purposes - -## Troubleshooting - -- **Admin not working**: Check if the username exactly matches the configuration (case-insensitive) -- **No admins configured**: Check the `AdminUsers` environment variable is set -- **Multiple environments**: Each environment (dev, staging, prod) should have its own admin configuration diff --git a/src/Managing.Api/appsettings.Oda-Sandbox.json b/src/Managing.Api/appsettings.Oda-Sandbox.json deleted file mode 100644 index 1472eed5..00000000 --- a/src/Managing.Api/appsettings.Oda-Sandbox.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "InfluxDb": { - "Url": "http://influxdb:8086/", - "Organization": "", - "Token": "" - }, - "Serilog": { - "MinimumLevel": { - "Default": "Information", - "Override": { - "Microsoft": "Information", - "System": "Warning" - } - } - }, - "ElasticConfiguration": { - "Uri": "http://elasticsearch:9200" - }, - "Discord": { - "BotActivity": "trading strategies", - "HandleUserAction": true, - "ApplicationId": "", - "PublicKey": "", - "TokenId": "", - "SignalChannelId": 966080506473099314, - "TradesChannelId": 998374177763491851, - "TroublesChannelId": 1015761955321040917, - "CopyTradingChannelId": 1132022887012909126, - "FundingRateChannelId": 1263566138709774336, - "RequestsChannelId": 1018589494968078356, - "ButtonExpirationMinutes": 10 - }, - "RunOrleansGrains": true, - "AllowedHosts": "*" -} \ No newline at end of file diff --git a/src/Managing.Api/appsettings.Oda-docker.json b/src/Managing.Api/appsettings.Oda-docker.json index 0ba5e8fa..82031ba8 100644 --- a/src/Managing.Api/appsettings.Oda-docker.json +++ b/src/Managing.Api/appsettings.Oda-docker.json @@ -1,9 +1,13 @@ { "InfluxDb": { - "Url": "http://influxdb:8086/", + "Url": "http://localhost:8086/", "Organization": "managing-org", "Token": "Fw2FPL2OwTzDHzSbR2Sd5xs0EKQYy00Q-hYKYAhr9cC1_q5YySONpxuf_Ck0PTjyUiF13xXmi__bu_pXH-H9zA==" }, + "PostgreSql": { + "ConnectionString": "Host=localhost;Port=5432;Database=managing;Username=postgres;Password=postgres", + "Orleans": "Host=localhost;Port=5432;Database=orleans;Username=postgres;Password=postgres" + }, "Privy": { "AppId": "cm6f47n1l003jx7mjwaembhup", "AppSecret": "63Chz2z5M8TgR5qc8dznSLRAGTHTyPU4cjdQobrBF1Cx5tszZpTuFgyrRd7hZ2k6HpwDz3GEwQZzsCqHb8Z311bF" @@ -30,19 +34,24 @@ "RequestsChannelId": 1018589494968078356, "ButtonExpirationMinutes": 2 }, - "RunOrleansGrains": true, - "WorkerPricesFifteenMinutes": false, + "RunOrleansGrains": false, + "AllowedHosts": "*", + "KAIGEN_SECRET_KEY": "KaigenXCowchain", + "KAIGEN_CREDITS_ENABLED": false, + "WorkerBalancesTracking": false, + "WorkerNotifyBundleBacktest": false, + "WorkerPricesFifteenMinutes": true, "WorkerPricesOneHour": false, "WorkerPricesFourHours": false, "WorkerPricesOneDay": false, "WorkerPricesFiveMinutes": false, + "WorkerFee": false, + "WorkerPositionManager": false, + "WorkerPositionFetcher": false, "WorkerSpotlight": false, "WorkerTraderWatcher": false, "WorkerLeaderboard": false, "WorkerFundingRatesWatcher": false, "WorkerGeneticAlgorithm": false, - "WorkerBundleBacktest": true, - "WorkerBalancesTracking": false, - "WorkerNotifyBundleBacktest": false, - "AllowedHosts": "*" + "WorkerBundleBacktest": false } \ No newline at end of file diff --git a/src/Managing.Api/failures.txt b/src/Managing.Api/failures.txt deleted file mode 100644 index d4d21d28..00000000 --- a/src/Managing.Api/failures.txt +++ /dev/null @@ -1,19 +0,0 @@ -{"Timestamp":"2022-09-13T02:59:02.0040536+02:00","Level":"Information","MessageTemplate":"02:59:01 Discord Discord.Net v3.8.0 (API v9)","Properties":{"SourceContext":"Managing.Infrastructure.Messengers.Discord.DiscordService","Environment":"Microsoft.AspNetCore.Hosting.HostingEnvironment"}} -{"Timestamp":"2022-09-13T02:59:02.0892523+02:00","Level":"Information","MessageTemplate":"02:59:02 Gateway Connecting","Properties":{"SourceContext":"Managing.Infrastructure.Messengers.Discord.DiscordService","Environment":"Microsoft.AspNetCore.Hosting.HostingEnvironment"}} -{"Timestamp":"2022-09-13T02:59:02.2504922+02:00","Level":"Information","MessageTemplate":"Now listening on: {address}","Properties":{"address":"https://localhost:5001","EventId":{"Id":14,"Name":"ListeningOnAddress"},"SourceContext":"Microsoft.Hosting.Lifetime","Environment":"Microsoft.AspNetCore.Hosting.HostingEnvironment"}} -{"Timestamp":"2022-09-13T02:59:02.2556804+02:00","Level":"Information","MessageTemplate":"Now listening on: {address}","Properties":{"address":"http://localhost:5000","EventId":{"Id":14,"Name":"ListeningOnAddress"},"SourceContext":"Microsoft.Hosting.Lifetime","Environment":"Microsoft.AspNetCore.Hosting.HostingEnvironment"}} -{"Timestamp":"2022-09-13T02:59:02.2591276+02:00","Level":"Information","MessageTemplate":"Application started. Press Ctrl+C to shut down.","Properties":{"SourceContext":"Microsoft.Hosting.Lifetime","Environment":"Microsoft.AspNetCore.Hosting.HostingEnvironment"}} -{"Timestamp":"2022-09-13T02:59:02.2625140+02:00","Level":"Information","MessageTemplate":"Hosting environment: {envName}","Properties":{"envName":"Development","SourceContext":"Microsoft.Hosting.Lifetime","Environment":"Microsoft.AspNetCore.Hosting.HostingEnvironment"}} -{"Timestamp":"2022-09-13T02:59:02.2651704+02:00","Level":"Information","MessageTemplate":"Content root path: {contentRoot}","Properties":{"contentRoot":"C:\\Users\\Utilisateur\\Desktop\\Projects\\apps\\Managing\\src\\Managing.Api\\","SourceContext":"Microsoft.Hosting.Lifetime","Environment":"Microsoft.AspNetCore.Hosting.HostingEnvironment"}} -{"Timestamp":"2022-09-13T02:59:03.3572754+02:00","Level":"Information","MessageTemplate":"02:59:03 Gateway You're using the GuildScheduledEvents gateway intent without listening to any events related to that intent, consider removing the intent from your config.","Properties":{"SourceContext":"Managing.Infrastructure.Messengers.Discord.DiscordService","Environment":"Microsoft.AspNetCore.Hosting.HostingEnvironment"}} -{"Timestamp":"2022-09-13T02:59:03.3628433+02:00","Level":"Information","MessageTemplate":"02:59:03 Gateway You're using the GuildInvites gateway intent without listening to any events related to that intent, consider removing the intent from your config.","Properties":{"SourceContext":"Managing.Infrastructure.Messengers.Discord.DiscordService","Environment":"Microsoft.AspNetCore.Hosting.HostingEnvironment"}} -{"Timestamp":"2022-09-13T02:59:03.3688717+02:00","Level":"Information","MessageTemplate":"02:59:03 Gateway Connected","Properties":{"SourceContext":"Managing.Infrastructure.Messengers.Discord.DiscordService","Environment":"Microsoft.AspNetCore.Hosting.HostingEnvironment"}} -{"Timestamp":"2022-09-13T02:59:03.9425506+02:00","Level":"Information","MessageTemplate":"02:59:03 Gateway Ready","Properties":{"SourceContext":"Managing.Infrastructure.Messengers.Discord.DiscordService","Environment":"Microsoft.AspNetCore.Hosting.HostingEnvironment"}} -{"Timestamp":"2022-09-13T02:59:10.5882097+02:00","Level":"Information","MessageTemplate":"{HostingRequestStartingLog:l}","Properties":{"Protocol":"HTTP/2","Method":"GET","ContentType":null,"ContentLength":null,"Scheme":"https","Host":"localhost:5001","PathBase":"","Path":"/index.html","QueryString":"","HostingRequestStartingLog":"Request starting HTTP/2 GET https://localhost:5001/index.html - -","EventId":{"Id":1},"SourceContext":"Microsoft.AspNetCore.Hosting.Diagnostics","RequestId":"0HMKL4CJ4LVHE:00000001","RequestPath":"/index.html","ConnectionId":"0HMKL4CJ4LVHE","Environment":"Microsoft.AspNetCore.Hosting.HostingEnvironment"},"Renderings":{"HostingRequestStartingLog":[{"Format":"l","Rendering":"Request starting HTTP/2 GET https://localhost:5001/index.html - -"}]}} -{"Timestamp":"2022-09-13T02:59:11.5711332+02:00","Level":"Information","MessageTemplate":"{HostingRequestFinishedLog:l}","Properties":{"ElapsedMilliseconds":996.3451,"StatusCode":200,"ContentType":"text/html;charset=utf-8","ContentLength":null,"Protocol":"HTTP/2","Method":"GET","Scheme":"https","Host":"localhost:5001","PathBase":"","Path":"/index.html","QueryString":"","HostingRequestFinishedLog":"Request finished HTTP/2 GET https://localhost:5001/index.html - - - 200 - text/html;charset=utf-8 996.3451ms","EventId":{"Id":2},"SourceContext":"Microsoft.AspNetCore.Hosting.Diagnostics","RequestId":"0HMKL4CJ4LVHE:00000001","RequestPath":"/index.html","ConnectionId":"0HMKL4CJ4LVHE","Environment":"Microsoft.AspNetCore.Hosting.HostingEnvironment"},"Renderings":{"HostingRequestFinishedLog":[{"Format":"l","Rendering":"Request finished HTTP/2 GET https://localhost:5001/index.html - - - 200 - text/html;charset=utf-8 996.3451ms"}]}} -{"Timestamp":"2022-09-13T02:59:11.6123850+02:00","Level":"Information","MessageTemplate":"{HostingRequestStartingLog:l}","Properties":{"Protocol":"HTTP/2","Method":"GET","ContentType":null,"ContentLength":null,"Scheme":"https","Host":"localhost:5001","PathBase":"","Path":"/_framework/aspnetcore-browser-refresh.js","QueryString":"","HostingRequestStartingLog":"Request starting HTTP/2 GET https://localhost:5001/_framework/aspnetcore-browser-refresh.js - -","EventId":{"Id":1},"SourceContext":"Microsoft.AspNetCore.Hosting.Diagnostics","RequestId":"0HMKL4CJ4LVHE:00000003","RequestPath":"/_framework/aspnetcore-browser-refresh.js","ConnectionId":"0HMKL4CJ4LVHE","Environment":"Microsoft.AspNetCore.Hosting.HostingEnvironment"},"Renderings":{"HostingRequestStartingLog":[{"Format":"l","Rendering":"Request starting HTTP/2 GET https://localhost:5001/_framework/aspnetcore-browser-refresh.js - -"}]}} -{"Timestamp":"2022-09-13T02:59:11.6281716+02:00","Level":"Information","MessageTemplate":"{HostingRequestFinishedLog:l}","Properties":{"ElapsedMilliseconds":15.5581,"StatusCode":200,"ContentType":"application/javascript; charset=utf-8","ContentLength":11994,"Protocol":"HTTP/2","Method":"GET","Scheme":"https","Host":"localhost:5001","PathBase":"","Path":"/_framework/aspnetcore-browser-refresh.js","QueryString":"","HostingRequestFinishedLog":"Request finished HTTP/2 GET https://localhost:5001/_framework/aspnetcore-browser-refresh.js - - - 200 11994 application/javascript;+charset=utf-8 15.5581ms","EventId":{"Id":2},"SourceContext":"Microsoft.AspNetCore.Hosting.Diagnostics","RequestId":"0HMKL4CJ4LVHE:00000003","RequestPath":"/_framework/aspnetcore-browser-refresh.js","ConnectionId":"0HMKL4CJ4LVHE","Environment":"Microsoft.AspNetCore.Hosting.HostingEnvironment"},"Renderings":{"HostingRequestFinishedLog":[{"Format":"l","Rendering":"Request finished HTTP/2 GET https://localhost:5001/_framework/aspnetcore-browser-refresh.js - - - 200 11994 application/javascript;+charset=utf-8 15.5581ms"}]}} -{"Timestamp":"2022-09-13T02:59:11.7015500+02:00","Level":"Information","MessageTemplate":"{HostingRequestStartingLog:l}","Properties":{"Protocol":"HTTP/2","Method":"GET","ContentType":null,"ContentLength":null,"Scheme":"https","Host":"localhost:5001","PathBase":"","Path":"/_vs/browserLink","QueryString":"","HostingRequestStartingLog":"Request starting HTTP/2 GET https://localhost:5001/_vs/browserLink - -","EventId":{"Id":1},"SourceContext":"Microsoft.AspNetCore.Hosting.Diagnostics","RequestId":"0HMKL4CJ4LVHE:00000005","RequestPath":"/_vs/browserLink","ConnectionId":"0HMKL4CJ4LVHE","Environment":"Microsoft.AspNetCore.Hosting.HostingEnvironment"},"Renderings":{"HostingRequestStartingLog":[{"Format":"l","Rendering":"Request starting HTTP/2 GET https://localhost:5001/_vs/browserLink - -"}]}} -{"Timestamp":"2022-09-13T02:59:11.8214511+02:00","Level":"Information","MessageTemplate":"{HostingRequestFinishedLog:l}","Properties":{"ElapsedMilliseconds":119.7799,"StatusCode":200,"ContentType":"text/javascript; charset=UTF-8","ContentLength":null,"Protocol":"HTTP/2","Method":"GET","Scheme":"https","Host":"localhost:5001","PathBase":"","Path":"/_vs/browserLink","QueryString":"","HostingRequestFinishedLog":"Request finished HTTP/2 GET https://localhost:5001/_vs/browserLink - - - 200 - text/javascript;+charset=UTF-8 119.7799ms","EventId":{"Id":2},"SourceContext":"Microsoft.AspNetCore.Hosting.Diagnostics","RequestId":"0HMKL4CJ4LVHE:00000005","RequestPath":"/_vs/browserLink","ConnectionId":"0HMKL4CJ4LVHE","Environment":"Microsoft.AspNetCore.Hosting.HostingEnvironment"},"Renderings":{"HostingRequestFinishedLog":[{"Format":"l","Rendering":"Request finished HTTP/2 GET https://localhost:5001/_vs/browserLink - - - 200 - text/javascript;+charset=UTF-8 119.7799ms"}]}} -{"Timestamp":"2022-09-13T02:59:11.9652804+02:00","Level":"Information","MessageTemplate":"{HostingRequestStartingLog:l}","Properties":{"Protocol":"HTTP/2","Method":"GET","ContentType":null,"ContentLength":null,"Scheme":"https","Host":"localhost:5001","PathBase":"","Path":"/swagger/v1/swagger.json","QueryString":"","HostingRequestStartingLog":"Request starting HTTP/2 GET https://localhost:5001/swagger/v1/swagger.json - -","EventId":{"Id":1},"SourceContext":"Microsoft.AspNetCore.Hosting.Diagnostics","RequestId":"0HMKL4CJ4LVHE:00000007","RequestPath":"/swagger/v1/swagger.json","ConnectionId":"0HMKL4CJ4LVHE","Environment":"Microsoft.AspNetCore.Hosting.HostingEnvironment"},"Renderings":{"HostingRequestStartingLog":[{"Format":"l","Rendering":"Request starting HTTP/2 GET https://localhost:5001/swagger/v1/swagger.json - -"}]}} -{"Timestamp":"2022-09-13T02:59:12.3915820+02:00","Level":"Information","MessageTemplate":"{HostingRequestFinishedLog:l}","Properties":{"ElapsedMilliseconds":426.2987,"StatusCode":200,"ContentType":"application/json;charset=utf-8","ContentLength":null,"Protocol":"HTTP/2","Method":"GET","Scheme":"https","Host":"localhost:5001","PathBase":"","Path":"/swagger/v1/swagger.json","QueryString":"","HostingRequestFinishedLog":"Request finished HTTP/2 GET https://localhost:5001/swagger/v1/swagger.json - - - 200 - application/json;charset=utf-8 426.2987ms","EventId":{"Id":2},"SourceContext":"Microsoft.AspNetCore.Hosting.Diagnostics","RequestId":"0HMKL4CJ4LVHE:00000007","RequestPath":"/swagger/v1/swagger.json","ConnectionId":"0HMKL4CJ4LVHE","Environment":"Microsoft.AspNetCore.Hosting.HostingEnvironment"},"Renderings":{"HostingRequestFinishedLog":[{"Format":"l","Rendering":"Request finished HTTP/2 GET https://localhost:5001/swagger/v1/swagger.json - - - 200 - application/json;charset=utf-8 426.2987ms"}]}} diff --git a/src/Managing.Docker/docker-compose.local.yml b/src/Managing.Docker/docker-compose.local.yml index 012cfa09..f4485abe 100644 --- a/src/Managing.Docker/docker-compose.local.yml +++ b/src/Managing.Docker/docker-compose.local.yml @@ -8,9 +8,12 @@ services: - ASPNETCORE_URLS=https://+:443;http://+:80 - ASPNETCORE_Kestrel__Certificates__Default__Password=!Managing94 - ASPNETCORE_Kestrel__Certificates__Default__Path=/app/managing_cert.pfx + - RUN_ORLEANS_GRAINS=true ports: - "80:80" - "443:443" + - "11111:11111" # Orleans silo port + - "30000:30000" # Orleans gateway port volumes: - ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro - ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro @@ -18,6 +21,7 @@ services: - /Users/oda/Microsoft/UserSecrets:/root/.microsoft/usersecrets/$USER_SECRETS_ID depends_on: - postgres + - influxdb postgres: image: postgres:17.5 diff --git a/src/Managing.Docker/docker-compose.yml b/src/Managing.Docker/docker-compose.yml index ea8a5225..c4314f05 100644 --- a/src/Managing.Docker/docker-compose.yml +++ b/src/Managing.Docker/docker-compose.yml @@ -8,12 +8,6 @@ services: dockerfile: Managing.Api/Dockerfile networks: - managing-network - ports: - - "11111:11111" # Orleans silo port - - "30000:30000" # Orleans gateway port - environment: - - ASPNETCORE_ENVIRONMENT=Production - - RUN_ORLEANS_GRAINS=true hostname: managing-api influxdb: diff --git a/src/Managing.Web3Proxy/src/plugins/custom/privy.ts b/src/Managing.Web3Proxy/src/plugins/custom/privy.ts index 23f4474f..dd04c504 100644 --- a/src/Managing.Web3Proxy/src/plugins/custom/privy.ts +++ b/src/Managing.Web3Proxy/src/plugins/custom/privy.ts @@ -566,6 +566,7 @@ export const initAddressImpl = async ( console.log('exchangeRouterAllowance', exchangeRouterAllowance) let exchangeRouterHash = ""; + console.log('approveAmount', approveAmount) if (exchangeRouterAllowance < approveAmount) { exchangeRouterHash = await approveContractImpl( address, @@ -782,7 +783,6 @@ export const getWalletBalanceImpl = async ( // Get user by wallet address const user = await privy.getUserByWalletAddress(address); - if (!user) { throw new Error(`User not found for wallet address: ${address}`); } diff --git a/src/Managing.Web3Proxy/test/plugins/initPrivyWallet.test.ts b/src/Managing.Web3Proxy/test/plugins/initPrivyWallet.test.ts new file mode 100644 index 00000000..57ce69d7 --- /dev/null +++ b/src/Managing.Web3Proxy/test/plugins/initPrivyWallet.test.ts @@ -0,0 +1,26 @@ +import {test} from 'node:test' +import assert from 'node:assert' +import {initAddressImpl} from '../../src/plugins/custom/privy' + +test('Privy Wallet Initialization', async (t) => { + await t.test('should initialize a wallet address for GMX trading', async () => { + const address = '0x0b4a132cb6ed8fa66953bf61a53d0b91dacaad78' + + const result = await initAddressImpl(address) + + console.log('Wallet initialization result:', result) + + // Verify the result structure + assert.ok(result, 'Wallet initialization result should be defined') + assert.ok(result.usdcHash, 'USDC hash should be defined') + assert.ok(result.orderVaultHash, 'Order vault hash should be defined') + assert.ok(result.exchangeRouterHash, 'Exchange router hash should be defined') + assert.ok(result.wethSyntheticsRouterHash, 'WETH synthetics router hash should be defined') + + // Verify all hashes are strings + assert.strictEqual(typeof result.usdcHash, 'string', 'USDC hash should be a string') + assert.strictEqual(typeof result.orderVaultHash, 'string', 'Order vault hash should be a string') + assert.strictEqual(typeof result.exchangeRouterHash, 'string', 'Exchange router hash should be a string') + assert.strictEqual(typeof result.wethSyntheticsRouterHash, 'string', 'WETH synthetics router hash should be a string') + }) +}) diff --git a/src/Managing.Web3Proxy/test/plugins/open-position.test.ts b/src/Managing.Web3Proxy/test/plugins/open-position.test.ts index 4804fd91..e11f32ed 100644 --- a/src/Managing.Web3Proxy/test/plugins/open-position.test.ts +++ b/src/Managing.Web3Proxy/test/plugins/open-position.test.ts @@ -5,17 +5,17 @@ import {Ticker, TradeDirection} from '../../src/generated/ManagingApiTypes' test('GMX Position Opening', async (t) => { await t.test('should open a long position for BTC', async () => { - const sdk = await getClientForAddress('0x932167388dD9aad41149b3cA23eBD489E2E2DD78') + const sdk = await getClientForAddress('0x0b4A132cb6ed8fa66953bf61a53D0B91DaCaAd78') const result = await openGmxPositionImpl( sdk, - Ticker.ETH, + Ticker.BTC, TradeDirection.Long, - 0.00678, + 0.00009129924572776991, 2, - 4410, - 3500, - 6000 + 111350, + 110000, + 114000 ) console.log('Position opening result:', result) assert.ok(result, 'Position opening result should be defined') diff --git a/src/Managing.Web3Proxy/test/plugins/scrypt.test.ts b/src/Managing.Web3Proxy/test/plugins/scrypt.test.ts deleted file mode 100644 index 09d0371e..00000000 --- a/src/Managing.Web3Proxy/test/plugins/scrypt.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { test } from 'node:test' -import Fastify from 'fastify' -import scryptPlugin from '../../src/plugins/custom/scrypt.js' -import assert from 'node:assert' - -test('scrypt works standalone', async t => { - const app = Fastify() - - t.after(() => app.close()) - - app.register(scryptPlugin) - - await app.ready() - - const password = 'test_password' - const hash = await app.hash(password) - assert.ok(typeof hash === 'string') - - const isValid = await app.compare(password, hash) - assert.ok(isValid, 'compare should return true for correct password') - - const isInvalid = await app.compare('wrong_password', hash) - assert.ok(!isInvalid, 'compare should return false for incorrect password') - - await assert.rejects( - () => app.compare(password, 'malformed_hash'), - 'compare should throw an error for malformed hash' - ) -})