Skip to content

Commit

Permalink
Add lookup methods to controller pkg (#1106)
Browse files Browse the repository at this point in the history
* Add lookup methods to controller pkg

* fix warning

* use workspace
  • Loading branch information
broody authored Dec 6, 2024
1 parent 61c19c5 commit b13959d
Show file tree
Hide file tree
Showing 11 changed files with 154 additions and 97 deletions.
1 change: 1 addition & 0 deletions examples/next/.env.development
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ NEXT_PUBLIC_RPC_MAINNET="http://localhost:8001/x/starknet/mainnet"
NEXT_PUBLIC_RPC_SEPOLIA="http://localhost:8001/x/starknet/sepolia"
NEXT_PUBLIC_KEYCHAIN_FRAME_URL="http://localhost:3001"
NEXT_PUBLIC_PROFILE_FRAME_URL="http://localhost:3003"
NEXT_PUBLIC_CARTRIDGE_API_URL="http://localhost:8000"
1 change: 1 addition & 0 deletions examples/next/.env.production
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ NEXT_PUBLIC_RPC_MAINNET="https://api.cartridge.gg/x/starknet/mainnet"
NEXT_PUBLIC_RPC_SEPOLIA="https://api.cartridge.gg/x/starknet/sepolia"
NEXT_PUBLIC_KEYCHAIN_FRAME_URL="https://x.cartridge.gg"
NEXT_PUBLIC_PROFILE_FRAME_URL="https://profile.cartridge.gg"
NEXT_PUBLIC_CARTRIDGE_API_URL="https://api.cartridge.gg"
NEXT_PUBLIC_NAMESPACE="namespace"
4 changes: 2 additions & 2 deletions examples/next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
"format:check": "prettier --check ./src"
},
"dependencies": {
"@cartridge/connector": "0.5.1",
"@cartridge/controller": "0.5.1",
"@cartridge/connector": "workspace:^",
"@cartridge/controller": "workspace:^",
"@cartridge/ui-next": "workspace:^",
"@starknet-react/chains": "^0.1.3",
"@starknet-react/core": "^3.0.2",
Expand Down
4 changes: 2 additions & 2 deletions examples/next/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { DelegateAccount } from "components/DelegateAccount";
import { ColorModeToggle } from "components/ColorModeToggle";
import { Profile } from "components/Profile";
import { Settings } from "components/Settings";
import { FetchControllers } from "components/FetchControllers";
import { LookupControllers } from "components/LookupControllers";

export default function Home() {
return (
Expand All @@ -26,7 +26,7 @@ export default function Home() {
<DelegateAccount />
<InvalidTxn />
<SignMessage />
<FetchControllers />
<LookupControllers />
</div>
);
}
51 changes: 0 additions & 51 deletions examples/next/src/components/FetchControllers.tsx

This file was deleted.

59 changes: 59 additions & 0 deletions examples/next/src/components/LookupControllers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"use client";

import { useAccount } from "@starknet-react/core";
import { useCallback, useState } from "react";
import ControllerConnector from "@cartridge/connector/controller";
import { lookupAddresses, lookupUsernames } from "@cartridge/controller";
import { Button } from "@cartridge/ui-next";

export function LookupControllers() {
const { address, connector } = useAccount();
const [error, setError] = useState<Error>();
const [addressToUsername, setAddressToUsername] =
useState<Map<string, string>>();
const [usernameToAddress, setUsernameToAddress] =
useState<Map<string, string>>();
const cartridgeConnector = connector as never as ControllerConnector;

const onClick = useCallback(async () => {
if (!address) return;

setError(undefined);
try {
const username = await cartridgeConnector.username()!;
const [addressResults, usernameResults] = await Promise.all([
lookupAddresses([address]),
lookupUsernames([username]),
]);

setAddressToUsername(addressResults);
setUsernameToAddress(usernameResults);
} catch (e) {
setError(e as Error);
}
}, [address, cartridgeConnector]);

if (!address) return null;

return (
<div>
<h2>Lookup Controllers</h2>
<h3>Address to Username</h3>
{addressToUsername &&
[...addressToUsername].map(([addr, username]) => (
<p key={addr}>
{addr}: {username}
</p>
))}
<h3>Username to Address</h3>
{usernameToAddress &&
[...usernameToAddress].map(([username, addr]) => (
<p key={username}>
{username}: {addr}
</p>
))}
{error && <p className="error">{error.message}</p>}
<Button onClick={onClick}>Lookup Controllers</Button>
</div>
);
}
1 change: 1 addition & 0 deletions packages/controller/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export const KEYCHAIN_URL = "https://x.cartridge.gg";
export const PROFILE_URL = "https://profile.cartridge.gg";
export const API_URL = "https://api.cartridge.gg";
2 changes: 2 additions & 0 deletions packages/controller/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export { default } from "./controller";
export * from "./errors";
export * from "./types";
export * from "./lookup";

export { toWasmPolicies, toSessionPolicies, toArray } from "./utils";
export * from "@cartridge/presets";
68 changes: 68 additions & 0 deletions packages/controller/src/lookup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { LookupRequest, LookupResponse } from "./types";
import { num } from "starknet";
import { API_URL } from "./constants";

const cache = new Map<string, string>();

async function lookup(request: LookupRequest): Promise<LookupResponse> {
if (!request.addresses?.length && !request.usernames?.length) {
return { results: [] };
}

const response = await fetch(`${API_URL}/lookup`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(request),
});

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

return response.json();
}

export async function lookupUsernames(
usernames: string[],
): Promise<Map<string, string>> {
const uncachedUsernames = usernames.filter((name) => !cache.has(name));

if (uncachedUsernames.length > 0) {
const response = await lookup({ usernames: uncachedUsernames });

response.results.forEach((result) => {
cache.set(result.username, result.addresses[0]); // TODO: handle multiple controller addresses
});
}

return new Map(
usernames
.map((name) => [name, cache.get(name)] as [string, string])
.filter((entry): entry is [string, string] => entry[1] !== undefined),
);
}

export async function lookupAddresses(
addresses: string[],
): Promise<Map<string, string>> {
addresses = addresses.map(num.toHex);
const uncachedAddresses = addresses.filter((addr) => !cache.has(addr));

if (uncachedAddresses.length > 0) {
const response = await lookup({
addresses: uncachedAddresses,
});

response.results.forEach((result) => {
cache.set(result.addresses[0], result.username); // TODO: handle multiple controller addresses
});
}

return new Map(
addresses
.map((addr) => [addr, cache.get(addr)] as [string, string])
.filter((entry): entry is [string, string] => entry[1] !== undefined),
);
}
14 changes: 14 additions & 0 deletions packages/controller/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,20 @@ export type IFrames = {
profile?: ProfileIFrame;
};

export interface LookupRequest {
usernames?: string[];
addresses?: string[];
}

export interface LookupResult {
username: string;
addresses: string[];
}

export interface LookupResponse {
results: LookupResult[];
}

type ContractAddress = string;
type CartridgeID = string;
export type ControllerAccounts = Record<ContractAddress, CartridgeID>;
Expand Down
46 changes: 4 additions & 42 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit b13959d

Please sign in to comment.