Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/tender-sloths-judge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@exactly/mobile": patch
---

♿️ add aria label to loan amount selector
19 changes: 19 additions & 0 deletions .maestro/flows/local.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,25 @@ tags: [critical]
commands: [{ tapOn: Home }]
- runFlow: ../subflows/readPortfolio.yaml
- assertTrue: ${output.portfolioBefore - output.portfolio === 69}
- evalScript: ${output.portfolioBefore = output.portfolio}
- runFlow:
file: ../subflows/borrowAsset.yaml
env: { amount: "10", installments: "4" }
- tapOn: Home
- runFlow: # HACK https://github.com/mobile-dev-inc/Maestro/issues/2914
when: { true: "${maestro.platform != 'web'}" }
commands:
- repeat:
while: { visible: Pending proposals }
commands: [{ tapOn: Home }]
- runFlow: # HACK https://github.com/mobile-dev-inc/Maestro/issues/2914
when: { platform: web }
commands:
- repeat:
while: { visible: { id: Pending proposals } }
commands: [{ tapOn: Home }]
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- runFlow: ../subflows/readPortfolio.yaml
- assertTrue: ${output.portfolio - output.portfolioBefore === 10}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- runFlow:
when: { visible: Getting Started }
commands:
Expand Down
6 changes: 6 additions & 0 deletions .maestro/src/anvil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
type Quantity,
type ReadContractParameters,
type ReadContractReturnType,
type RpcLog,
type RpcTransactionReceipt,
type TransactionRequest,
type WriteContractParameters,
Expand Down Expand Up @@ -50,6 +51,7 @@ export function writeContract<

declare const output: { id?: number };

