Skip to content

Commit

Permalink
Merge branch 'main' into joel.composite-primary-keys
Browse files Browse the repository at this point in the history
  • Loading branch information
Joel Gustafson committed Jan 22, 2025
2 parents dc19d42 + 104b940 commit 731beed
Show file tree
Hide file tree
Showing 14 changed files with 969 additions and 40 deletions.
1 change: 1 addition & 0 deletions examples/chat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@canvas-js/interfaces": "0.14.0-next.0",
"@canvas-js/modeldb-sqlite-wasm": "0.14.0-next.0",
"@cosmjs/encoding": "^0.32.3",
"@farcaster/auth-kit": "^0.6.0",
"@keplr-wallet/types": "^0.11.64",
"@libp2p/interface": "^2.2.1",
"@magic-ext/auth": "^4.3.2",
Expand Down
67 changes: 45 additions & 22 deletions examples/chat/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useRef, useState } from "react"

import type { SessionSigner } from "@canvas-js/interfaces"
import { SIWESigner } from "@canvas-js/chain-ethereum"
import { SIWESigner, SIWFSigner, Eip712Signer } from "@canvas-js/chain-ethereum"
import { ATPSigner } from "@canvas-js/chain-atp"
import { CosmosSigner } from "@canvas-js/chain-cosmos"
import { SubstrateSigner } from "@canvas-js/chain-substrate"
Expand All @@ -11,6 +11,9 @@ import type { Contract } from "@canvas-js/core"

import { useCanvas } from "@canvas-js/hooks"

import { AuthKitProvider } from "@farcaster/auth-kit"
import { JsonRpcProvider } from "ethers"

import { AppContext } from "./AppContext.js"
import { Messages } from "./Chat.js"
import { MessageComposer } from "./MessageComposer.js"
Expand All @@ -21,11 +24,21 @@ import { Connect } from "./connect/index.js"
import { LogStatus } from "./LogStatus.js"
import { contract } from "./contract.js"

const topic = "chat-example.canvas.xyz"
export const topic = "chat-example.canvas.xyz"

const wsURL = import.meta.env.VITE_CANVAS_WS_URL ?? null
console.log("websocket API URL:", wsURL)

const config = {
// For a production app, replace this with an Optimism Mainnet
// RPC URL from a provider like Alchemy or Infura.
relay: "https://relay.farcaster.xyz",
rpcUrl: "https://mainnet.optimism.io",
domain: "chat-example.canvas.xyz",
siweUri: "https://chat-example.canvas.xyz",
provider: new JsonRpcProvider(undefined, 10),
}

