Skip to content
This repository was archived by the owner on Feb 8, 2025. It is now read-only.

Commit 9424378

Browse files
authored
Merge pull request #272 from zallo-labs/Z-322-fix-sim
fix(api): inserting simulation of self-transfer
2 parents fef5991 + b266f44 commit 9424378

File tree

7 files changed

+287
-230
lines changed

7 files changed

+287
-230
lines changed

api/dbschema/edgeql-js/__spec__.ts

+70-70
Large diffs are not rendered by default.

api/dbschema/edgeql-js/modules/default.ts

+101-101
Large diffs are not rendered by default.

api/dbschema/edgeql-js/modules/schema.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -700,14 +700,14 @@ export type $ObjectTypeλShape = $.typeutil.flatten<$SourceλShape & Omit<$Consi
700700
"<__type__[is Result]": $.LinkDesc<_default.$Result, $.Cardinality.Many, {}, false, false, false, false>;
701701
"<__type__[is ReceiptResult]": $.LinkDesc<_default.$ReceiptResult, $.Cardinality.Many, {}, false, false, false, false>;
702702
"<__type__[is Successful]": $.LinkDesc<_default.$Successful, $.Cardinality.Many, {}, false, false, false, false>;
703-
"<__type__[is Approver]": $.LinkDesc<_default.$Approver, $.Cardinality.Many, {}, false, false, false, false>;
704-
"<__type__[is current_approver]": $.LinkDesc<_default.$current_approver, $.Cardinality.Many, {}, false, false, false, false>;
705-
"<__type__[is Rejection]": $.LinkDesc<_default.$Rejection, $.Cardinality.Many, {}, false, false, false, false>;
703+
"<__type__[is ApproverDetails]": $.LinkDesc<_default.$ApproverDetails, $.Cardinality.Many, {}, false, false, false, false>;
706704
"<__type__[is Message]": $.LinkDesc<_default.$Message, $.Cardinality.Many, {}, false, false, false, false>;
707705
"<__type__[is Operation]": $.LinkDesc<_default.$Operation, $.Cardinality.Many, {}, false, false, false, false>;
708706
"<__type__[is Transaction]": $.LinkDesc<_default.$Transaction, $.Cardinality.Many, {}, false, false, false, false>;
709707
"<__type__[is UserLabelled]": $.LinkDesc<_default.$UserLabelled, $.Cardinality.Many, {}, false, false, false, false>;
710708
"<__type__[is Token]": $.LinkDesc<_default.$Token, $.Cardinality.Many, {}, false, false, false, false>;
709+
"<__type__[is Approver]": $.LinkDesc<_default.$Approver, $.Cardinality.Many, {}, false, false, false, false>;
710+
"<__type__[is current_approver]": $.LinkDesc<_default.$current_approver, $.Cardinality.Many, {}, false, false, false, false>;
711711
"<__type__[is User]": $.LinkDesc<_default.$User, $.Cardinality.Many, {}, false, false, false, false>;
712712
"<__type__[is current_user]": $.LinkDesc<_default.$current_user, $.Cardinality.Many, {}, false, false, false, false>;
713713
"<__type__[is Contact]": $.LinkDesc<_default.$Contact, $.Cardinality.Many, {}, false, false, false, false>;
@@ -717,6 +717,7 @@ export type $ObjectTypeλShape = $.typeutil.flatten<$SourceλShape & Omit<$Consi
717717
"<__type__[is Transferlike]": $.LinkDesc<_default.$Transferlike, $.Cardinality.Many, {}, false, false, false, false>;
718718
"<__type__[is Transfer]": $.LinkDesc<_default.$Transfer, $.Cardinality.Many, {}, false, false, false, false>;
719719
"<__type__[is TransferApproval]": $.LinkDesc<_default.$TransferApproval, $.Cardinality.Many, {}, false, false, false, false>;
720+
"<__type__[is Rejection]": $.LinkDesc<_default.$Rejection, $.Cardinality.Many, {}, false, false, false, false>;
720721
"<__type__[is ActionFunction]": $.LinkDesc<_default.$ActionFunction, $.Cardinality.Many, {}, false, false, false, false>;
721722
"<__type__[is Action]": $.LinkDesc<_default.$Action, $.Cardinality.Many, {}, false, false, false, false>;
722723
"<__type__[is TransferLimit]": $.LinkDesc<_default.$TransferLimit, $.Cardinality.Many, {}, false, false, false, false>;
@@ -730,7 +731,6 @@ export type $ObjectTypeλShape = $.typeutil.flatten<$SourceλShape & Omit<$Consi
730731
"<__type__[is PaymasterFees]": $.LinkDesc<_default.$PaymasterFees, $.Cardinality.Many, {}, false, false, false, false>;
731732
"<__type__[is Function]": $.LinkDesc<_default.$Function, $.Cardinality.Many, {}, false, false, false, false>;
732733
"<__type__[is Contract]": $.LinkDesc<_default.$Contract, $.Cardinality.Many, {}, false, false, false, false>;
733-
"<__type__[is ApproverDetails]": $.LinkDesc<_default.$ApproverDetails, $.Cardinality.Many, {}, false, false, false, false>;
734734
"<__type__": $.LinkDesc<$.ObjectType, $.Cardinality.Many, {}, false, false, false, false>;
735735
"<intersection_of": $.LinkDesc<$.ObjectType, $.Cardinality.Many, {}, false, false, false, false>;
736736
"<subject": $.LinkDesc<$.ObjectType, $.Cardinality.Many, {}, false, false, false, false>;

