Skip to content

Commit

Permalink
🚧
Browse files Browse the repository at this point in the history
  • Loading branch information
cruzdanilo committed Jul 5, 2024
1 parent 7ce52ce commit 7698bd5
Show file tree
Hide file tree
Showing 13 changed files with 194 additions and 19 deletions.
Binary file modified bun.lockb
Binary file not shown.
15 changes: 12 additions & 3 deletions common/constants.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
export const rpId =
process.env.EXPO_PUBLIC_URL ??
/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion -- prevents typescript-eslint issues */

export const rpId = (process.env.EXPO_PUBLIC_URL ??
(process.env.VERCEL_ENV === "production"
? process.env.VERCEL_PROJECT_PRODUCTION_URL
: process.env.VERCEL_BRANCH_URL) ??
"localhost";
"localhost") as string;

export { optimismSepolia as chain } from "@alchemy/aa-core";

if (!process.env.EXPO_PUBLIC_ALCHEMY_API_KEY) throw new Error("missing alchemy api key");
if (!process.env.EXPO_PUBLIC_ALCHEMY_GAS_POLICY_ID) throw new Error("missing alchemy gas policy");

export const alchemyAPIKey = process.env.EXPO_PUBLIC_ALCHEMY_API_KEY as string;
export const alchemyGasPolicyId = process.env.EXPO_PUBLIC_ALCHEMY_GAS_POLICY_ID as string;

/* eslint-enable @typescript-eslint/no-unnecessary-type-assertion */
2 changes: 1 addition & 1 deletion common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"dependencies": {
"@alchemy/aa-core": "^3.18.2",
"valibot": "^0.35.0",
"valibot": "^0.36.0",
"viem": "^2.17.1"
}
}
1 change: 1 addition & 0 deletions contracts/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ deny_warnings = true
verbosity = 3
isolate = true
libs = ["lib", "../node_modules"]
fs_permissions = [{ access = "read", path = "../node_modules" }]

[fmt]
tab_width = 2
Expand Down
33 changes: 33 additions & 0 deletions contracts/script/Base.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;

import { Script, stdJson } from "forge-std/Script.sol";
import { StdAssertions } from "forge-std/StdAssertions.sol";
import { Vm } from "forge-std/Vm.sol"; // solhint-disable-line no-unused-import

abstract contract BaseScript is Script, StdAssertions {
using stdJson for string;

function protocol(string memory name) internal returns (address addr) {
addr = vm.readFile(string.concat("../../node_modules/@exactly/protocol/deployments/", chain(), "/", name, ".json"))
.readAddress(".address");
vm.label(addr, name);

address impl =
address(uint160(uint256(vm.load(addr, bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1)))));
if (impl != address(0)) {
vm.label(impl, string.concat(name, "_Impl"));
} else if (bytes10(addr.code) == 0x363d3d373d3d3d363d73) {
vm.label(address(uint160(uint240(bytes30(addr.code)))), string.concat(name, "_Impl"));
}
}

function chain() internal returns (string memory) {
if (block.chainid == 11_155_420) return "op-sepolia";
return getChain(block.chainid).chainAlias;
}
}

interface IProxy {
function implementation() external returns (address);
}
47 changes: 47 additions & 0 deletions contracts/script/Deploy.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.0;

import { LibString } from "solady/utils/LibString.sol";

import { ACCOUNT_IMPL, ENTRYPOINT } from "webauthn-owner-plugin/../script/Deploy.s.sol";
import { WebauthnOwnerPlugin } from "webauthn-owner-plugin/WebauthnOwnerPlugin.sol";

import { ExaAccountFactory } from "../src/ExaAccountFactory.sol";
import { ExaPlugin, IAuditor } from "../src/ExaPlugin.sol";

import { BaseScript, stdJson, Vm } from "./Base.s.sol";