export default function anvil(method: "eth_blockNumber", params: readonly []): Hex;
export default function anvil(
method: "eth_call",
params: readonly [transaction: ExactPartial<TransactionRequest>],
Expand All @@ -58,6 +60,10 @@ export default function anvil(
method: "eth_getBalance",
params: readonly [account: Address, block: BlockIdentifier | BlockNumber<number> | BlockTag],
): `0x${string}`;
export default function anvil(
method: "eth_getLogs",
params: readonly [filter: { address?: Address; fromBlock?: Hex; toBlock?: Hex; topics?: (Hex | Hex[] | null)[] }],
): RpcLog[];
export default function anvil(
method: "eth_getTransactionCount",
params: readonly [account: Address, block: BlockIdentifier | BlockNumber<number> | BlockTag],
Expand Down
23 changes: 21 additions & 2 deletions .maestro/src/script/hookProposals.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { isHex } from "viem/utils";
import { erc20Abi, pad } from "viem";
import { getAbiItem, isHex, toEventSelector } from "viem/utils";

import { proposalManagerAbi, proposalManagerAddress } from "@exactly/common/generated/chain";

import anvil, { readContract } from "../anvil";
import { block } from "../server";
import { activity, block } from "../server";

declare const account: string | undefined;
declare const count: string | undefined;
Expand All @@ -30,4 +31,22 @@ const proposals = Array.from({ length }, (_, index) => {
});

anvil("anvil_mine", [1, Number(proposalDelay)]);
const fromBlock = anvil("eth_blockNumber", []);
block(account, proposals);

while (
readContract({ address: proposalManagerAddress, functionName: "nonces", args: [account], abi: proposalManagerAbi }) <
nextNonce
);
Comment thread
cruzdanilo marked this conversation as resolved.
Comment thread
cruzdanilo marked this conversation as resolved.
Comment thread
cruzdanilo marked this conversation as resolved.
Comment thread
cruzdanilo marked this conversation as resolved.
Comment thread
cruzdanilo marked this conversation as resolved.
const toBlock = anvil("eth_blockNumber", []);
const logs = anvil("eth_getLogs", [
{
fromBlock,
toBlock,
topics: [toEventSelector(getAbiItem({ abi: erc20Abi, name: "Transfer" })), null, pad(account)],
},
]);
for (const log of logs) {
const decimals = readContract({ address: log.address, functionName: "decimals", abi: erc20Abi });
activity(log.address, account, Number(BigInt(log.data)) / 10 ** decimals);
}
39 changes: 39 additions & 0 deletions .maestro/subflows/borrowAsset.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
appId: ${APP_ID ?? "app.exactly"}
---
- assertTrue: ${amount && !Number.isNaN(Number(amount))}
- assertTrue: ${installments && !Number.isNaN(Number(installments))}
Comment thread
cruzdanilo marked this conversation as resolved.
- tapOn: DeFi
- runFlow:
when: { visible: Explore decentralized services }
commands: [{ tapOn: "Explore decentralized services" }]
- tapOn: USDC funding
- runFlow:
when: { visible: Connect wallet to Exactly Protocol }
commands: [{ tapOn: Connect wallet to Exactly Protocol }]
- tapOn: Explore funding options
- assertVisible: Select amount
- runFlow: # HACK https://github.com/mobile-dev-inc/Maestro/issues/2914
when: { true: "${maestro.platform != 'web'}" }
commands: [{ tapOn: Amount }]
- runFlow: # HACK https://github.com/mobile-dev-inc/Maestro/issues/2914
when: { platform: web }
commands: [{ tapOn: { id: Amount } }]
- inputText: ${amount}
- tapOn: Select Amount # HACK
- tapOn: Continue
- assertVisible: Select your funding installment plan
- tapOn: "${installments + ' installment' + (installments > 1 ? 's' : '') + ' of'}"
- tapOn: Continue
- assertVisible: Select first due date
- tapOn: "^[A-Z][a-z]+ \\d+, \\d{4}$"
- tapOn: Continue
- assertVisible: Your Exa account
- tapOn: Review loan terms
- assertVisible: Review terms
- tapOn: Confirm and receive USDC
- extendedWaitUntil: { visible: Funding request sent, timeout: 180000 }
- runScript: ../dist/getAccount.js
- runScript:
file: ../dist/hookProposals.js
env: { account: "${output.account}" }
Comment thread
cruzdanilo marked this conversation as resolved.
- tapOn: Close
4 changes: 4 additions & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"domerrors",
"ecommerce",
"ellipsize",
"erigon",
"facta",
"farcaster",
"favware",
Expand All @@ -80,6 +81,7 @@
"initializable",
"interactable",
"ioredis",
"ipfs",
"isows",
"itofarina",
"IWETH",
Expand Down Expand Up @@ -109,6 +111,7 @@
"onesignal",
"opengraph",
"opensearch",
"otterscan",
"parameterless",
"passwordless",
"pglite",
Expand Down Expand Up @@ -138,6 +141,7 @@
"solana",
"solhint",
"solmate",
"sourcify",
"spkg",
"spotlightjs",
"staticcall",
Expand Down
2 changes: 1 addition & 1 deletion server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"generate:release": "echo \"module.exports = /** @type {const} */ ('$(git describe --tags --abbrev=7 --match '@exactly/server@*' | sed 's/@exactly\\///')')\" > generated/release.js",
"generate:openapi": "tsx script/openapi.ts",
"generate:sql": "POSTGRES_URL=postgres drizzle-kit export > generated/schema.sql",
"generate:broadcasts": "[ \"$CHAIN_ID\" != 31337 ] || tsx -e 'require(\"./test/anvil\").default({ provide: () => undefined }).then((teardown) => teardown())'",
"generate:broadcasts": "[ \"$CHAIN_ID\" != 31337 ] || NODE_ENV=development tsx -e 'require(\"./test/anvil\").default({ provide: () => undefined }).then((teardown) => teardown())'",
"db:push": "drizzle-kit push",
"e2e": "tsx script/e2e.ts",
"test": "nx test server",
Expand Down
2 changes: 1 addition & 1 deletion server/script/e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ process.on("uncaughtException", () => null);
process.stdout.on("error", () => null);
process.stderr.on("error", () => null);

const v = spawn("vitest", ["run"], { stdio: ["ignore", "pipe", "pipe"], env: { ...process.env, FORCE_COLOR: "1" } });
const v = spawn("vitest", ["--watch"], { stdio: ["ignore", "pipe", "pipe"], env: { ...process.env, FORCE_COLOR: "1" } });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n server/script/e2e.ts

Repository: exactly/exa

Length of output: 1676


🏁 Script executed:

# Check if there are other scripts using similar patterns for CI detection
rg "process\.env\.CI|CI.*spawn|vitest" --type ts --type js -B2 -A2

Repository: exactly/exa

Length of output: 12848


🏁 Script executed:

# Check how the e2e script is typically invoked
find . -type f -name "package.json" -o -name "*.yml" -o -name "*.yaml" | head -20

Repository: exactly/exa

Length of output: 730


🏁 Script executed:

# Check package.json scripts
rg "e2e" package.json -A2 -B2

Repository: exactly/exa

Length of output: 2598


🏁 Script executed:

# Check workflow files for e2e.ts invocation
rg "e2e" .github/workflows/test.yaml -A3 -B3

Repository: exactly/exa

Length of output: 1475


🏁 Script executed:

# Search for how vitest watch mode is typically handled
rg "spawn.*vitest|--watch" --type ts --type js

Repository: exactly/exa

Length of output: 197


Gate watch mode to interactive environments; use run mode in CI.

Vitest's --watch mode continuously monitors files and never exits on its own. While the current HTTP shutdown mechanism works, this approach is semantically incorrect—watch mode should only be used for local development. CI environments should use vitest run for single execution. Use process.env.CI (automatically set by GitHub Actions and standard CI systems) to conditionally select the appropriate mode:

Suggested fix
-const v = spawn("vitest", ["--watch"], { stdio: ["ignore", "pipe", "pipe"], env: { ...process.env, FORCE_COLOR: "1" } });
+const v = spawn("vitest", [process.env.CI ? "run" : "--watch"], { stdio: ["ignore", "pipe", "pipe"], env: { ...process.env, FORCE_COLOR: "1" } });
🤖 Prompt for AI Agents
In `@server/script/e2e.ts` at line 14, The current spawn call starts Vitest in
persistent watch mode (const v = spawn(...)), which is inappropriate for CI;
modify the spawn invocation that creates v to choose args based on
process.env.CI so CI runs a single pass. Specifically, replace the hardcoded
["--watch"] with a conditional like: const args = process.env.CI ? ["run"] :
["--watch"]; then call spawn("vitest", args, { stdio: ["ignore","pipe","pipe"],
env: { ...process.env, FORCE_COLOR: "1" } }); keep the variable name v and
existing stdio/env options unchanged.


v.stdout.pipe(process.stdout);
v.stderr.pipe(process.stderr);
Expand Down
Loading