diff --git a/src/Managing.Api/Controllers/TradingController.cs b/src/Managing.Api/Controllers/TradingController.cs
index bd053d18..cf465dad 100644
--- a/src/Managing.Api/Controllers/TradingController.cs
+++ b/src/Managing.Api/Controllers/TradingController.cs
@@ -200,6 +200,49 @@ public class TradingController : BaseController
}
}
+ ///
+ /// Revokes all token approvals for a Privy wallet address.
+ /// Only admins can revoke approvals for any address, regular users can only revoke approvals for their own addresses.
+ ///
+ /// The public address of the Privy wallet to revoke approvals for.
+ /// The revocation response containing success status and transaction hashes.
+ [HttpPost("RevokeAllApprovals")]
+ public async Task> RevokeAllApprovals([FromBody] string publicAddress)
+ {
+ if (string.IsNullOrEmpty(publicAddress))
+ {
+ return BadRequest("Public address cannot be null or empty.");
+ }
+
+ try
+ {
+ var user = await GetUser();
+ if (user == null)
+ {
+ return Unauthorized("User not found");
+ }
+
+ // Check if user has permission to revoke approvals for this address
+ if (!await CanUserInitializeAddress(user.Name, publicAddress))
+ {
+ return Forbid(
+ "You don't have permission to revoke approvals for this wallet address. You can only revoke approvals for your own wallet addresses.");
+ }
+
+ var result = await _tradingService.RevokeAllApprovals(publicAddress);
+ return Ok(result);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error revoking all approvals for Privy wallet address: {Address}", publicAddress);
+ return StatusCode(500, new Managing.Infrastructure.Evm.Models.Privy.PrivyRevokeAllApprovalsResponse
+ {
+ Success = false,
+ Error = "An error occurred while revoking all approvals for the Privy wallet address."
+ });
+ }
+ }
+
///
/// Checks if the user can initialize the given public address.
/// Admins can initialize any address, regular users can only initialize their own addresses.
diff --git a/src/Managing.Api/appsettings.json b/src/Managing.Api/appsettings.json
index 95225bb0..ad88ac95 100644
--- a/src/Managing.Api/appsettings.json
+++ b/src/Managing.Api/appsettings.json
@@ -28,7 +28,7 @@
},
"Llm": {
"Gemini": {
- "DefaultModel": "gemini-2.0-flash"
+ "DefaultModel": "gemini/gemini-3-flash-preview"
},
"OpenAI": {
"DefaultModel": "gpt-4o"
diff --git a/src/Managing.Application.Abstractions/Services/ITradingService.cs b/src/Managing.Application.Abstractions/Services/ITradingService.cs
index b31543ff..65026f5a 100644
--- a/src/Managing.Application.Abstractions/Services/ITradingService.cs
+++ b/src/Managing.Application.Abstractions/Services/ITradingService.cs
@@ -69,6 +69,8 @@ public interface ITradingService
DateTime startDate,
DateTime endDate,
List indicators);
+
+ Task RevokeAllApprovals(string publicAddress);
}
///
diff --git a/src/Managing.Application.Abstractions/Services/IWeb3ProxyService.cs b/src/Managing.Application.Abstractions/Services/IWeb3ProxyService.cs
index 1b5254c8..32d99d85 100644
--- a/src/Managing.Application.Abstractions/Services/IWeb3ProxyService.cs
+++ b/src/Managing.Application.Abstractions/Services/IWeb3ProxyService.cs
@@ -41,5 +41,7 @@ namespace Managing.Application.Abstractions.Services
string? ticker = null,
DateTime? fromDate = null,
DateTime? toDate = null);
+
+ Task RevokeAllApprovalsAsync(string address);
}
}
\ No newline at end of file
diff --git a/src/Managing.Application/Trading/TradingService.cs b/src/Managing.Application/Trading/TradingService.cs
index 11dfac08..19b3de7b 100644
--- a/src/Managing.Application/Trading/TradingService.cs
+++ b/src/Managing.Application/Trading/TradingService.cs
@@ -542,12 +542,39 @@ public class TradingService : ITradingService
// Generate signals for the date range using rolling window approach
var signals = GenerateSignalsForDateRange(candlesList, scenario, indicatorsValues);
- return new RefineIndicatorsResult
+ return new RefineIndicatorsResult
+ {
+ IndicatorsValues = indicatorsValues,
+ Signals = signals
+ };
+ }
+
+ public async Task RevokeAllApprovals(string publicAddress)
{
- IndicatorsValues = indicatorsValues,
- Signals = signals
- };
- }
+ try
+ {
+ if (string.IsNullOrEmpty(publicAddress))
+ {
+ _logger.LogWarning("Attempted to revoke approvals with null or empty public address");
+ return new Managing.Infrastructure.Evm.Models.Privy.PrivyRevokeAllApprovalsResponse
+ { Success = false, Error = "Public address cannot be null or empty" };
+ }
+
+ // Call the Web3ProxyService to revoke all approvals
+ var result = await _web3ProxyService.RevokeAllApprovalsAsync(publicAddress);
+
+ return result;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error revoking all approvals for address {PublicAddress}", publicAddress);
+ return new Managing.Infrastructure.Evm.Models.Privy.PrivyRevokeAllApprovalsResponse
+ {
+ Success = false,
+ Error = ex.Message
+ };
+ }
+ }
///
/// Maps IndicatorRequest list to a domain Scenario object.
diff --git a/src/Managing.Domain/Evm/PrivyRevokeAllApprovalsResponse.cs b/src/Managing.Domain/Evm/PrivyRevokeAllApprovalsResponse.cs
new file mode 100644
index 00000000..c7f366a2
--- /dev/null
+++ b/src/Managing.Domain/Evm/PrivyRevokeAllApprovalsResponse.cs
@@ -0,0 +1,18 @@
+namespace Managing.Infrastructure.Evm.Models.Privy;
+
+public class PrivyRevokeAllApprovalsResponse
+{
+ public bool Success { get; set; }
+ public string? OrderVaultUsdcHash { get; set; }
+ public string? OrderVaultWethHash { get; set; }
+ public string? ExchangeRouterUsdcHash { get; set; }
+ public string? ExchangeRouterWethHash { get; set; }
+ public string? SyntheticsRouterUsdcHash { get; set; }
+ public string? SyntheticsRouterWethHash { get; set; }
+ public string? DataStoreUsdcHash { get; set; }
+ public string? DataStoreWethHash { get; set; }
+ public string? DepositVaultUsdcHash { get; set; }
+ public string? DepositVaultWethHash { get; set; }
+ public string? Error { get; set; }
+}
+
diff --git a/src/Managing.Infrastructure.Web3/Services/Web3ProxyService.cs b/src/Managing.Infrastructure.Web3/Services/Web3ProxyService.cs
index c0d29841..cc740417 100644
--- a/src/Managing.Infrastructure.Web3/Services/Web3ProxyService.cs
+++ b/src/Managing.Infrastructure.Web3/Services/Web3ProxyService.cs
@@ -819,5 +819,19 @@ namespace Managing.Infrastructure.Evm.Services
return positions;
}
+
+ public async Task RevokeAllApprovalsAsync(string address)
+ {
+ var payload = new { address };
+
+ var response = await CallPrivyServiceAsync("/revoke-all-approvals", payload);
+
+ if (response == null)
+ {
+ throw new Web3ProxyException("Revoke all approvals response is null");
+ }
+
+ return response;
+ }
}
}
\ No newline at end of file
diff --git a/src/Managing.Web3Proxy/src/generated/ManagingApiTypes.ts b/src/Managing.Web3Proxy/src/generated/ManagingApiTypes.ts
index d7c51156..a7045f98 100644
--- a/src/Managing.Web3Proxy/src/generated/ManagingApiTypes.ts
+++ b/src/Managing.Web3Proxy/src/generated/ManagingApiTypes.ts
@@ -1444,40 +1444,6 @@ export interface JobStatusTypeSummary {
count?: number;
}
-export interface LlmProgressUpdate {
- type?: string;
- message?: string;
- iteration?: number | null;
- maxIterations?: number | null;
- toolName?: string | null;
- toolArguments?: { [key: string]: any; } | null;
- content?: string | null;
- response?: LlmChatResponse | null;
- error?: string | null;
- timestamp?: Date;
-}
-
-export interface LlmChatResponse {
- content?: string;
- provider?: string;
- model?: string;
- toolCalls?: LlmToolCall[] | null;
- usage?: LlmUsage | null;
- requiresToolExecution?: boolean;
-}
-
-export interface LlmToolCall {
- id?: string;
- name?: string;
- arguments?: { [key: string]: any; };
-}
-
-export interface LlmUsage {
- promptTokens?: number;
- completionTokens?: number;
- totalTokens?: number;
-}
-
export interface LlmChatRequest {
messages?: LlmMessage[];
provider?: string | null;
@@ -1488,6 +1454,10 @@ export interface LlmChatRequest {
tools?: McpToolDefinition[] | null;
}
+export interface LlmChatStreamRequest extends LlmChatRequest {
+ connectionId?: string | null;
+}
+
export interface LlmMessage {
role?: string;
content?: string;
@@ -1495,6 +1465,12 @@ export interface LlmMessage {
toolCallId?: string | null;
}
+export interface LlmToolCall {
+ id?: string;
+ name?: string;
+ arguments?: { [key: string]: any; };
+}
+
export interface McpToolDefinition {
name?: string;
description?: string;
@@ -1508,6 +1484,21 @@ export interface McpParameterDefinition {
defaultValue?: any | null;
}
+export interface LlmChatResponse {
+ content?: string;
+ provider?: string;
+ model?: string;
+ toolCalls?: LlmToolCall[] | null;
+ usage?: LlmUsage | null;
+ requiresToolExecution?: boolean;
+}
+
+export interface LlmUsage {
+ promptTokens?: number;
+ completionTokens?: number;
+ totalTokens?: number;
+}
+
export interface ScenarioViewModel {
name: string;
indicators: IndicatorViewModel[];
@@ -1548,6 +1539,21 @@ export interface PrivyInitAddressResponse {
isAlreadyInitialized?: boolean;
}
+export interface PrivyRevokeAllApprovalsResponse {
+ success?: boolean;
+ orderVaultUsdcHash?: string | null;
+ orderVaultWethHash?: string | null;
+ exchangeRouterUsdcHash?: string | null;
+ exchangeRouterWethHash?: string | null;
+ syntheticsRouterUsdcHash?: string | null;
+ syntheticsRouterWethHash?: string | null;
+ dataStoreUsdcHash?: string | null;
+ dataStoreWethHash?: string | null;
+ depositVaultUsdcHash?: string | null;
+ depositVaultWethHash?: string | null;
+ error?: string | null;
+}
+
export interface IndicatorRequestDto {
indicatorName: string;
strategyDescription: string;
diff --git a/src/Managing.Web3Proxy/src/plugins/custom/privy.ts b/src/Managing.Web3Proxy/src/plugins/custom/privy.ts
index 70ae74a7..2e771b78 100644
--- a/src/Managing.Web3Proxy/src/plugins/custom/privy.ts
+++ b/src/Managing.Web3Proxy/src/plugins/custom/privy.ts
@@ -45,6 +45,7 @@ declare module 'fastify' {
signPrivyMessage: typeof signPrivyMessage;
approveToken: typeof approveToken;
initAddress: typeof initAddress;
+ revokeAllApprovals: typeof revokeAllApprovals;
sendToken: typeof sendToken;
getWalletBalance: typeof getWalletBalance;
getTokenBalanceOnChain: typeof getTokenBalanceOnChain;
@@ -975,6 +976,277 @@ export async function initAddress(
}
}
+/**
+ * Revokes all token approvals for an address by setting approvals to 0 for all GMX contracts
+ * @param address The wallet address to revoke approvals for
+ * @returns Object containing transaction hashes for all revoked approvals
+ */
+export const revokeAllApprovalsImpl = async (
+ address: string,
+ fastify?: FastifyInstance
+): Promise<{
+ orderVaultUsdcHash: string,
+ orderVaultWethHash: string,
+ exchangeRouterUsdcHash: string,
+ exchangeRouterWethHash: string,
+ syntheticsRouterUsdcHash: string,
+ syntheticsRouterWethHash: string,
+ dataStoreUsdcHash: string,
+ dataStoreWethHash: string,
+ depositVaultUsdcHash: string,
+ depositVaultWethHash: string
+}> => {
+ try {
+ console.log('š« Starting revocation of all approvals for address:', address);
+
+ const sdk = await getClientForAddress(address);
+ const {tokensData} = await sdk.tokens.getTokensData();
+ const usdcTokenData = getTokenDataFromTicker(Ticker.USDC, tokensData);
+ const wrapperEtherData = getTokenDataFromTicker("WETH", tokensData);
+
+ // Revoke by setting approval to 0
+ const revokeAmount = BigInt(0);
+ console.log('š Revocation amount set to:', revokeAmount.toString());
+
+ // Get USDC and WETH token addresses
+ const usdcToken = GetToken('USDC');
+ console.log('š± USDC Token Address:', usdcToken.address);
+ console.log('š± WETH Token Address:', wrapperEtherData.address);
+
+ const results: any = {};
+
+ // ============================================================================
+ // Revoke OrderVault Approvals
+ // ============================================================================
+ console.log('\nš Step 1: Revoking OrderVault approvals...');
+
+ // USDC approval for OrderVault
+ console.log(' Revoking USDC -> OrderVault approval...');
+ results.orderVaultUsdcHash = await approveContractImpl(
+ address,
+ usdcToken.address,
+ CONTRACTS[ARBITRUM].OrderVault,
+ ARBITRUM,
+ revokeAmount,
+ true,
+ fastify
+ );
+ console.log(' ā
USDC OrderVault revocation hash:', results.orderVaultUsdcHash);
+
+ // WETH approval for OrderVault
+ console.log(' Revoking WETH -> OrderVault approval...');
+ results.orderVaultWethHash = await approveContractImpl(
+ address,
+ wrapperEtherData.address,
+ CONTRACTS[ARBITRUM].OrderVault,
+ ARBITRUM,
+ revokeAmount,
+ true,
+ fastify
+ );
+ console.log(' ā
WETH OrderVault revocation hash:', results.orderVaultWethHash);
+
+ // ============================================================================
+ // Revoke ExchangeRouter Approvals
+ // ============================================================================
+ console.log('\nš Step 2: Revoking ExchangeRouter approvals...');
+
+ // USDC approval for ExchangeRouter
+ console.log(' Revoking USDC -> ExchangeRouter approval...');
+ results.exchangeRouterUsdcHash = await approveContractImpl(
+ address,
+ usdcToken.address,
+ CONTRACTS[ARBITRUM].ExchangeRouter,
+ ARBITRUM,
+ revokeAmount,
+ true,
+ fastify
+ );
+ console.log(' ā
USDC ExchangeRouter revocation hash:', results.exchangeRouterUsdcHash);
+
+ // WETH approval for ExchangeRouter
+ console.log(' Revoking WETH -> ExchangeRouter approval...');
+ results.exchangeRouterWethHash = await approveContractImpl(
+ address,
+ wrapperEtherData.address,
+ CONTRACTS[ARBITRUM].ExchangeRouter,
+ ARBITRUM,
+ revokeAmount,
+ true,
+ fastify
+ );
+ console.log(' ā
WETH ExchangeRouter revocation hash:', results.exchangeRouterWethHash);
+
+ // ============================================================================
+ // Revoke SyntheticsRouter Approvals
+ // ============================================================================
+ console.log('\nš Step 3: Revoking SyntheticsRouter approvals...');
+
+ // USDC approval for SyntheticsRouter
+ console.log(' Revoking USDC -> SyntheticsRouter approval...');
+ results.syntheticsRouterUsdcHash = await approveContractImpl(
+ address,
+ usdcToken.address,
+ CONTRACTS[ARBITRUM].SyntheticsRouter,
+ ARBITRUM,
+ revokeAmount,
+ true,
+ fastify
+ );
+ console.log(' ā
USDC SyntheticsRouter revocation hash:', results.syntheticsRouterUsdcHash);
+
+ // WETH approval for SyntheticsRouter
+ console.log(' Revoking WETH -> SyntheticsRouter approval...');
+ results.syntheticsRouterWethHash = await approveContractImpl(
+ address,
+ wrapperEtherData.address,
+ CONTRACTS[ARBITRUM].SyntheticsRouter,
+ ARBITRUM,
+ revokeAmount,
+ true,
+ fastify
+ );
+ console.log(' ā
WETH SyntheticsRouter revocation hash:', results.syntheticsRouterWethHash);
+
+ // ============================================================================
+ // Revoke DataStore Approvals
+ // ============================================================================
+ console.log('\nš Step 4: Revoking DataStore approvals...');
+
+ // USDC approval for DataStore
+ console.log(' Revoking USDC -> DataStore approval...');
+ results.dataStoreUsdcHash = await approveContractImpl(
+ address,
+ usdcToken.address,
+ CONTRACTS[ARBITRUM].DataStore,
+ ARBITRUM,
+ revokeAmount,
+ true,
+ fastify
+ );
+ console.log(' ā
USDC DataStore revocation hash:', results.dataStoreUsdcHash);
+
+ // WETH approval for DataStore
+ console.log(' Revoking WETH -> DataStore approval...');
+ results.dataStoreWethHash = await approveContractImpl(
+ address,
+ wrapperEtherData.address,
+ CONTRACTS[ARBITRUM].DataStore,
+ ARBITRUM,
+ revokeAmount,
+ true,
+ fastify
+ );
+ console.log(' ā
WETH DataStore revocation hash:', results.dataStoreWethHash);
+
+ // ============================================================================
+ // Revoke DepositVault Approvals
+ // ============================================================================
+ console.log('\nš Step 5: Revoking DepositVault approvals...');
+
+ // USDC approval for DepositVault
+ console.log(' Revoking USDC -> DepositVault approval...');
+ results.depositVaultUsdcHash = await approveContractImpl(
+ address,
+ usdcToken.address,
+ CONTRACTS[ARBITRUM].DepositVault,
+ ARBITRUM,
+ revokeAmount,
+ true,
+ fastify
+ );
+ console.log(' ā
USDC DepositVault revocation hash:', results.depositVaultUsdcHash);
+
+ // WETH approval for DepositVault
+ console.log(' Revoking WETH -> DepositVault approval...');
+ results.depositVaultWethHash = await approveContractImpl(
+ address,
+ wrapperEtherData.address,
+ CONTRACTS[ARBITRUM].DepositVault,
+ ARBITRUM,
+ revokeAmount,
+ true,
+ fastify
+ );
+ console.log(' ā
WETH DepositVault revocation hash:', results.depositVaultWethHash);
+
+ // ============================================================================
+ // SUMMARY: Final revocation status
+ // ============================================================================
+ console.log('\nš Final Revocation Summary:');
+ console.log(' OrderVault USDC:', results.orderVaultUsdcHash);
+ console.log(' OrderVault WETH:', results.orderVaultWethHash);
+ console.log(' ExchangeRouter USDC:', results.exchangeRouterUsdcHash);
+ console.log(' ExchangeRouter WETH:', results.exchangeRouterWethHash);
+ console.log(' SyntheticsRouter USDC:', results.syntheticsRouterUsdcHash);
+ console.log(' SyntheticsRouter WETH:', results.syntheticsRouterWethHash);
+ console.log(' DataStore USDC:', results.dataStoreUsdcHash);
+ console.log(' DataStore WETH:', results.dataStoreWethHash);
+ console.log(' DepositVault USDC:', results.depositVaultUsdcHash);
+ console.log(' DepositVault WETH:', results.depositVaultWethHash);
+
+ // Clear approval cache for this address since all approvals have been revoked
+ try {
+ const {clearApprovalCacheForAccount} = await import('../../utils/approvalCache.js');
+ await clearApprovalCacheForAccount(ARBITRUM, address);
+ console.log(' ā
Approval cache cleared for address');
+ } catch (cacheError) {
+ console.warn(' ā ļø Failed to clear approval cache:', cacheError);
+ // Don't fail the entire operation if cache clearing fails
+ }
+
+ console.log('\nā
All approvals revoked successfully!');
+
+ return results;
+ } catch (error) {
+ console.error('ā Error revoking approvals:', error);
+ throw new Error(`Failed to revoke approvals: ${error instanceof Error ? error.message : 'Unknown error'}`);
+ }
+};
+
+/**
+ * Revokes all token approvals for a wallet address
+ * @param this The FastifyRequest instance
+ * @param reply The FastifyReply instance
+ * @param address The wallet address to revoke approvals for
+ * @returns The response object with success status and transaction hashes
+ */
+export async function revokeAllApprovals(
+ this: FastifyRequest,
+ reply: FastifyReply,
+ address: string
+) {
+ try {
+ if (!address) {
+ throw new Error('Wallet address is required for revocation');
+ }
+
+ const results = await revokeAllApprovalsImpl(address, this.server);
+
+ return {
+ success: true,
+ orderVaultUsdcHash: results.orderVaultUsdcHash,
+ orderVaultWethHash: results.orderVaultWethHash,
+ exchangeRouterUsdcHash: results.exchangeRouterUsdcHash,
+ exchangeRouterWethHash: results.exchangeRouterWethHash,
+ syntheticsRouterUsdcHash: results.syntheticsRouterUsdcHash,
+ syntheticsRouterWethHash: results.syntheticsRouterWethHash,
+ dataStoreUsdcHash: results.dataStoreUsdcHash,
+ dataStoreWethHash: results.dataStoreWethHash,
+ depositVaultUsdcHash: results.depositVaultUsdcHash,
+ depositVaultWethHash: results.depositVaultWethHash
+ };
+ } catch (error) {
+ this.log.error(error);
+
+ reply.status(500);
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : 'An unknown error occurred'
+ };
+ }
+}
+
/**
* Sends tokens from one address to another using Privy wallet (implementation)
* @param senderAddress The sender's wallet address
@@ -1756,6 +2028,10 @@ export default fp(async (fastify) => {
return initAddress.call(this, reply, address);
});
+ fastify.decorateRequest('revokeAllApprovals', async function(this: FastifyRequest, reply: FastifyReply, address: string) {
+ return revokeAllApprovals.call(this, reply, address);
+ });
+
fastify.decorateRequest('sendToken', async function(this: FastifyRequest, reply: FastifyReply, senderAddress: string, recipientAddress: string, ticker: string, amount: string, chainId?: number) {
return sendToken.call(this, reply, senderAddress, recipientAddress, ticker, amount, chainId);
});
diff --git a/src/Managing.Web3Proxy/src/routes/api/privy/index.ts b/src/Managing.Web3Proxy/src/routes/api/privy/index.ts
index a046db80..3f3db7c8 100644
--- a/src/Managing.Web3Proxy/src/routes/api/privy/index.ts
+++ b/src/Managing.Web3Proxy/src/routes/api/privy/index.ts
@@ -77,6 +77,50 @@ const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
}
)
+ fastify.post(
+ '/revoke-all-approvals',
+ {
+ schema: {
+ body: Type.Object({
+ address: Type.String()
+ }),
+ response: {
+ 200: Type.Object({
+ success: Type.Boolean(),
+ orderVaultUsdcHash: Type.Optional(Type.String()),
+ orderVaultWethHash: Type.Optional(Type.String()),
+ exchangeRouterUsdcHash: Type.Optional(Type.String()),
+ exchangeRouterWethHash: Type.Optional(Type.String()),
+ syntheticsRouterUsdcHash: Type.Optional(Type.String()),
+ syntheticsRouterWethHash: Type.Optional(Type.String()),
+ dataStoreUsdcHash: Type.Optional(Type.String()),
+ dataStoreWethHash: Type.Optional(Type.String()),
+ depositVaultUsdcHash: Type.Optional(Type.String()),
+ depositVaultWethHash: Type.Optional(Type.String()),
+ error: Type.Optional(Type.String())
+ }),
+ 400: Type.Object({
+ success: Type.Boolean(),
+ error: Type.String()
+ }),
+ 500: Type.Object({
+ success: Type.Boolean(),
+ error: Type.String()
+ })
+ },
+ tags: ['Privy']
+ }
+ },
+ async function (request, reply) {
+ try {
+ const { address } = request.body;
+ return await request.revokeAllApprovals(reply, address);
+ } catch (error) {
+ return handleError(request, reply, error, 'privy/revoke-all-approvals');
+ }
+ }
+ )
+
fastify.post(
'/send-token',
{
diff --git a/src/Managing.WebApp/src/generated/ManagingApi.ts b/src/Managing.WebApp/src/generated/ManagingApi.ts
index a6035a36..6339892f 100644
--- a/src/Managing.WebApp/src/generated/ManagingApi.ts
+++ b/src/Managing.WebApp/src/generated/ManagingApi.ts
@@ -2910,7 +2910,7 @@ export class LlmClient extends AuthorizedApiBase {
this.baseUrl = baseUrl ?? "http://localhost:5000";
}
- llm_ChatStream(request: LlmChatRequest): Promise {
+ llm_ChatStream(request: LlmChatStreamRequest): Promise {
let url_ = this.baseUrl + "/Llm/ChatStream";
url_ = url_.replace(/[?&]$/, "");
@@ -2921,7 +2921,7 @@ export class LlmClient extends AuthorizedApiBase {
method: "POST",
headers: {
"Content-Type": "application/json",
- "Accept": "application/json"
+ "Accept": "application/octet-stream"
}
};
@@ -2932,21 +2932,26 @@ export class LlmClient extends AuthorizedApiBase {
});
}
- protected processLlm_ChatStream(response: Response): Promise {
+ protected processLlm_ChatStream(response: Response): Promise {
const status = response.status;
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
- if (status === 200) {
- return response.text().then((_responseText) => {
- let result200: any = null;
- result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as LlmProgressUpdate[];
- return result200;
- });
+ if (status === 200 || status === 206) {
+ const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined;
+ let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : undefined;
+ let fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[3] || fileNameMatch[2] : undefined;
+ if (fileName) {
+ fileName = decodeURIComponent(fileName);
+ } else {
+ fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined;
+ fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined;
+ }
+ return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; });
} else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
- return Promise.resolve(null as any);
+ return Promise.resolve(null as any);
}
llm_Chat(request: LlmChatRequest): Promise {
@@ -4262,6 +4267,45 @@ export class TradingClient extends AuthorizedApiBase {
return Promise.resolve(null as any);
}
+ trading_RevokeAllApprovals(publicAddress: string): Promise {
+ let url_ = this.baseUrl + "/Trading/RevokeAllApprovals";
+ url_ = url_.replace(/[?&]$/, "");
+
+ const content_ = JSON.stringify(publicAddress);
+
+ let options_: RequestInit = {
+ body: content_,
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "Accept": "application/json"
+ }
+ };
+
+ return this.transformOptions(options_).then(transformedOptions_ => {
+ return this.http.fetch(url_, transformedOptions_);
+ }).then((_response: Response) => {
+ return this.processTrading_RevokeAllApprovals(_response);
+ });
+ }
+
+ protected processTrading_RevokeAllApprovals(response: Response): Promise {
+ const status = response.status;
+ let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
+ if (status === 200) {
+ return response.text().then((_responseText) => {
+ let result200: any = null;
+ result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as PrivyRevokeAllApprovalsResponse;
+ return result200;
+ });
+ } else if (status !== 200 && status !== 204) {
+ return response.text().then((_responseText) => {
+ return throwException("An unexpected server error occurred.", status, _responseText, _headers);
+ });
+ }
+ return Promise.resolve(null as any);
+ }
+
trading_RequestIndicator(request: IndicatorRequestDto): Promise {
let url_ = this.baseUrl + "/Trading/RequestIndicator";
url_ = url_.replace(/[?&]$/, "");
@@ -6272,40 +6316,6 @@ export interface JobStatusTypeSummary {
count?: number;
}
-export interface LlmProgressUpdate {
- type?: string;
- message?: string;
- iteration?: number | null;
- maxIterations?: number | null;
- toolName?: string | null;
- toolArguments?: { [key: string]: any; } | null;
- content?: string | null;
- response?: LlmChatResponse | null;
- error?: string | null;
- timestamp?: Date;
-}
-
-export interface LlmChatResponse {
- content?: string;
- provider?: string;
- model?: string;
- toolCalls?: LlmToolCall[] | null;
- usage?: LlmUsage | null;
- requiresToolExecution?: boolean;
-}
-
-export interface LlmToolCall {
- id?: string;
- name?: string;
- arguments?: { [key: string]: any; };
-}
-
-export interface LlmUsage {
- promptTokens?: number;
- completionTokens?: number;
- totalTokens?: number;
-}
-
export interface LlmChatRequest {
messages?: LlmMessage[];
provider?: string | null;
@@ -6316,6 +6326,10 @@ export interface LlmChatRequest {
tools?: McpToolDefinition[] | null;
}
+export interface LlmChatStreamRequest extends LlmChatRequest {
+ connectionId?: string | null;
+}
+
export interface LlmMessage {
role?: string;
content?: string;
@@ -6323,6 +6337,12 @@ export interface LlmMessage {
toolCallId?: string | null;
}
+export interface LlmToolCall {
+ id?: string;
+ name?: string;
+ arguments?: { [key: string]: any; };
+}
+
export interface McpToolDefinition {
name?: string;
description?: string;
@@ -6336,6 +6356,21 @@ export interface McpParameterDefinition {
defaultValue?: any | null;
}
+export interface LlmChatResponse {
+ content?: string;
+ provider?: string;
+ model?: string;
+ toolCalls?: LlmToolCall[] | null;
+ usage?: LlmUsage | null;
+ requiresToolExecution?: boolean;
+}
+
+export interface LlmUsage {
+ promptTokens?: number;
+ completionTokens?: number;
+ totalTokens?: number;
+}
+
export interface ScenarioViewModel {
name: string;
indicators: IndicatorViewModel[];
@@ -6376,6 +6411,21 @@ export interface PrivyInitAddressResponse {
isAlreadyInitialized?: boolean;
}
+export interface PrivyRevokeAllApprovalsResponse {
+ success?: boolean;
+ orderVaultUsdcHash?: string | null;
+ orderVaultWethHash?: string | null;
+ exchangeRouterUsdcHash?: string | null;
+ exchangeRouterWethHash?: string | null;
+ syntheticsRouterUsdcHash?: string | null;
+ syntheticsRouterWethHash?: string | null;
+ dataStoreUsdcHash?: string | null;
+ dataStoreWethHash?: string | null;
+ depositVaultUsdcHash?: string | null;
+ depositVaultWethHash?: string | null;
+ error?: string | null;
+}
+
export interface IndicatorRequestDto {
indicatorName: string;
strategyDescription: string;
diff --git a/src/Managing.WebApp/src/generated/ManagingApiTypes.ts b/src/Managing.WebApp/src/generated/ManagingApiTypes.ts
index d7c51156..a7045f98 100644
--- a/src/Managing.WebApp/src/generated/ManagingApiTypes.ts
+++ b/src/Managing.WebApp/src/generated/ManagingApiTypes.ts
@@ -1444,40 +1444,6 @@ export interface JobStatusTypeSummary {
count?: number;
}
-export interface LlmProgressUpdate {
- type?: string;
- message?: string;
- iteration?: number | null;
- maxIterations?: number | null;
- toolName?: string | null;
- toolArguments?: { [key: string]: any; } | null;
- content?: string | null;
- response?: LlmChatResponse | null;
- error?: string | null;
- timestamp?: Date;
-}
-
-export interface LlmChatResponse {
- content?: string;
- provider?: string;
- model?: string;
- toolCalls?: LlmToolCall[] | null;
- usage?: LlmUsage | null;
- requiresToolExecution?: boolean;
-}
-
-export interface LlmToolCall {
- id?: string;
- name?: string;
- arguments?: { [key: string]: any; };
-}
-
-export interface LlmUsage {
- promptTokens?: number;
- completionTokens?: number;
- totalTokens?: number;
-}
-
export interface LlmChatRequest {
messages?: LlmMessage[];
provider?: string | null;
@@ -1488,6 +1454,10 @@ export interface LlmChatRequest {
tools?: McpToolDefinition[] | null;
}
+export interface LlmChatStreamRequest extends LlmChatRequest {
+ connectionId?: string | null;
+}
+
export interface LlmMessage {
role?: string;
content?: string;
@@ -1495,6 +1465,12 @@ export interface LlmMessage {
toolCallId?: string | null;
}
+export interface LlmToolCall {
+ id?: string;
+ name?: string;
+ arguments?: { [key: string]: any; };
+}
+
export interface McpToolDefinition {
name?: string;
description?: string;
@@ -1508,6 +1484,21 @@ export interface McpParameterDefinition {
defaultValue?: any | null;
}
+export interface LlmChatResponse {
+ content?: string;
+ provider?: string;
+ model?: string;
+ toolCalls?: LlmToolCall[] | null;
+ usage?: LlmUsage | null;
+ requiresToolExecution?: boolean;
+}
+
+export interface LlmUsage {
+ promptTokens?: number;
+ completionTokens?: number;
+ totalTokens?: number;
+}
+
export interface ScenarioViewModel {
name: string;
indicators: IndicatorViewModel[];
@@ -1548,6 +1539,21 @@ export interface PrivyInitAddressResponse {
isAlreadyInitialized?: boolean;
}
+export interface PrivyRevokeAllApprovalsResponse {
+ success?: boolean;
+ orderVaultUsdcHash?: string | null;
+ orderVaultWethHash?: string | null;
+ exchangeRouterUsdcHash?: string | null;
+ exchangeRouterWethHash?: string | null;
+ syntheticsRouterUsdcHash?: string | null;
+ syntheticsRouterWethHash?: string | null;
+ dataStoreUsdcHash?: string | null;
+ dataStoreWethHash?: string | null;
+ depositVaultUsdcHash?: string | null;
+ depositVaultWethHash?: string | null;
+ error?: string | null;
+}
+
export interface IndicatorRequestDto {
indicatorName: string;
strategyDescription: string;
diff --git a/src/Managing.WebApp/src/pages/adminPage/account/accountTable.tsx b/src/Managing.WebApp/src/pages/adminPage/account/accountTable.tsx
index 4901b36d..13e92c0b 100644
--- a/src/Managing.WebApp/src/pages/adminPage/account/accountTable.tsx
+++ b/src/Managing.WebApp/src/pages/adminPage/account/accountTable.tsx
@@ -1,7 +1,7 @@
import {ChevronDownIcon, ChevronRightIcon,} from '@heroicons/react/solid'
import React, {useEffect, useMemo, useState} from 'react'
import {useNavigate} from 'react-router-dom'
-import {FiCopy, FiKey, FiPlay, FiTrash2, FiTrendingUp} from 'react-icons/fi'
+import {FiCopy, FiKey, FiPlay, FiTrash2, FiTrendingUp, FiX} from 'react-icons/fi'
import useApiUrlStore from '../../../app/store/apiStore'
import {SelectColumnFilter, Table, Toast,} from '../../../components/mollecules'
@@ -55,6 +55,22 @@ const AccountTable: React.FC = ({ list, isFetching }) => {
}
}
+ async function revokeAllApprovals(publicAddress: string) {
+ const t = new Toast('Revoking all approvals')
+ const client = new TradingClient({}, apiUrl)
+
+ try {
+ const response = await client.trading_RevokeAllApprovals(publicAddress)
+ if (response.success) {
+ t.update('success', 'All approvals revoked successfully')
+ } else {
+ t.update('error', `Revocation failed: ${response.error || 'Unknown error'}`)
+ }
+ } catch (err) {
+ t.update('error', 'Error: ' + err)
+ }
+ }
+
async function copyToClipboard(text: string) {
const t = new Toast('Copying to clipboard...')
try {
@@ -160,6 +176,14 @@ const AccountTable: React.FC = ({ list, isFetching }) => {
Init
+
+
+
+