export const App: React.FC<{}> = ({}) => {
const [sessionSigner, setSessionSigner] = useState<SessionSigner | null>(null)
const [address, setAddress] = useState<string | null>(null)
Expand All @@ -35,32 +48,42 @@ export const App: React.FC<{}> = ({}) => {
const { app } = useCanvas(wsURL, {
topic: topicRef.current,
contract: contract,
signers: [new SIWESigner(), new ATPSigner(), new CosmosSigner(), new SubstrateSigner({}), new SolanaSigner()],
signers: [
new SIWESigner(),
new Eip712Signer(),
new SIWFSigner(),
new ATPSigner(),
new CosmosSigner(),
new SubstrateSigner({}),
new SolanaSigner(),
],
})

return (
<AppContext.Provider value={{ address, setAddress, sessionSigner, setSessionSigner, app: app ?? null }}>
{app ? (
<main>
<div className="flex flex-row gap-4 h-full">
<div className="min-w-[480px] flex-1 flex flex-col justify-stretch gap-2">
<div className="flex-1 border rounded px-2 overflow-y-scroll">
<Messages address={address} />
<AuthKitProvider config={config}>
{app ? (
<main>
<div className="flex flex-row gap-4 h-full">
<div className="min-w-[480px] flex-1 flex flex-col justify-stretch gap-2">
<div className="flex-1 border rounded px-2 overflow-y-scroll">
<Messages address={address} />
</div>
<MessageComposer />
</div>
<div className="flex flex-col gap-4 w-[480px] break-all">
<Connect />
<SessionStatus />
<ConnectionStatus topic={topicRef.current} />
<LogStatus />
<ControlPanel />
</div>
<MessageComposer />
</div>
<div className="flex flex-col gap-4 w-[480px] break-all">
<Connect />
<SessionStatus />
<ConnectionStatus topic={topicRef.current} />
<LogStatus />
<ControlPanel />
</div>
</div>
</main>
) : (
<div className="text-center my-20">Connecting to {wsURL}...</div>
)}
</main>
) : (
<div className="text-center my-20">Connecting to {wsURL}...</div>
)}
</AuthKitProvider>
</AppContext.Provider>
)
}
106 changes: 106 additions & 0 deletions examples/chat/src/connect/ConnectSIWF.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import "@farcaster/auth-kit/styles.css"

import React, { useContext, useEffect, useRef, useState } from "react"
import { hexlify, getBytes } from "ethers"
import { SIWFSigner } from "@canvas-js/chain-ethereum"
import { ed25519 } from "@canvas-js/signatures"
import { SignInButton, useProfile } from "@farcaster/auth-kit"

import { topic } from "../App.js"
import { AppContext } from "../AppContext.js"

export interface ConnectSIWFProps {}

export const ConnectSIWF: React.FC<ConnectSIWFProps> = ({}) => {
const { app, setSessionSigner, setAddress } = useContext(AppContext)

const profile = useProfile()
const {
isAuthenticated,
profile: { fid, displayName, custody, verifications },
} = profile

const [error, setError] = useState<Error | null>(null)
const [requestId, setRequestId] = useState<string | null>(null)
const [privateKey, setPrivateKey] = useState<string | null>(null)

const initialRef = useRef(false)
useEffect(() => {
if (initialRef.current) {
return
}

initialRef.current = true

const { requestId, privateKey } = SIWFSigner.newSIWFRequestId(topic)
setRequestId(requestId)
setPrivateKey(hexlify(privateKey))
}, [])

if (error !== null) {
return (
<div className="p-2 border rounded bg-red-100 text-sm">
<code>{error.message}</code>
</div>
)
} else if (!privateKey || !requestId || !app) {
return (
<div className="p-2 border rounded bg-gray-200">
<button disabled>Loading...</button>
</div>
)
} else {
return (
<div style={{ marginTop: "12px", right: "12px" }}>
{isAuthenticated && (
<div>
<p>
Hello, {displayName}! Your FID is {fid}.
</p>
<p>Your custody address is: </p>
<pre>{custody}</pre>
<p>Your connected signers: </p>
{verifications?.map((v, i) => <pre key={i}>{v}</pre>)}
</div>
)}
<SignInButton
requestId={requestId}
onSuccess={async (result) => {
const { signature, message } = result
if (!message || !signature) {
setError(new Error("login succeeded but did not return a valid SIWF message"))
return
}

const { authorizationData, topic, custodyAddress } = SIWFSigner.parseSIWFMessage(message, signature)
const signer = new SIWFSigner({ custodyAddress, privateKey: privateKey.slice(2) })
const address = await signer.getDid()

const timestamp = new Date(authorizationData.siweIssuedAt).valueOf()
const { payload, signer: delegateSigner } = await signer.newSIWFSession(
topic,
authorizationData,
timestamp,
getBytes(privateKey),
)
setAddress(address)
setSessionSigner(signer)
app.updateSigners([
signer,
...app.signers.getAll().filter((signer) => signer.key !== "chain-ethereum-farcaster"),
])
app.messageLog.append(payload, { signer: delegateSigner })
console.log("started SIWF chat session", authorizationData)
}}
onError={(...args) => {
console.log("received SIWF error", args)
}}
onSignOut={(...args) => {
setAddress(null)
setSessionSigner(null)
}}
/>
</div>
)
}
}
6 changes: 5 additions & 1 deletion examples/chat/src/connect/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useState } from "react"

import { ConnectSIWEBurner } from "./ConnectSIWEBurner.js"
import { ConnectSIWE } from "./ConnectSIWE.js"
import { ConnectSIWF } from "./ConnectSIWF.js"
import { ConnectSIWEViem } from "./ConnectSIWEViem.js"
import { ConnectEIP712Burner } from "./ConnectEIP712Burner.js"
import { ConnectEIP712 } from "./ConnectEIP712.js"
Expand All @@ -27,6 +28,7 @@ export const Connect: React.FC<{}> = ({}) => {
>
<option value="burner">Burner Wallet</option>
<option value="burner-eip712">Burner Wallet - EIP712</option>
<option value="farcaster">Sign in with Farcaster</option>
<option value="ethereum">Ethereum</option>
<option value="ethereum-viem">Ethereum (Viem)</option>
<option value="ethereum-eip712">Ethereum (EIP712)</option>
Expand All @@ -37,7 +39,7 @@ export const Connect: React.FC<{}> = ({}) => {
{/* <option value="near">NEAR</option> */}
<option value="terra">Terra</option>
<option value="cosmos-evm">Cosmos/EVM</option>
<option value="bluesky">BlueSky</option>
<option value="bluesky">Bluesky</option>
<option value="leap">Leap</option>
<option value="magic">Magic</option>
</select>
Expand All @@ -48,6 +50,8 @@ export const Connect: React.FC<{}> = ({}) => {

const Method: React.FC<{ method: string }> = (props) => {
switch (props.method) {
case "farcaster":
return <ConnectSIWF />
case "burner":
return <ConnectSIWEBurner />
case "burner-eip712":
Expand Down
Loading

0 comments on commit 731beed

Please sign in to comment.