Skip to content

Commit

Permalink
fix(api): inserting simulation of self-transfer
Browse files Browse the repository at this point in the history
  • Loading branch information
hbriese committed Jul 23, 2024
1 parent fef5991 commit b266f44
Show file tree
Hide file tree
Showing 7 changed files with 287 additions and 230 deletions.
140 changes: 70 additions & 70 deletions api/dbschema/edgeql-js/__spec__.ts

Large diffs are not rendered by default.

202 changes: 101 additions & 101 deletions api/dbschema/edgeql-js/modules/default.ts

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions api/dbschema/edgeql-js/modules/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -700,14 +700,14 @@ export type $ObjectTypeλShape = $.typeutil.flatten<$SourceλShape & Omit<$Consi
"<__type__[is Result]": $.LinkDesc<_default.$Result, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is ReceiptResult]": $.LinkDesc<_default.$ReceiptResult, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is Successful]": $.LinkDesc<_default.$Successful, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is Approver]": $.LinkDesc<_default.$Approver, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is current_approver]": $.LinkDesc<_default.$current_approver, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is Rejection]": $.LinkDesc<_default.$Rejection, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is ApproverDetails]": $.LinkDesc<_default.$ApproverDetails, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is Message]": $.LinkDesc<_default.$Message, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is Operation]": $.LinkDesc<_default.$Operation, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is Transaction]": $.LinkDesc<_default.$Transaction, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is UserLabelled]": $.LinkDesc<_default.$UserLabelled, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is Token]": $.LinkDesc<_default.$Token, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is Approver]": $.LinkDesc<_default.$Approver, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is current_approver]": $.LinkDesc<_default.$current_approver, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is User]": $.LinkDesc<_default.$User, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is current_user]": $.LinkDesc<_default.$current_user, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is Contact]": $.LinkDesc<_default.$Contact, $.Cardinality.Many, {}, false, false, false, false>;
Expand All @@ -717,6 +717,7 @@ export type $ObjectTypeλShape = $.typeutil.flatten<$SourceλShape & Omit<$Consi
"<__type__[is Transferlike]": $.LinkDesc<_default.$Transferlike, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is Transfer]": $.LinkDesc<_default.$Transfer, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is TransferApproval]": $.LinkDesc<_default.$TransferApproval, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is Rejection]": $.LinkDesc<_default.$Rejection, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is ActionFunction]": $.LinkDesc<_default.$ActionFunction, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is Action]": $.LinkDesc<_default.$Action, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is TransferLimit]": $.LinkDesc<_default.$TransferLimit, $.Cardinality.Many, {}, false, false, false, false>;
Expand All @@ -730,7 +731,6 @@ export type $ObjectTypeλShape = $.typeutil.flatten<$SourceλShape & Omit<$Consi
"<__type__[is PaymasterFees]": $.LinkDesc<_default.$PaymasterFees, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is Function]": $.LinkDesc<_default.$Function, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is Contract]": $.LinkDesc<_default.$Contract, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__[is ApproverDetails]": $.LinkDesc<_default.$ApproverDetails, $.Cardinality.Many, {}, false, false, false, false>;
"<__type__": $.LinkDesc<$.ObjectType, $.Cardinality.Many, {}, false, false, false, false>;
"<intersection_of": $.LinkDesc<$.ObjectType, $.Cardinality.Many, {}, false, false, false, false>;
"<subject": $.LinkDesc<$.ObjectType, $.Cardinality.Many, {}, false, false, false, false>;
Expand Down
26 changes: 13 additions & 13 deletions api/dbschema/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,12 @@ export namespace $default {
"implementation": string;
"photo"?: string | null;
"salt": string;
"policies": Policy[];
"approvers": Approver[];
"messages": Message[];
"proposals": Proposal[];
"transactions": Transaction[];
"transfers": Transfer[];
"policies": Policy[];
}
export interface Action extends std.$Object {
"functions": ActionFunction[];
Expand All @@ -119,18 +119,18 @@ export namespace $default {
export type ApprovalIssue = "HashMismatch" | "Expired";
export interface Approver extends std.$Object {
"address": string;
"user": User;
"labelled"?: Labelled | null;
"accounts": Account[];
"details"?: ApproverDetails | null;
"label"?: string | null;
"user": User;
"accounts": Account[];
}
export interface ApproverDetails extends std.$Object {
"approver": Approver;
"name"?: string | null;
"bluetoothDevices"?: string[] | null;
"name"?: string | null;
"cloud"?: {provider: CloudProvider, subject: string} | null;
"pushToken"?: string | null;
"approver": Approver;
}
export type CloudProvider = "Apple" | "Google";
export interface UserLabelled extends Labelled {}
Expand All @@ -145,11 +145,11 @@ export namespace $default {
export interface Event extends std.$Object {
"account": Account;
"block": bigint;
"internal": boolean;
"logIndex": number;
"systxHash": string;
"timestamp": Date;
"systx"?: SystemTx | null;
"internal": boolean;
}
export interface Result extends std.$Object {
"timestamp": Date;
Expand Down Expand Up @@ -185,9 +185,9 @@ export namespace $default {
"timestamp": Date;
"validationErrors": {reason: string, operation: number}[];
"approvals": Approval[];
"policy": Policy;
"proposedBy": Approver;
"rejections": Rejection[];
"policy": Policy;
}
export interface Message extends Proposal {
"signature"?: string | null;
Expand All @@ -214,9 +214,9 @@ export namespace $default {
"draft"?: PolicyState | null;
"proposal"?: Transaction | null;
"initState": boolean;
"isActive": boolean;
"isDraft": boolean;
"latest"?: PolicyState | null;
"isActive": boolean;
"isLatest": boolean;
}
export interface Policy extends PolicyState {
Expand Down Expand Up @@ -256,16 +256,16 @@ export namespace $default {
"result"?: Result | null;
}
export interface Token extends UserLabelled {
"units"?: {symbol: string, decimals: number}[] | null;
"address": string;
"symbol": string;
"name": string;
"decimals": number;
"isFeeToken": boolean;
"icon"?: string | null;
"pythUsdPriceId"?: string | null;
"user"?: User | null;
"isSystem": boolean;
"units"?: {symbol: string, decimals: number}[] | null;
"name": string;
"symbol": string;
}
export interface Transaction extends Proposal {
"maxAmount": string;
Expand All @@ -291,10 +291,10 @@ export namespace $default {
"token"?: Token | null;
"amount": string;
"from": string;
"isFeeTransfer": boolean;
"to": string;
"incoming": boolean;
"isFeeTransfer": boolean;
"outgoing": boolean;
"to": string;
}
export interface Transferlike extends Event, TransferDetails {
"spentBy"?: Policy | null;
Expand Down
28 changes: 28 additions & 0 deletions api/src/feat/simulations/insert-simulation.edgeql
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
with tx := (select Transaction filter .id = <uuid>$transaction),
transfers := <array<json>>$transfers,
account := tx.account
select {
prevSimulation := (delete tx.simulation),
tx := (
update tx set {
executable := <bool>$executable,
simulation := (insert Simulation {
success := <bool>$success,
responses := <array<Bytes>>$responses,
transfers := assert_distinct((
for transfer in array_unpack(transfers) union (
insert TransferDetails {
account := account,
from := <Address>transfer['from'],
to := <Address>transfer['to'],
tokenAddress := <UAddress>transfer['tokenAddress'],
amount := <decimal><str>transfer['amount'],
incoming := <bool>transfer['incoming'],
outgoing := <bool>transfer['outgoing']
}
) if count(transfers) > 0 else {}
))
})
}
)
}
53 changes: 53 additions & 0 deletions api/src/feat/simulations/insert-simulation.query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// GENERATED by @edgedb/generate v0.5.3

import type {Executor} from "edgedb";

export type InsertSimulationArgs = {
readonly "transaction": string;
readonly "transfers": ReadonlyArray<unknown>;
readonly "executable": boolean;
readonly "success": boolean;
readonly "responses": ReadonlyArray<string>;
};

export type InsertSimulationReturns = {
"prevSimulation": {
"id": string;
} | null;
"tx": {
"id": string;
} | null;
};

export function insertSimulation(client: Executor, args: InsertSimulationArgs): Promise<InsertSimulationReturns> {
return client.queryRequiredSingle(`\
with tx := (select Transaction filter .id = <uuid>$transaction),
transfers := <array<json>>$transfers,
account := tx.account
select {
prevSimulation := (delete tx.simulation),
tx := (
update tx set {
executable := <bool>$executable,
simulation := (insert Simulation {
success := <bool>$success,
responses := <array<Bytes>>$responses,
transfers := assert_distinct((
for transfer in array_unpack(transfers) union (
insert TransferDetails {
account := account,
from := <Address>transfer['from'],
to := <Address>transfer['to'],
tokenAddress := <UAddress>transfer['tokenAddress'],
amount := <decimal><str>transfer['amount'],
incoming := <bool>transfer['incoming'],
outgoing := <bool>transfer['outgoing']
}
) if count(transfers) > 0 else {}
))
})
}
)
}`, args);

}
60 changes: 18 additions & 42 deletions api/src/feat/simulations/simulations.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { DatabaseService } from '~/core/database';
import e, { $infer } from '~/edgeql-js';
import { and } from '~/core/database';
import { OperationsService } from '../operations/operations.service';
import { selectAccount } from '../accounts/accounts.util';
import { SwapOp, TransferFromOp, TransferOp } from '../operations/operations.model';
import { RUNNING_JOB_STATUSES, TypedJob, createQueue } from '~/core/bull/bull.util';
import { Worker } from '~/core/bull/Worker';
Expand All @@ -33,6 +32,7 @@ import { selectTransaction } from '../transactions/transactions.util';
import { SelectedPolicies, selectPolicy } from '../policies/policies.util';
import { ProposalsService } from '../proposals/proposals.service';
import { ProposalEvent } from '../proposals/proposals.input';
import { insertSimulation } from './insert-simulation.query';

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

async process(job: TypedJob<SimulationsQueue>) {
const proposal = selectTransaction(job.data.transaction);
const p = await this.db.query(
const t = await this.db.query(
e.select(proposal, () => ({
id: true,
...TransactionExecutableShape,
})),
);
if (!p) return 'Transaction not found';
if (!t) return 'Transaction not found';

const promisedExecutable = this.isExecutable(p);
const account = asUAddress(p.account.address);
const promisedExecutable = this.isExecutable(t);
const account = asUAddress(t.account.address);
const localAccount = asAddress(account);
const chain = asChain(account);
const selectedAccount = selectAccount(account);

const simulations = await Promise.all(
p.operations.map(async (op) =>
t.operations.map(async (op) =>
(
await simulate({
network: this.networks.get(chain),
account: localAccount,
gas: p.gasLimit,
gas: t.gasLimit,
type: 'eip712',
to: asAddress(op.to),
value: op.value ?? 0n,
Expand Down Expand Up @@ -117,7 +116,7 @@ export class SimulationsWorker extends Worker<SimulationsQueue> {
.filter(isTruthy);

const transfers: Omit<TransferDetails, 'account'>[] = [];
for (const op of p.operations) {
for (const op of t.operations) {
if (op.value) {
transfers.push({
from: localAccount,
Expand All @@ -142,7 +141,7 @@ export class SimulationsWorker extends Worker<SimulationsQueue> {
from: localAccount,
to: f.to,
tokenAddress: asUAddress(f.token, chain),
amount: f.to === localAccount ? e.decimal('0') : f.amount.negated().toString(),
amount: f.to === localAccount ? '0' : f.amount.negated().toString(),
incoming: localAccount === f.to,
outgoing: true,
});
Expand All @@ -168,38 +167,15 @@ export class SimulationsWorker extends Worker<SimulationsQueue> {
}

const executable = await promisedExecutable;
await this.db.query(
e.select({
prevSimulation: e.delete(proposal.simulation, () => ({})),
proposal: e.update(proposal, () => ({
set: {
executable,
simulation: e.insert(e.Simulation, {
success,
responses,
...(transfers.length && {
transfers: e.with(
[selectedAccount],
e.for(e.set(...transfers.map((t) => e.json(t))), (t) =>
e.insert(e.TransferDetails, {
account: selectedAccount,
from: e.cast(e.Address, t.from),
to: e.cast(e.Address, t.to),
tokenAddress: e.cast(e.UAddress, t.tokenAddress),
amount: e.cast(e.decimal, e.cast(e.str, t.amount)),
incoming: e.cast(e.bool, t.incoming),
outgoing: e.cast(e.bool, t.outgoing),
}),
),
),
}),
}),
},
})),
}),
);

this.proposals.event({ id: asUUID(p.id), account }, ProposalEvent.simulated);
await this.db.exec(insertSimulation, {
transaction: t.id,
executable,
success,
responses,
transfers,
});

this.proposals.event({ id: asUUID(t.id), account }, ProposalEvent.simulated);

return { executable };
}
Expand Down

0 comments on commit b266f44

Please sign in to comment.