Fix TS typings, add README & CI

Fix TS typings & make example code 'work' as best as can be determined.
Add README with setup instructions.
Add basic GH Actions CI pipeline to run TS build.
This commit is contained in:
jacque006
2024-02-17 15:49:57 -07:00
parent eed49a814b
commit 26ce1d8a69
10 changed files with 107 additions and 57 deletions

19
.github/workflows/main.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: main
on:
push:
jobs:
build:
name: Build project
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: "18.x"
cache: "npm"
- run: npm ci
- run: npm run build

29
README.md Normal file
View File

@@ -0,0 +1,29 @@
# farcaster_chnage_custody
Web app implementing https://docs.farcaster.xyz/developers/guides/accounts/change-custody
## setup
### deps
[NodeJS](https://nodejs.org)
### install
```sh
npm i
```
## commands
### build
```sh
npm run build
```
### run
```sh
npm run start
```

8
package-lock.json generated
View File

@@ -10,7 +10,7 @@
"license": "MIT",
"dependencies": {
"@farcaster/core": "^0.14.0",
"viem": "^2.7.9"
"viem": "^2.7.10"
},
"devDependencies": {
"http-server": "^14.1.1",
@@ -826,9 +826,9 @@
"dev": true
},
"node_modules/viem": {
"version": "2.7.9",
"resolved": "https://registry.npmjs.org/viem/-/viem-2.7.9.tgz",
"integrity": "sha512-iDfc8TwaZFp1K95zlsxYh6Cs0OWCt35Tqs8uYgXKSxtz7w075mZ0H5SJ8zSyJGoEaticVDhtdmRRX6TtcW9EeQ==",
"version": "2.7.10",
"resolved": "https://registry.npmjs.org/viem/-/viem-2.7.10.tgz",
"integrity": "sha512-mpm/A3Rbq6hhRovOw6btkrLeDe0DlEGLoCmO2LCbH/MuTQgLNd0cWJSIov9TL/8/Pz+qC2e+bh9zohQnKA+6PQ==",
"funding": [
{
"type": "github",

View File

@@ -11,7 +11,7 @@
"license": "MIT",
"dependencies": {
"@farcaster/core": "^0.14.0",
"viem": "^2.7.9"
"viem": "^2.7.10"
},
"devDependencies": {
"http-server": "^14.1.1",

View File

@@ -1,23 +0,0 @@
import { ID_REGISTRY_EIP_712_TYPES, idRegistryABI, ID_GATEWAY_ADDRESS } from '@farcaster/core';
import { walletClient, account } from './clients';
import { readNonce, getDeadline } from './helpers';
const nonce = await readNonce();
const deadline = getDeadline();
const IdContract = {
abi: idRegistryABI,
address: ID_GATEWAY_ADDRESS,
chain: optimism
};
export const signature = await walletClient.signTypedData({
account,
...ID_REGISTRY_EIP_712_TYPES,
primaryType: 'Transfer',
message: {
fid: 1n,
to: account,
nonce,
deadline
}
});

View File

@@ -1,5 +1,4 @@
import { createWalletClient, createPublicClient, custom, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { optimism } from 'viem/chains';
export const publicClient = createPublicClient({
@@ -12,8 +11,8 @@ export const walletClient = createWalletClient({
transport: custom(window.ethereum)
});
// JSON-RPC Account
//export const [account] = await walletClient.getAddresses();
export const getAccountAddress = async () => {
const [firstAddress] = await walletClient.getAddresses();
return firstAddress;
};
// Local Account
export const account = privateKeyToAccount('0x...');

6
src/contract.ts Normal file
View File

@@ -0,0 +1,6 @@
import { ID_GATEWAY_ADDRESS, idRegistryABI } from "@farcaster/core";
export const idContract = {
abi: idRegistryABI,
address: ID_GATEWAY_ADDRESS,
};

View File

@@ -1,17 +1,19 @@
import { ID_REGISTRY_ADDRESS, idRegistryABI } from '@farcaster/core';
import { publicClient, account } from './clients';
import { Address } from 'viem';
import { publicClient } from './client';
// Returns one hour from now, in seconds
export const getDeadline = () => {
const now = Math.floor(Date.now() / 1000);
const oneHour = 60 * 60;
return now + oneHour;
return BigInt(now + oneHour);
};
export const readNonce = async () => {
return await publicClient.readContract({
export const readNonce = async (account: Address) => {
return publicClient.readContract({
address: ID_REGISTRY_ADDRESS,
abi: idRegistryABI,
functionName: 'nonce',
functionName: 'nonces',
args: [account]
});
};

View File

@@ -1,22 +1,35 @@
import { ViemWalletEip712Signer } from '@farcaster/core';
import { walletClient, account } from './clients';
import { readNonce, getDeadline } from './helpers';
import { Address, bytesToHex } from 'viem';
import { walletClient, publicClient, getAccountAddress } from './client';
import { idContract } from './contract';
import { readNonce, getDeadline } from './helper';
const nonce = await readNonce();
const deadline = getDeadline();
export const transferAccount = async (fid: bigint, to: Address) => {
// TODO fix 'any' typing, signer constrcutor expeting wallet client with netowrk prop.
const eip712Signer = new ViemWalletEip712Signer(walletClient as any);
const eip712Signer = new ViemWalletEip712Signer(walletClient);
const signature = await eip712Signer.signTransfer({
fid: 1n,
to: account,
nonce,
deadline
});
const { request: transferRequest } = await walletClient.simulateContract({
...IdContract,
functionName: 'transfer',
args: [account, deadline, signature] // to, deadline, signature
});
await walletClient.writeContract(transferRequest);
const account = await getAccountAddress();
const nonce = await readNonce(account);
const deadline = getDeadline();
const sigRes = await eip712Signer.signTransfer({
fid,
to,
nonce,
deadline
});
// See https://github.com/supermacro/neverthrow/wiki/Basic-Usage-Examples#asynchronous-api for neverthrow pattern
if (sigRes.isErr()) {
throw sigRes.error;
}
const signature = bytesToHex(sigRes.value);
const { request: transferRequest } = await publicClient.simulateContract({
...idContract,
account,
functionName: 'transfer',
args: [account, deadline, signature] // to, deadline, signature
});
await walletClient.writeContract(transferRequest);
};

5
src/window.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
import { EIP1193Provider } from "viem";
declare global {
interface Window { ethereum: EIP1193Provider; }
}