Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
67 changes: 67 additions & 0 deletions .github/workflows/deploy-staging-sync-service.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Deploy staging sync service

on:
workflow_dispatch:
pull_request:

jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout code
uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0

- uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2.0.2
with:
bun-version: '1.2.4'

- name: Build code
run: |
make sync-service.build


- name: Copy files to server
uses: appleboy/scp-action@917f8b81dfc1ccd331fef9e2d61bdc6c8be94634 # v0.1.7
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USERNAME }}
key: ${{ secrets.SERVER_KEY }}
port: ${{ secrets.SERVER_PORT }}
source: "apps/sync-service/build/*"
target: /home/deployer/staging_sync_service
strip_components: 2
rm: true
debug: true

- name: Deploy staging sync service to server
uses: appleboy/ssh-action@25ce8cbbcb08177468c7ff7ec5cbfa236f9341e1 # v1.1.0
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USERNAME }}
key: ${{ secrets.SERVER_KEY }}
port: ${{ secrets.SERVER_PORT }}
script_stop: true
script: |
chmod -R o+rX /home/deployer/staging_sync_service
rm -rf /tmp/staging_sync_service
mv /home/deployer/staging_sync_service /tmp
sudo -u staging_sync_service bash -c '
rm -rf /home/staging_sync_service/build
cp -r /tmp/staging_sync_service/* /home/staging_sync_service/build

cat > /home/staging_sync_service/build/.env <<-EOF
NODE_ENV=production
APP_PORT=49534
SETTINGS_DB_URL=settings.sqlite
EOF
# cf. https://github.com/appleboy/drone-ssh/issues/175
sed -i '/DRONE_SSH_PREV_COMMAND_EXIT_CODE/d' /home/staging_sync_service/build/.env
cd /home/staging_sync_service/build
bun migrate.es.js
'
rm -rf /tmp/staging_sync_service
sudo /bin/systemctl restart staging-sync.service
67 changes: 67 additions & 0 deletions .github/workflows/deploy-sync-service.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Deploy sync service

on:
workflow_dispatch:
pull_request:

jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout code
uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0

- uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2.0.2
with:
bun-version: '1.2.4'

- name: Build code
run: |
make sync-service.build


- name: Copy files to server
uses: appleboy/scp-action@917f8b81dfc1ccd331fef9e2d61bdc6c8be94634 # v0.1.7
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USERNAME }}
key: ${{ secrets.SERVER_KEY }}
port: ${{ secrets.SERVER_PORT }}
source: "apps/sync-service/build/*"
target: /home/deployer/sync_service
strip_components: 2
rm: true
debug: true

- name: Deploy sync service to server
uses: appleboy/ssh-action@25ce8cbbcb08177468c7ff7ec5cbfa236f9341e1 # v1.1.0
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USERNAME }}
key: ${{ secrets.SERVER_KEY }}
port: ${{ secrets.SERVER_PORT }}
script_stop: true
script: |
chmod -R o+rX /home/deployer/sync_service
rm -rf /tmp/sync_service
mv /home/deployer/sync_service /tmp
sudo -u sync_service bash -c '
rm -rf /home/sync_service/build
cp -r /tmp/sync_service/* /home/sync_service/build

cat > /home/sync_service/build/.env <<-EOF
NODE_ENV=production
APP_PORT=49535
SETTINGS_DB_URL=settings.sqlite
EOF
# cf. https://github.com/appleboy/drone-ssh/issues/175
sed -i '/DRONE_SSH_PREV_COMMAND_EXIT_CODE/d' /home/sync_service/build/.env
cd /home/sync_service/build
bun migrate.es.js
'
rm -rf /tmp/sync_service
sudo /bin/systemctl restart sync.service
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,10 @@ monitor-service.build: setup shared.build submitter.build
cd apps/monitor-service && make build
.PHONY: monitor-service.build

sync-service.build: setup shared.build
cd apps/sync-service && make build
.PHONY: sync-service.build

# ==================================================================================================
##@ Docs

Expand Down
5 changes: 5 additions & 0 deletions apps/iframe/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ VITE_FAUCET_ENDPOINT=https://faucet.testnet.happy.tech/faucet
# Safe to publicize, this gets bundled in the client code served by the wallet.
VITE_TURNSTILE_SITEKEY=0x4AAAAAABRnNdBbR6oFMviC

########################################################################################################################
# SYNC SERVICE

VITE_SYNC_SERVICE_URL=https://sync-staging.happy.tech

########################################################################################################################
# DEV UTILS

Expand Down
1 change: 1 addition & 0 deletions apps/iframe/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"@happy.tech/common": "workspace:*",
"@happy.tech/contracts": "workspace:0.2.0",
"@happy.tech/wallet-common": "workspace:*",
"@legendapp/state": "^3.0.0-beta.30",
"@metamask/safe-event-emitter": "^3.1.1",
"@phosphor-icons/react": "^2.1.10",
"@tanstack/react-query": "^5.56.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ enum TokenMenuActions {
}

interface RemoveTokensMenuProps {
user: Address
token: Address
}

const RemoveTokenMenu = ({ user, token }: RemoveTokensMenuProps) => {
const RemoveTokenMenu = ({ token }: RemoveTokensMenuProps) => {
return (
<Menu.Root aria-label="Asset Options Menu" lazyMount={true} unmountOnExit={true}>
<Menu.Trigger>
Expand All @@ -31,7 +30,7 @@ const RemoveTokenMenu = ({ user, token }: RemoveTokensMenuProps) => {
asChild
className="text-primary dark:text-content cursor-pointer bg-primary/20 hover:bg-primary/30 dark:bg-primary/10 dark:hover:bg-primary/20 rounded-md p-1.5"
value={TokenMenuActions.StopTracking}
onClick={() => removeWatchedAsset(user, token)}
onClick={() => removeWatchedAsset(token)}
>
<span className="text-primary/60">{TokenMenuActions.StopTracking}</span>
</Menu.Item>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { observer } from "@legendapp/state/react"
import { CoinsIcon } from "@phosphor-icons/react"
import { useAtomValue } from "jotai"
import { userAtom } from "#src/state/user"
import { watchedAssetsAtom } from "#src/state/watchedAssets"
import { getWatchedAssets } from "#src/state/watchedAssets"
import { UserNotFoundWarning } from "../UserNotFoundWarning"
import { TriggerImportTokensDialog } from "./ImportTokensDialog"
import { WatchedAsset } from "./WatchedAsset"

/**
* Displays all watched assets registered by the connected user.
*/
export const TokenView = () => {
export const TokenView = observer(() => {
const user = useAtomValue(userAtom)
const watchedAssets = useAtomValue(watchedAssetsAtom)
const userAssets = getWatchedAssets()

if (!user) return <UserNotFoundWarning />
const userAssets = watchedAssets[user.address]

return (
<ul className="flex flex-col w-full bg-content min-h-full gap-y-2">
Expand All @@ -35,4 +35,4 @@ export const TokenView = () => {
<TriggerImportTokensDialog />
</ul>
)
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export const WatchedAsset = ({ user, asset }: WatchedAssetProps) => {
</span>

<BalanceDisplay isLoading={isLoading} balance={truncatedBalance} />
<RemoveTokenMenu user={userAddress} token={tokenAddress as Address} />
<RemoveTokenMenu token={tokenAddress as Address} />
</div>
)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useCollapsible } from "@ark-ui/react"
import { Button } from "#src/components/primitives/button/Button"
import { InlineDrawer } from "#src/components/primitives/collapsible/InlineDrawer"
import { type AppPermissions, clearAppPermissions } from "#src/state/permissions"
import { clearAppPermissions } from "#src/state/permissions"
import type { AppPermissions } from "#src/state/permissions/types"
import type { AppURL } from "#src/utils/appURL"

interface ClearAllDappsPermissionsProps {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CaretRightIcon } from "@phosphor-icons/react"
import { Link } from "@tanstack/react-router"
import { useState } from "react"
import type { AppPermissions } from "#src/state/permissions"
import type { AppPermissions } from "#src/state/permissions/types"
import { getAppURL } from "#src/utils/appURL"

interface ListItemProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { Switch } from "#src/components/primitives/toggle-switch/Switch"
import { PermissionName } from "#src/constants/permissions"
import { type PermissionDescriptionIndex, permissionDescriptions } from "#src/constants/requestLabels"
import { useLocalPermissionChanges } from "#src/hooks/useLocalPermissionChanges"
import type { AppPermissions, PermissionsRequest, WalletPermission } from "#src/state/permissions"
import type { PermissionsRequest } from "#src/state/permissions/types"
import type { AppPermissions, WalletPermission } from "#src/state/permissions/types"
import type { AppURL } from "#src/utils/appURL"
import { SessionKeyCheckbox } from "./SessionKeyCheckbox"

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
import { entries } from "@happy.tech/common"
import { useAtomValue } from "jotai"
import { useAccount } from "wagmi"
import { type AppPermissions, permissionsMapAtom } from "#src/state/permissions"
import { use$ } from "@legendapp/state/react"
import { permissionsMapLegend } from "#src/state/permissions/observable"
import type { AppPermissions } from "#src/state/permissions/types"
import { type AppURL, isWallet } from "#src/utils/appURL"

export function useAppsWithPermissions(): [AppURL, AppPermissions][] {
const permissionsMap = useAtomValue(permissionsMapAtom)
const account = useAccount()
const appsWithPermissions = () => {
const permissions = permissionsMapLegend.get()
return Object.values(permissions)
.filter((permission) => !isWallet(permission.invoker))
.reduce(
(acc, permission) => {
const existing = acc.find(([app]) => app === permission.invoker)
if (existing) {
existing[1][permission.parentCapability] = permission
} else {
acc.push([
permission.invoker,
{
[permission.parentCapability]: permission,
},
])
}
return acc
},
[] as [AppURL, AppPermissions][],
)
}

// TODO: the default here should include the wallet app, but currently its empty
// adding a permission to an unrelated app will cause the wallet to _also_ be
// granted the default permissions and will then show up here
return entries(permissionsMap[account?.address ?? "0x0"] ?? {}) //
.filter(([app]) => !isWallet(app))
return use$(() => appsWithPermissions())
}
9 changes: 5 additions & 4 deletions apps/iframe/src/hooks/useCachedPermissions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useAtomValue } from "jotai"
import { useState } from "react"
import { getAppPermissions, getAppPermissionsPure, permissionsMapAtom } from "#src/state/permissions"
import type { AppPermissions } from "#src/state/permissions"
import { getAppPermissions, getAppPermissionsPure } from "#src/state/permissions"
import { permissionsMapLegend } from "#src/state/permissions/observable"
import type { AppPermissions } from "#src/state/permissions/types"
import { userAtom } from "#src/state/user"
import type { AppURL } from "#src/utils/appURL"
import { canonicalCaveatKey, mergeCaveats } from "#src/utils/caveats"
Expand All @@ -11,8 +12,8 @@ export function useCachedPermissions(appURL: AppURL): { permissions: AppPermissi
// and can be toggle back on while we don't navigate away.
const [cachedPermissions, setCachedPermissions] = useState(structuredClone(getAppPermissions(appURL)))
const user = useAtomValue(userAtom)
const permissionsMap = useAtomValue(permissionsMapAtom)
const reactivePermissions = getAppPermissionsPure(user, appURL, permissionsMap)
const permissionsMap = permissionsMapLegend.get()
const reactivePermissions = getAppPermissionsPure(user, appURL, Object.values(permissionsMap))

/**
* flag to track if any update has occurred. If se, we will set state
Expand Down
13 changes: 4 additions & 9 deletions apps/iframe/src/hooks/useHasPermissions.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
import { useAtomValue } from "jotai"
import { useMemo } from "react"
import { type PermissionsRequest, atomForPermissionsCheck } from "../state/permissions"
import { use$ } from "@legendapp/state/react"
import { hasPermissions } from "#src/state/permissions"
import type { PermissionsRequest } from "#src/state/permissions/types"
import { type AppURL, getAppURL } from "../utils/appURL"

export function useHasPermissions(permissionsRequest: PermissionsRequest, app: AppURL = getAppURL()) {
// This must be memoized to avoid an infinite render loop.
const permissionsAtom = useMemo(
() => atomForPermissionsCheck(permissionsRequest, app), //
[permissionsRequest, app],
)
return useAtomValue(permissionsAtom)
return use$(() => hasPermissions(app, permissionsRequest))
}
2 changes: 1 addition & 1 deletion apps/iframe/src/hooks/useLocalPermissionChanges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { PermissionName } from "#src/constants/permissions"
import { revokeSessionKeys } from "#src/requests/utils/sessionKeys"
import { revokedSessionKeys } from "#src/state/interfaceState"
import { grantPermissions, hasPermissions, permissionRequestEntries, revokePermissions } from "#src/state/permissions"
import type { PermissionsRequest } from "#src/state/permissions"
import type { PermissionsRequest } from "#src/state/permissions/types"
import type { AppURL } from "#src/utils/appURL"
import { mergeCaveats } from "#src/utils/caveats"
import { checkIfCaveatsMatch } from "#src/utils/checkIfCaveatsMatch"
Expand Down
4 changes: 2 additions & 2 deletions apps/iframe/src/listeners/atoms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Msgs } from "@happy.tech/wallet-common"
import { getDefaultStore } from "jotai/vanilla"
import { http, createPublicClient } from "viem"
import { mainnet } from "viem/chains"
import { permissionsMapAtom } from "#src/state/permissions"
import { permissionsMapLegend } from "#src/state/permissions/observable"
import { appMessageBus } from "../services/eventBus"
import { authStateAtom } from "../state/authState"
import { userAtom } from "../state/user"
Expand Down Expand Up @@ -64,7 +64,7 @@ if (store.get(userAtom)) emitUserUpdate(store.get(userAtom))
* @emits {@link Msgs.UserChanged} (optional)
* @emits {@link Msgs.ProviderEvent} (optional)
*/
store.sub(permissionsMapAtom, () => {
permissionsMapLegend.onChange(() => {
emitUserUpdate(store.get(userAtom))
})

Expand Down
2 changes: 1 addition & 1 deletion apps/iframe/src/requests/handlers/approved.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export async function dispatchApprovedRequest(request: PopupMsgs[Msgs.PopupAppro

case "wallet_watchAsset": {
const params = checkedWatchedAsset(request.payload.params)
return addWatchedAsset(user.address, params)
return addWatchedAsset(params)
}

case HappyMethodNames.LOAD_ABI: {
Expand Down
2 changes: 1 addition & 1 deletion apps/iframe/src/requests/handlers/injected.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ export async function dispatchInjectedRequest(request: ProviderMsgsFromApp[Msgs.
case "wallet_watchAsset": {
checkUser(user)
const params = checkedWatchedAsset(request.payload.params)
return addWatchedAsset(user.address, params)
return addWatchedAsset(params)
}

case HappyMethodNames.LOAD_ABI: {
Expand Down
Loading