Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into entrykit
Browse files Browse the repository at this point in the history
  • Loading branch information
holic committed Jan 9, 2025
2 parents 0be6a43 + 7409095 commit a5665b5
Show file tree
Hide file tree
Showing 49 changed files with 1,080 additions and 503 deletions.
5 changes: 5 additions & 0 deletions .changeset/dirty-buttons-tickle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@latticexyz/entrykit": patch
---

Initial, experimental release of EntryKit.
9 changes: 9 additions & 0 deletions .changeset/seven-ducks-complain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@latticexyz/cli": patch
---

In addition to a hex `--salt`, deploy commands now accept a string salt for world deployment, which will get converted to a hex.

```
pnpm mud deploy --salt hello
```
3 changes: 3 additions & 0 deletions packages/entrykit/bin/deploy-local-prereqs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env node
// workaround for https://github.com/pnpm/pnpm/issues/1801
import "../dist/tsup/bin/deploy-local-prereqs.js";
29 changes: 21 additions & 8 deletions packages/entrykit/mprocs.deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,32 @@ scrollback: 10000
procs:
anvil:
shell: anvil --dump-state playground/anvil-state.json
deploy-factory:

deploy-csw-factory:
cwd: ../../../coinbase-smart-wallet
shell: make deploy-local
deploy-bundler:
cwd: ../../../alto
shell: pnpm ts-node scripts/localDeployer/index.ts
deploy-paymaster:
cwd: ../../../quarry-paymaster/packages/contracts
# TODO: pick or mine a nice salt for paymaster
shell: pnpm mud deploy --salt 0x && pnpm fund:paymaster:local && pnpm fund:issuer:local

deploy-prereqs:
shell: ./bin/deploy-local-prereqs.js
env:
DEBUG: "mud:*"
# Anvil default account (0x70997970C51812dc3A010C7d01b50e0d17dc79C8)
PRIVATE_KEY: "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"

# deploy-quarry-paymaster:
# cwd: ../../../quarry-paymaster/packages/contracts
# shell: pnpm mud deploy --salt 0x && pnpm fund:paymaster:local && pnpm fund:issuer:local
# env:
# DEBUG: "mud:*"

deploy-game:
cwd: ../../test/mock-game-contracts
shell: pnpm deploy:local --salt 0x
env:
DEBUG: "mud:*"
# Anvil default account (0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc)
PRIVATE_KEY: "0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba"

# deploy-bundler:
# cwd: ../../../alto
# shell: pnpm ts-node scripts/localDeployer/index.ts
22 changes: 9 additions & 13 deletions packages/entrykit/mprocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,15 @@ procs:
shell: pnpm vite dev playground
anvil:
shell: anvil --block-time 2 --load-state playground/anvil-state.json

# mud:
# cwd: ../..
# shell: pnpm run dev --filter=!@latticexyz/entrykit
bundler:
cwd: ../../../alto
shell: pnpm ts-node src --config ../mud/packages/entrykit/playground/alto.config.json
issuer:
cwd: ../../../quarry-paymaster/packages/issuer
shell: pnpm start
# explorer:
# shell: pnpm explorer
id:
cwd: ../id
shell: pnpm vite --port 5155
tunnel:
shell: cloudflared tunnel run

# quarry-issuer:
# cwd: ../../../quarry-paymaster/packages/issuer
# shell: pnpm start