contract DeployScript is BaseScript {
using LibString for uint256;
using stdJson for string;

ExaAccountFactory public factory;
ExaPlugin public exaPlugin;
WebauthnOwnerPlugin public ownerPlugin;
IAuditor public auditor;

function setUp() external {
Vm.DirEntry[] memory broadcasts = vm.readDir(
string.concat("../../node_modules/webauthn-owner-plugin/broadcast/Deploy.s.sol/", block.chainid.toString())
);
ownerPlugin = WebauthnOwnerPlugin(
payable(vm.readFile(broadcasts[broadcasts.length - 1].path).readAddress(".transactions[0].contractAddress"))
);
auditor = IAuditor(protocol("Auditor"));
}

function run() external {
assert(msg.sender != DEFAULT_SENDER);

vm.startBroadcast(msg.sender);

exaPlugin = new ExaPlugin(auditor, msg.sender);
factory = new ExaAccountFactory(msg.sender, ownerPlugin, exaPlugin, ACCOUNT_IMPL, ENTRYPOINT);

factory.addStake{ value: 0.1 ether }(1 days, 0.1 ether);

exaPlugin.grantRole(exaPlugin.KEEPER_ROLE(), msg.sender);

vm.stopBroadcast();
}
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"@simplewebauthn/browser": "^10.0.0",
"@tamagui/config": "^1.101.7",
"@tanstack/react-form": "^0.25.2",
"@tanstack/react-query": "^5.49.2",
"@tanstack/react-query": "^5.50.1",
"@tanstack/zod-form-adapter": "^0.25.2",
"abitype": "^1.0.5",
"expo": "~51.0.18",
Expand All @@ -63,7 +63,7 @@
"react-native": "0.74.3",
"react-native-gesture-handler": "~2.16.2",
"react-native-onesignal": "^5.2.2",
"react-native-quick-crypto": "^0.7.0",
"react-native-quick-crypto": "^0.7.1",
"react-native-safe-area-context": "4.10.1",
"react-native-screens": "~3.31.1",
"react-native-web": "^0.19.12",
Expand Down
77 changes: 77 additions & 0 deletions server/api/event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import type { VercelRequest, VercelResponse } from "@vercel/node";
import * as v from "valibot";

// import client from "../utils/chainClient.js";

export default function handler({ method, body, headers }: VercelRequest, response: VercelResponse) {
if (method !== "POST") return response.status(405).end("method not allowed");

const payload = v.safeParse(Payload, body || placeholderPayload);
console.dir(payload, { depth: null }); // eslint-disable-line no-console, unicorn/no-null
if (!payload.success) return response.status(400).json(payload); // HACK for debugging

// const { amount } = payload.output.data;

// console.log(await client.simulateContract({}));

return response.json({ response_code: "69" });
}

const Payload = v.variant("event_type", [
v.object({
event_type: v.literal("AUTHORIZATION"),
status: v.literal("PENDING"),
product: v.literal("CARDS"),
operation_id: v.string(),
data: v.object({
card_id: v.string(),
amount: v.number(),
currency_number: v.literal(840),
currency_code: v.literal("USD"),
exchange_rate: v.null(),
channel: v.picklist(["ECOMMERCE", "POS", "ATM", "Visa Direct"]),
created_at: v.pipe(v.string(), v.isoTimestamp()),
fees: v.object({ atm_fees: v.number(), fx_fees: v.number() }),
merchant_data: v.object({
id: v.string(),
name: v.string(),
city: v.string(),
post_code: v.nullable(v.string()),
state: v.nullable(v.string()),
country: v.string(),
mcc_category: v.string(),
mcc_code: v.string(),
}),
}),
}),
]);
type Payload = v.InferOutput<typeof Payload>; // eslint-disable-line @typescript-eslint/no-redeclare

/* eslint-disable unicorn/no-null */
const placeholderPayload = {
event_type: "AUTHORIZATION",
status: "PENDING",
product: "CARDS",
operation_id: "1b013f33-15e6-4073-9699-7b63c1146b1d",
data: {
card_id: "111fdf0f-9521-403e-a53d-874319243df1",
amount: 0.1,
currency_number: 840,
currency_code: "USD",
exchange_rate: null,
channel: "ECOMMERCE",
created_at: "2024-07-05T19:03:13.485Z",
fees: { atm_fees: 0, fx_fees: 0 },
merchant_data: {
id: "311178830000",
name: "Reap",
city: "www.reap.global",
post_code: null,
state: null,
country: "HK",
mcc_category: "Electronics Stores",
mcc_code: "5732",
},
},
};
/* eslint-enable unicorn/no-null */
6 changes: 3 additions & 3 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@
"dependencies": {
"@exactly/common": "workspace:*",
"@onesignal/node-onesignal": "^5.0.0-alpha-01",
"@sentry/node": "^8.14.0",
"@sentry/node": "^8.15.0",
"@simplewebauthn/server": "^10.0.0",
"@simplewebauthn/types": "^10.0.0",
"@vercel/kv": "^2.0.0",
"@vercel/node": "^3.2.1",
"@vercel/postgres": "^0.9.0",
"drizzle-orm": "^0.31.2",
"jose": "^5.6.3",
"valibot": "^0.35.0",
"valibot": "^0.36.0",
"viem": "^2.17.1",
"zod": "^3.23.8"
},
"devDependencies": {
"@types/node": "^20.14.9",
"@types/node": "^20.14.10",
"drizzle-kit": "^0.22.8",
"typescript": "^5.4.5",
"vercel": "^34.3.0"
Expand Down
15 changes: 15 additions & 0 deletions server/utils/chainClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { alchemyAPIKey, chain } from "@exactly/common/constants.js";
import { Hash } from "@exactly/common/types.js";
import { parse } from "valibot";
import { createClient, http, publicActions, walletActions } from "viem";
import { privateKeyToAccount } from "viem/accounts";

if (!chain.rpcUrls.alchemy?.http[0]) throw new Error("missing alchemy rpc url");

export default createClient({
chain,
account: privateKeyToAccount(parse(Hash, process.env.PRIVATE_KEY, { message: "invalid private key" })),
transport: http(`${chain.rpcUrls.alchemy.http[0]}/${alchemyAPIKey}`),
})
.extend(publicActions)
.extend(walletActions);
3 changes: 1 addition & 2 deletions src/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@ import React, { useEffect } from "react";
import { TamaguiProvider } from "tamagui";
import { WagmiProvider, createConfig, createStorage, custom } from "wagmi";

import { chain } from "@exactly/common/constants";
import { alchemyAPIKey, chain } from "@exactly/common/constants";

import metadata from "../../package.json";
import tamaguiConfig from "../../tamagui.config";
import { alchemyAPIKey } from "../constants";
import alchemyConnector from "../utils/alchemyConnector";
import handleError from "../utils/handleError";
import useOneSignal from "../utils/useOneSignal";
Expand Down
5 changes: 0 additions & 5 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import { rpId } from "@exactly/common/constants";

if (!process.env.EXPO_PUBLIC_ALCHEMY_API_KEY) throw new Error("missing alchemy api key");
if (!process.env.EXPO_PUBLIC_ALCHEMY_GAS_POLICY_ID) throw new Error("missing alchemy gas policy");

export const apiURL = rpId === "localhost" ? "http://localhost:3000/api" : `https://${rpId}/api`;
export const alchemyAPIKey = process.env.EXPO_PUBLIC_ALCHEMY_API_KEY;
export const alchemyGasPolicyId = process.env.EXPO_PUBLIC_ALCHEMY_GAS_POLICY_ID;
export const oneSignalAppId = process.env.EXPO_PUBLIC_ONE_SIGNAL_APP_ID;
5 changes: 2 additions & 3 deletions src/utils/alchemyConnector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,14 @@ import {
maxUint256,
} from "viem";
import { ChainNotConfiguredError, createConnector } from "wagmi";
import deployments from "webauthn-owner-plugin/broadcast/Deploy.s.sol/11155420/run-1716346701.json";
import deployments from "webauthn-owner-plugin/broadcast/Deploy.s.sol/11155420/run-1720127816.json";

import { chain, rpId } from "@exactly/common/constants";
import { alchemyGasPolicyId, chain, rpId } from "@exactly/common/constants";
import type { Passkey } from "@exactly/common/types";

import createPasskey from "./createPasskey";
import handleError from "./handleError";
import loadPasskey from "./loadPasskey";
import { alchemyGasPolicyId } from "../constants";

alchemyConnector.type = "alchemy" as const;
export default function alchemyConnector(publicClient: ClientWithAlchemyMethods) {
Expand Down

0 comments on commit 7698bd5

Please sign in to comment.