-
Notifications
You must be signed in to change notification settings - Fork 54
Expand file tree
/
Copy pathsync.ts
More file actions
165 lines (140 loc) · 6.11 KB
/
Copy pathsync.ts
File metadata and controls
165 lines (140 loc) · 6.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import { gql, gqlAll } from "~gateways/api";
import { AO_YIELD_AGENT_SYNC_QUERY } from "./queries";
import { getAOYieldAgentInfo, getAOYieldAgents, setAOYieldAgents, updateAOYieldAgent } from "./utils";
import { log, LOG_GROUP } from "~utils/log/log.utils";
import {
AO_YIELD_AGENT_SYNC_ALARM_NAME_PREFIX,
AO_YIELD_AGENT_SYNC_STATUS_PREFIX_KEY,
HAS_SHOWN_AGENTS_EXPLAINER_POPUP,
SHOW_CREATE_WANDER_AGENT_CTA,
} from "./constants";
import browser from "webextension-polyfill";
import type { AOYieldAgent } from "./types";
import { IS_EMBEDDED_APP } from "~utils/embedded/embedded.constants";
import { pLimit } from "plimit-lit";
import { ExtensionStorage } from "~utils/storage";
import { queryClient } from "~utils/tanstack";
import { isWalletUnlocked } from "~wallets/auth";
import { getTagValue } from "~tokens/aoTokens/ao";
const limit = pLimit(10);
export async function checkAndSyncAgents(address: string): Promise<void> {
try {
await ExtensionStorage.set(AO_YIELD_AGENT_SYNC_STATUS_PREFIX_KEY + address, {
status: "in_progress",
timestamp: Date.now(),
});
if (!address) {
log(LOG_GROUP.AGENTS, "No address provided");
return;
}
log(LOG_GROUP.AGENTS, "Checking and syncing agents for: ", address);
let agents = await getAOYieldAgents(address);
if (agents.length > 0) {
log(LOG_GROUP.AGENTS, "Agents already present, no need to sync");
return;
}
const edges = await gqlAll(AO_YIELD_AGENT_SYNC_QUERY, { address });
if (edges.length === 0) {
log(LOG_GROUP.AGENTS, "No agents found");
return;
}
// sort edges by timestamp in ascending order
const sortedEdges = edges.sort((a, b) => {
const aDate = new Date(a.node.block?.timestamp ? a.node.block.timestamp * 1000 : Date.now());
const bDate = new Date(b.node.block?.timestamp ? b.node.block.timestamp * 1000 : Date.now());
return aDate.getTime() - bDate.getTime();
});
const foundAgents = sortedEdges.map((edge) => {
const agentVersion = getTagValue("Agent-Version", edge?.node?.tags) || "1.0.0";
return { agentId: edge.node.id, agentVersion };
});
// Set extension storage values immediately since we know agents exist
await ExtensionStorage.set(HAS_SHOWN_AGENTS_EXPLAINER_POPUP, true);
await ExtensionStorage.set(SHOW_CREATE_WANDER_AGENT_CTA, false);
// Read existing agents once and maintain ordered slots
const currentAgents = await getAOYieldAgents(address);
const agentSlots: (AOYieldAgent | null)[] = new Array(foundAgents.length).fill(null);
let successCount = 0;
const agentInfoPromises = foundAgents.map(({ agentId, agentVersion }, index) =>
limit(async () => {
try {
log(LOG_GROUP.AGENTS, `Fetching agent info for ${agentId}`);
const agentInfo = await queryClient.fetchQuery({
queryKey: ["ao-yield-agent-info", agentId],
queryFn: () => getAOYieldAgentInfo(agentId, agentVersion),
staleTime: 0, // Force fresh data
gcTime: 0,
retry: 1,
retryDelay: (attemptIndex: number) => Math.min(1000 * 2 ** attemptIndex, 30000),
});
if (!agentInfo) {
log(LOG_GROUP.AGENTS, `Agent info not found for ${agentId}`);
return null;
}
log(LOG_GROUP.AGENTS, `Agent info fetched for ${agentId}`);
if (!agentInfo.agentVersion) {
log(LOG_GROUP.AGENTS, `Agent version not found for ${agentId}`);
return null;
}
const agent: AOYieldAgent = {
id: agentId,
status: agentInfo.status,
conversionPercentage: agentInfo.conversionPercentage,
tokenOut: agentInfo.tokenOut,
startDate: agentInfo.startDate,
endDate: agentInfo.endDate,
runIndefinitely: agentInfo.runIndefinitely,
slippage: agentInfo.slippage,
version: agentInfo.agentVersion,
};
// Store agent in correct position and update storage with ordered agents
agentSlots[index] = agent;
const orderedNewAgents = agentSlots.filter((agent): agent is AOYieldAgent => agent !== null);
await setAOYieldAgents(address, [...currentAgents, ...orderedNewAgents]);
successCount++;
log(LOG_GROUP.AGENTS, `Agent ${agentId} added at position ${index} (${successCount}/${foundAgents.length})`);
return agent;
} catch (error) {
log(LOG_GROUP.AGENTS, `Error fetching agent info for ${agentId}:`, error);
return null;
}
}),
);
await Promise.allSettled(agentInfoPromises);
try {
log(LOG_GROUP.AGENTS, "Checking for expired agents");
const aoAgents = await getAOYieldAgents(address);
const expiredAgents = aoAgents.filter((agent) => agent.status === "Active" && agent.endDate < Date.now());
const expiredPromises = expiredAgents.map(async (agent) => {
const walletUnlocked = await isWalletUnlocked();
if (walletUnlocked) {
await updateAOYieldAgent(agent.id, { status: "Completed" });
}
});
log(LOG_GROUP.AGENTS, `Updating ${expiredAgents.length} expired agents status to completed`);
await Promise.allSettled(expiredPromises);
} catch (error) {
log(LOG_GROUP.AGENTS, "Error checking for expired agents: ", error);
}
if (successCount > 0) {
log(LOG_GROUP.AGENTS, `Successfully synced ${successCount} agents progressively`);
} else {
log(LOG_GROUP.AGENTS, "No valid agents were fetched successfully");
}
} catch (error) {
log(LOG_GROUP.AGENTS, "Error checking and syncing agents: ", error);
} finally {
await ExtensionStorage.remove(AO_YIELD_AGENT_SYNC_STATUS_PREFIX_KEY + address);
}
}
export async function scheduleAgentsSync(address: string) {
if (IS_EMBEDDED_APP) return;
try {
const alarmName = AO_YIELD_AGENT_SYNC_ALARM_NAME_PREFIX + address;
const alarms = await browser.alarms.get(alarmName);
if (alarms) return;
browser.alarms.create(alarmName, { when: Date.now() });
} catch (error) {
log(LOG_GROUP.AGENTS, "Error scheduling agents sync: ", error);
}
}