# bundler:
# cwd: ../../../alto
# shell: pnpm ts-node src --config ../mud/packages/entrykit/playground/alto.config.json
19 changes: 11 additions & 8 deletions packages/entrykit/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@latticexyz/entrykit",
"version": "0.0.0",
"version": "2.2.14",
"description": "User onboarding flows for MUD apps",
"repository": {
"type": "git",
Expand All @@ -10,19 +10,22 @@
"license": "MIT",
"type": "module",
"exports": {
".": "./dist/tsup/index.js",
"./internal": "./dist/tsup/internal.js"
".": "./dist/tsup/exports/index.js",
"./internal": "./dist/tsup/exports/internal.js"
},
"typesVersions": {
"*": {
"index": [
"./dist/tsup/index.d.ts"
"./dist/tsup/exports/index.d.ts"
],
"internal": [
"./dist/tsup/internal.d.ts"
"./dist/tsup/exports/internal.d.ts"
]
}
},
"bin": {
"deploy-local-prereqs": "./bin/deploy-local-prereqs.js"
},
"files": [
"dist"
],
Expand All @@ -31,19 +34,18 @@
"build:js": "tsup",
"clean": "pnpm run clean:js",
"clean:js": "shx rm -rf dist",
"data:relay-chains": "tsx src/scripts/get-relay-chains.ts",
"dev": "tsup --watch",
"playground": "mprocs",
"playground:deploy": "mprocs --config mprocs.deploy.yaml",
"snapshot:push": "gh workflow run snapshot.yml --ref entrykit",
"snapshot:status": "gh run list --workflow snapshot.yml --limit 5",
"test": "tsc --noEmit && vitest",
"test:ci": "tsc --noEmit && vitest --run"
},
"dependencies": {
"@account-abstraction/contracts": "^0.7.0",
"@ark/util": "0.2.2",
"@latticexyz/common": "workspace:*",
"@latticexyz/config": "workspace:*",
"@latticexyz/explorer": "workspace:*",
"@latticexyz/id": "workspace:*",
"@latticexyz/paymaster": "workspace:*",
"@latticexyz/protocol-parser": "workspace:*",
Expand All @@ -55,6 +57,7 @@
"@radix-ui/react-dialog": "^1.0.5",
"@rainbow-me/rainbowkit": "2.1.7",
"debug": "^4.3.4",
"dotenv": "^16.0.3",
"permissionless": "^0.2.3",
"react-error-boundary": "^4.0.13",
"react-merge-refs": "^2.1.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/entrykit/playground/anvil-state.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion packages/entrykit/playground/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { Hex } from "viem";
import { anvil } from "viem/chains";

const testWorlds = {
[anvil.id]: "0x6Eb9682FE93c6fE4346e0a1e70bC049Aa18CC0CA",
// TODO: get this from somewhere else, like playground deploy output
[anvil.id]: "0x60e7e3caed67b9d2cca14519b6cd7700a7d4ee66",
} as Partial<Record<string, Hex>>;

const searchParams = new URLSearchParams(window.location.search);
Expand Down
20 changes: 11 additions & 9 deletions packages/entrykit/playground/wagmiConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,20 @@ const chains = [
...anvil,
rpcUrls: {
...anvil.rpcUrls,
bundler: {
http: ["http://127.0.0.1:4337"],
},
// bundler: {
// http: ["http://127.0.0.1:4337"],
// },
// TODO: automatically grant allowance in anvil instead of requiring the service
quarryPassIssuer: {
http: ["http://127.0.0.1:3003/rpc"],
},
// quarryPassIssuer: {
// http: ["http://127.0.0.1:3003/rpc"],
// },
},
contracts: {
// TODO: make optional in entrykit?
quarryPaymaster: {
address: "0x8D8b6b8414E1e3DcfD4168561b9be6bD3bF6eC4B",
// quarryPaymaster: {
// address: "0x8D8b6b8414E1e3DcfD4168561b9be6bD3bF6eC4B",
// },
paymaster: {
address: "0xf03E61E7421c43D9068Ca562882E98d1be0a6b6e",
},
},
},
Expand Down
3 changes: 2 additions & 1 deletion packages/entrykit/src/AccountModalErrorBoundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ export function AccountModalErrorBoundary({ children }: Props) {
<button
type="button"
onClick={async (event) => {
// fake pending state while we retry so that if the same error occurs,
// if we retry and the same error occurs, it'll look like the button click did nothing
// so we'll fake a pending state here to give users an indication something is happening
event.currentTarget.ariaBusy = "true";
await wait(1000);
resetErrorBoundary();
Expand Down
6 changes: 1 addition & 5 deletions packages/entrykit/src/ConnectWallet.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import { useAccount } from "wagmi";
import { Button } from "./ui/Button";
import { useAccountModal } from "./useAccountModal";
import { useConnectModal } from "@rainbow-me/rainbowkit";
import { useMutation } from "@tanstack/react-query";
import { usePasskeyConnector } from "./usePasskeyConnector";
import { AppInfo } from "./AppInfo";
import { twMerge } from "tailwind-merge";

export function ConnectWallet() {
const userAccount = useAccount();
const { accountModalOpen } = useAccountModal();
const { openConnectModal, connectModalOpen } = useConnectModal();

// TODO: show error states
// TODO: show error states?
// TODO: fix passkey issue where pending state disappears but we don't transition right away

const passkeyConnector = usePasskeyConnector();
Expand Down
8 changes: 2 additions & 6 deletions packages/entrykit/src/EntryKitConfigProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ import "@rainbow-me/rainbowkit/styles.css";
import { createContext, useContext, type ReactNode } from "react";
import { RainbowKitProvider, lightTheme, midnightTheme } from "@rainbow-me/rainbowkit";
import { EntryKitConfig } from "./config/output";
import { Address, Chain } from "viem";
import { Chain } from "viem";
import { useChains } from "wagmi";
import { getPaymasterAddress } from "./getPaymasterAddress";

type ContextValue = EntryKitConfig & {
chain: Chain;
paymasterAddress: Address;
};

/** @internal */
Expand All @@ -29,8 +27,6 @@ export function EntryKitConfigProvider({ config, children }: Props) {
const chain = chains.find(({ id }) => id === config.chainId);
if (!chain) throw new Error(`Could not find configured chain for chain ID ${config.chainId}.`);

const paymasterAddress = getPaymasterAddress(chain);

return (
<RainbowKitProvider
// Prevent RainbowKit/Wagmi trying to switch chains after connection
Expand All @@ -52,7 +48,7 @@ export function EntryKitConfigProvider({ config, children }: Props) {
}
}
>
<Context.Provider value={{ ...config, chain, paymasterAddress }}>{children}</Context.Provider>
<Context.Provider value={{ ...config, chain }}>{children}</Context.Provider>
</RainbowKitProvider>
);
}
Expand Down
135 changes: 135 additions & 0 deletions packages/entrykit/src/bin/deploy-local-prereqs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import "dotenv/config";
import {
Hex,
concatHex,
createWalletClient,
http,
isHex,
parseAbiParameters,
encodeAbiParameters,
size,
parseEther,
} from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { getRpcUrl } from "@latticexyz/common/foundry";
import {
ensureContractsDeployed,
ensureDeployer,
getContractAddress,
waitForTransactions,
} from "@latticexyz/common/internal";
import entryPointArtifact from "@account-abstraction/contracts/artifacts/EntryPoint.json" assert { type: "json" };
import simpleAccountFactoryArtifact from "@account-abstraction/contracts/artifacts/SimpleAccountFactory.json" assert { type: "json" };
import paymasterArtifact from "@latticexyz/paymaster/out/GenerousPaymaster.sol/GenerousPaymaster.json" assert { type: "json" };
import { getChainId } from "viem/actions";
import { writeContract } from "@latticexyz/common";

// TODO: parse env with arktype (to avoid zod dep) and throw when absent

const privateKey = process.env.PRIVATE_KEY;
if (!isHex(privateKey)) {
// TODO: detect anvil and automatically put this env var where it needs to go?
throw new Error(
`Missing \`PRIVATE_KEY\` environment variable. If you're using Anvil, run
echo "PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" > .env
to use a prefunded Anvil account.`,
);
}
const account = privateKeyToAccount(privateKey);

// TODO: rpc url flag/env var?
// TODO: foundry profile flag/env var?
const rpc = await getRpcUrl();

const client = createWalletClient({
transport: http(rpc),
account,
});

const chainId = await getChainId(client);

// TODO: deployer address flag/env var?
const deployerAddress = await ensureDeployer(client);

// https://github.com/eth-infinitism/account-abstraction/blob/b3bae63bd9bc0ed394dfca8668008213127adb62/hardhat.config.ts#L11
const entryPointSalt = "0x90d8084deab30c2a37c45e8d47f49f2f7965183cb6990a98943ef94940681de3";
const entryPointAddress = getContractAddress({
deployerAddress,
bytecode: entryPointArtifact.bytecode as Hex,
salt: entryPointSalt,
});
// TODO: assert that this matches Viem's entryPoint07Address

// Deploy entrypoint first, because following deploys need to be able to call it.
await ensureContractsDeployed({
client,
deployerAddress,
contracts: [
{
bytecode: entryPointArtifact.bytecode as Hex,
salt: entryPointSalt,
deployedBytecodeSize: size(entryPointArtifact.deployedBytecode as Hex),
debugLabel: "EntryPoint v0.7",
},
],
});

const paymasterBytecode = concatHex([
paymasterArtifact.bytecode.object as Hex,
encodeAbiParameters(parseAbiParameters("address"), [entryPointAddress]),
]);
const paymasterAddress = getContractAddress({ deployerAddress, bytecode: paymasterBytecode });

await ensureContractsDeployed({
client,
deployerAddress,
contracts: [
{
bytecode: concatHex([
simpleAccountFactoryArtifact.bytecode as Hex,
encodeAbiParameters(parseAbiParameters("address"), [entryPointAddress]),
]),
deployedBytecodeSize: size(simpleAccountFactoryArtifact.deployedBytecode as Hex),
debugLabel: "SimpleAccountFactory",
},
{
bytecode: paymasterBytecode,
deployedBytecodeSize: size(paymasterArtifact.deployedBytecode.object as Hex),
debugLabel: "GenerousPaymaster",
},
],
});

console.log("\nContracts deployed!\n");

if (chainId === 31337) {
const tx = await writeContract(client, {
chain: null,
address: entryPointAddress,
abi: [
{
inputs: [{ name: "account", type: "address" }],
name: "depositTo",
outputs: [],
stateMutability: "payable",
type: "function",
},
],
functionName: "depositTo",
args: [paymasterAddress],
value: parseEther("100"),
});
await waitForTransactions({ client, hashes: [tx] });
console.log("\nFunded paymaster at:", paymasterAddress, "\n");
} else {
console.log(`
Be sure to fund the paymaster by making a deposit in the entrypoint contract. For example:
cast send ${entryPointAddress} "depositTo(address)" ${paymasterAddress} --value 1ether
`);
}

console.log("\nEntryKit prerequisites complete!\n");
process.exit(0);
Loading

0 comments on commit a5665b5

Please sign in to comment.