api/dbschema/interfaces.ts

+13-13
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,12 @@ export namespace $default {
8787
"implementation": string;
8888
"photo"?: string | null;
8989
"salt": string;
90+
"policies": Policy[];
9091
"approvers": Approver[];
9192
"messages": Message[];
9293
"proposals": Proposal[];
9394
"transactions": Transaction[];
9495
"transfers": Transfer[];
95-
"policies": Policy[];
9696
}
9797
export interface Action extends std.$Object {
9898
"functions": ActionFunction[];
@@ -119,18 +119,18 @@ export namespace $default {
119119
export type ApprovalIssue = "HashMismatch" | "Expired";
120120
export interface Approver extends std.$Object {
121121
"address": string;
122-
"user": User;
123122
"labelled"?: Labelled | null;
124-
"accounts": Account[];
125123
"details"?: ApproverDetails | null;
126124
"label"?: string | null;
125+
"user": User;
126+
"accounts": Account[];
127127
}
128128
export interface ApproverDetails extends std.$Object {
129-
"approver": Approver;
130-
"name"?: string | null;
131129
"bluetoothDevices"?: string[] | null;
130+
"name"?: string | null;
132131
"cloud"?: {provider: CloudProvider, subject: string} | null;
133132
"pushToken"?: string | null;
133+
"approver": Approver;
134134
}
135135
export type CloudProvider = "Apple" | "Google";
136136
export interface UserLabelled extends Labelled {}
@@ -145,11 +145,11 @@ export namespace $default {
145145
export interface Event extends std.$Object {
146146
"account": Account;
147147
"block": bigint;
148+
"internal": boolean;
148149
"logIndex": number;
149150
"systxHash": string;
150151
"timestamp": Date;
151152
"systx"?: SystemTx | null;
152-
"internal": boolean;
153153
}
154154
export interface Result extends std.$Object {
155155
"timestamp": Date;
@@ -185,9 +185,9 @@ export namespace $default {
185185
"timestamp": Date;
186186
"validationErrors": {reason: string, operation: number}[];
187187
"approvals": Approval[];
188+
"policy": Policy;
188189
"proposedBy": Approver;
189190
"rejections": Rejection[];
190-
"policy": Policy;
191191
}
192192
export interface Message extends Proposal {
193193
"signature"?: string | null;
@@ -214,9 +214,9 @@ export namespace $default {
214214
"draft"?: PolicyState | null;
215215
"proposal"?: Transaction | null;
216216
"initState": boolean;
217+
"isActive": boolean;
217218
"isDraft": boolean;
218219
"latest"?: PolicyState | null;
219-
"isActive": boolean;
220220
"isLatest": boolean;
221221
}
222222
export interface Policy extends PolicyState {
@@ -256,16 +256,16 @@ export namespace $default {
256256
"result"?: Result | null;
257257
}
258258
export interface Token extends UserLabelled {
259+
"units"?: {symbol: string, decimals: number}[] | null;
259260
"address": string;
261+
"symbol": string;
262+
"name": string;
260263
"decimals": number;
261264
"isFeeToken": boolean;
262265
"icon"?: string | null;
263266
"pythUsdPriceId"?: string | null;
264267
"user"?: User | null;
265268
"isSystem": boolean;
266-
"units"?: {symbol: string, decimals: number}[] | null;
267-
"name": string;
268-
"symbol": string;
269269
}
270270
export interface Transaction extends Proposal {
271271
"maxAmount": string;
@@ -291,10 +291,10 @@ export namespace $default {
291291
"token"?: Token | null;
292292
"amount": string;
293293
"from": string;
294-
"isFeeTransfer": boolean;
295-
"to": string;
296294
"incoming": boolean;
295+
"isFeeTransfer": boolean;
297296
"outgoing": boolean;
297+
"to": string;
298298
}
299299
export interface Transferlike extends Event, TransferDetails {
300300
"spentBy"?: Policy | null;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
with tx := (select Transaction filter .id = <uuid>$transaction),
2+
transfers := <array<json>>$transfers,
3+
account := tx.account
4+
select {
5+
prevSimulation := (delete tx.simulation),
6+
tx := (
7+
update tx set {
8+
executable := <bool>$executable,
9+
simulation := (insert Simulation {
10+
success := <bool>$success,
11+
responses := <array<Bytes>>$responses,
12+
transfers := assert_distinct((
13+
for transfer in array_unpack(transfers) union (
14+
insert TransferDetails {
15+
account := account,
16+
from := <Address>transfer['from'],
17+
to := <Address>transfer['to'],
18+
tokenAddress := <UAddress>transfer['tokenAddress'],
19+
amount := <decimal><str>transfer['amount'],
20+
incoming := <bool>transfer['incoming'],
21+
outgoing := <bool>transfer['outgoing']
22+
}
23+
) if count(transfers) > 0 else {}
24+
))
25+
})
26+
}
27+
)
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// GENERATED by @edgedb/generate v0.5.3
2+
3+
import type {Executor} from "edgedb";
4+
5+
export type InsertSimulationArgs = {
6+
readonly "transaction": string;
7+
readonly "transfers": ReadonlyArray<unknown>;
8+
readonly "executable": boolean;
9+
readonly "success": boolean;
10+
readonly "responses": ReadonlyArray<string>;
11+
};
12+
13+
export type InsertSimulationReturns = {
14+
"prevSimulation": {
15+
"id": string;
16+
} | null;
17+
"tx": {
18+
"id": string;
19+
} | null;
20+
};
21+
22+
export function insertSimulation(client: Executor, args: InsertSimulationArgs): Promise<InsertSimulationReturns> {
23+
return client.queryRequiredSingle(`\
24+
with tx := (select Transaction filter .id = <uuid>$transaction),
25+
transfers := <array<json>>$transfers,
26+
account := tx.account
27+
select {
28+
prevSimulation := (delete tx.simulation),
29+
tx := (
30+
update tx set {
31+
executable := <bool>$executable,
32+
simulation := (insert Simulation {
33+
success := <bool>$success,
34+
responses := <array<Bytes>>$responses,
35+
transfers := assert_distinct((
36+
for transfer in array_unpack(transfers) union (
37+
insert TransferDetails {
38+
account := account,
39+
from := <Address>transfer['from'],
40+
to := <Address>transfer['to'],
41+
tokenAddress := <UAddress>transfer['tokenAddress'],
42+
amount := <decimal><str>transfer['amount'],
43+
incoming := <bool>transfer['incoming'],
44+
outgoing := <bool>transfer['outgoing']
45+
}
46+
) if count(transfers) > 0 else {}
47+
))
48+
})
49+
}
50+
)
51+
}`, args);
52+
53+
}

api/src/feat/simulations/simulations.worker.ts

+18-42
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import { DatabaseService } from '~/core/database';
2020
import e, { $infer } from '~/edgeql-js';
2121
import { and } from '~/core/database';
2222
import { OperationsService } from '../operations/operations.service';
23-
import { selectAccount } from '../accounts/accounts.util';
2423
import { SwapOp, TransferFromOp, TransferOp } from '../operations/operations.model';
2524
import { RUNNING_JOB_STATUSES, TypedJob, createQueue } from '~/core/bull/bull.util';
2625
import { Worker } from '~/core/bull/Worker';
@@ -33,6 +32,7 @@ import { selectTransaction } from '../transactions/transactions.util';
3332
import { SelectedPolicies, selectPolicy } from '../policies/policies.util';
3433
import { ProposalsService } from '../proposals/proposals.service';
3534
import { ProposalEvent } from '../proposals/proposals.input';
35+
import { insertSimulation } from './insert-simulation.query';
3636

3737
export const SimulationsQueue = createQueue<{ transaction: UUID | Hex }>('Simulations');
3838
export type SimulationsQueue = typeof SimulationsQueue;
@@ -66,27 +66,26 @@ export class SimulationsWorker extends Worker<SimulationsQueue> {
6666

6767
async process(job: TypedJob<SimulationsQueue>) {
6868
const proposal = selectTransaction(job.data.transaction);
69-
const p = await this.db.query(
69+
const t = await this.db.query(
7070
e.select(proposal, () => ({
7171
id: true,
7272
...TransactionExecutableShape,
7373
})),
7474
);
75-
if (!p) return 'Transaction not found';
75+
if (!t) return 'Transaction not found';
7676

77-
const promisedExecutable = this.isExecutable(p);
78-
const account = asUAddress(p.account.address);
77+
const promisedExecutable = this.isExecutable(t);
78+
const account = asUAddress(t.account.address);
7979
const localAccount = asAddress(account);
8080
const chain = asChain(account);
81-
const selectedAccount = selectAccount(account);
8281

8382
const simulations = await Promise.all(
84-
p.operations.map(async (op) =>
83+
t.operations.map(async (op) =>
8584
(
8685
await simulate({
8786
network: this.networks.get(chain),
8887
account: localAccount,
89-
gas: p.gasLimit,
88+
gas: t.gasLimit,
9089
type: 'eip712',
9190
to: asAddress(op.to),
9291
value: op.value ?? 0n,
@@ -117,7 +116,7 @@ export class SimulationsWorker extends Worker<SimulationsQueue> {
117116
.filter(isTruthy);
118117

119118
const transfers: Omit<TransferDetails, 'account'>[] = [];
120-
for (const op of p.operations) {
119+
for (const op of t.operations) {
121120
if (op.value) {
122121
transfers.push({
123122
from: localAccount,
@@ -142,7 +141,7 @@ export class SimulationsWorker extends Worker<SimulationsQueue> {
142141
from: localAccount,
143142
to: f.to,
144143
tokenAddress: asUAddress(f.token, chain),
145-
amount: f.to === localAccount ? e.decimal('0') : f.amount.negated().toString(),
144+
amount: f.to === localAccount ? '0' : f.amount.negated().toString(),
146145
incoming: localAccount === f.to,
147146
outgoing: true,
148147
});
@@ -168,38 +167,15 @@ export class SimulationsWorker extends Worker<SimulationsQueue> {
168167
}
169168

170169
const executable = await promisedExecutable;
171-
await this.db.query(
172-
e.select({
173-
prevSimulation: e.delete(proposal.simulation, () => ({})),
174-
proposal: e.update(proposal, () => ({
175-
set: {
176-
executable,
177-
simulation: e.insert(e.Simulation, {
178-
success,
179-
responses,
180-
...(transfers.length && {
181-
transfers: e.with(
182-
[selectedAccount],
183-
e.for(e.set(...transfers.map((t) => e.json(t))), (t) =>
184-
e.insert(e.TransferDetails, {
185-
account: selectedAccount,
186-
from: e.cast(e.Address, t.from),
187-
to: e.cast(e.Address, t.to),
188-
tokenAddress: e.cast(e.UAddress, t.tokenAddress),
189-
amount: e.cast(e.decimal, e.cast(e.str, t.amount)),
190-
incoming: e.cast(e.bool, t.incoming),
191-
outgoing: e.cast(e.bool, t.outgoing),
192-
}),
193-
),
194-
),
195-
}),
196-
}),
197-
},
198-
})),
199-
}),
200-
);
201-
202-
this.proposals.event({ id: asUUID(p.id), account }, ProposalEvent.simulated);
170+
await this.db.exec(insertSimulation, {
171+
transaction: t.id,
172+
executable,
173+
success,
174+
responses,
175+
transfers,
176+
});
177+
178+
this.proposals.event({ id: asUUID(t.id), account }, ProposalEvent.simulated);
203179

204180
return { executable };
205181
}

0 commit comments

Comments
 (0)