Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/update tests #6

Closed
wants to merge 68 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
97f4eb4
feat: init commit with createAccount and state updates
k-g-j Jan 11, 2024
958ee49
feat: init commit with createAccount and state updates
k-g-j Jan 11, 2024
2cdfde5
Added [email protected] to dependencies
k-g-j Jan 11, 2024
4ebffef
Added sign transaction to unsupported methods
k-g-j Jan 12, 2024
10be421
Added initCode generation to createAccount
k-g-j Jan 12, 2024
cabd8fd
Removed unnecessary error throw and set deployed to false in createAc…
k-g-j Jan 12, 2024
995518b
Init: removed async methods and flows
k-g-j Jan 12, 2024
a6e7d77
Added method stubs for user operations
k-g-j Jan 12, 2024
53629a4
Started implementing method to prepare userOp
k-g-j Jan 12, 2024
187e6e4
Finished implementing prepareUserOp
k-g-j Jan 16, 2024
c9e90f1
Merge remote-tracking branch 'origin/feat/deploy-factories' into feat…
k-g-j Jan 16, 2024
7e62b2c
Updated implementation for preparing and signing requests and merged …
k-g-j Jan 16, 2024
174178f
Updated dummy values and added urls to env.sample
k-g-j Jan 16, 2024
fea673b
Updated paymaster url in env.sample
k-g-j Jan 16, 2024
24ac8da
Added salt to wallet state and address for paymaster to env.sample
k-g-j Jan 17, 2024
b0ca7da
feat: impl patchUserOperation
montelaidev Jan 18, 2024
1f2ab26
fix: add network-access permission
montelaidev Jan 18, 2024
32d20d9
fix: return types for prepareUserOperation
montelaidev Jan 18, 2024
70269f2
fix: SimpleAccountFactory getAddress to getAccountAddress
montelaidev Jan 18, 2024
7fbedce
fix: update keyring api on site
montelaidev Jan 18, 2024
daced3d
fix: change salt to be dynamic
montelaidev Jan 18, 2024
c719043
updated front end to import private key in create account and include…
k-g-j Jan 18, 2024
5aed321
Updated snap name on front end
k-g-j Jan 18, 2024
e3bab75
Merge remote-tracking branch 'origin/feat/update-front-end' into feat…
montelaidev Jan 19, 2024
73fb85f
feat: update hardhat config with chainId and max accounts
montelaidev Jan 19, 2024
40aa29f
fix: sign userOperation
montelaidev Jan 19, 2024
5f922ca
chore: update readme
montelaidev Jan 19, 2024
0d894b7
fix: patchUserOperation to use verifying paymaster
montelaidev Jan 19, 2024
7320685
Added compile step to build
k-g-j Jan 22, 2024
164206a
fix: remove usage of jest env
montelaidev Jan 23, 2024
9b883a4
Added salt ability to front end create account
k-g-j Jan 19, 2024
46204ea
Added ability to set chain configuration via keyring and UI
k-g-j Jan 19, 2024
481498a
Fix: wrap user op hash in bytes before signing
k-g-j Jan 19, 2024
6729cd0
Fix: updated chainIdDecimal to base 10
k-g-j Jan 19, 2024
0ad1e23
Fix: return '0x' for dummy paymaster and data
k-g-j Jan 19, 2024
0f28579
Fix: do not destructure transaction array in prepareUserOp
k-g-j Jan 19, 2024
50c3821
Updated TODOs for validation and setting if an account is deployed
k-g-j Jan 22, 2024
fa6e101
Added validation to setting the config
k-g-j Jan 22, 2024
2587ba4
Removed userOp methods from front-end
k-g-j Jan 22, 2024
4fe9247
fix: tests
montelaidev Jan 24, 2024
31b9f92
fix: verifying paymaster test
montelaidev Jan 24, 2024
b870f25
fix: lint
montelaidev Jan 24, 2024
d01e3f2
feat: add .prettierignore
montelaidev Jan 24, 2024
0a369aa
fix: remove unused variables
montelaidev Jan 24, 2024
9a62f45
fix: update env files for snap
montelaidev Jan 24, 2024
bcefc98
fix: add build step for test to create types
montelaidev Jan 24, 2024
ba50085
fix: remove @uniswap/sdk-core
montelaidev Jan 24, 2024
bce4f41
bump: metamask/providers
montelaidev Jan 24, 2024
0b83f14
fix: dynamically set networks based on env
montelaidev Jan 24, 2024
c76281c
chore: update yarn lock
montelaidev Jan 24, 2024
f209e44
chore: fix lint
montelaidev Jan 24, 2024
fca138a
fix: remove prettier for cache, coverage and artifacts
montelaidev Jan 24, 2024
194227a
fix: lint
montelaidev Jan 24, 2024
24a7573
Added salt ability to front end create account
k-g-j Jan 19, 2024
73d8c08
Added ability to set chain configuration via keyring and UI
k-g-j Jan 19, 2024
5c70fdc
Fix: wrap user op hash in bytes before signing
k-g-j Jan 19, 2024
9558528
Fix: updated chainIdDecimal to base 10
k-g-j Jan 19, 2024
3b87680
Fix: return '0x' for dummy paymaster and data
k-g-j Jan 19, 2024
8c83803
Fix: do not destructure transaction array in prepareUserOp
k-g-j Jan 19, 2024
c3aeb66
Updated TODOs for validation and setting if an account is deployed
k-g-j Jan 22, 2024
0102d64
Added validation to setting the config
k-g-j Jan 22, 2024
05c7074
Removed userOp methods from front-end
k-g-j Jan 22, 2024
fbba5f4
Updated keyring tests for init codes
k-g-j Jan 23, 2024
e2522d4
Updating tests
k-g-j Jan 24, 2024
98e89b1
Merge remote-tracking branch 'origin/feat/implement-patch-user-operat…
k-g-j Jan 24, 2024
8ccf550
Updated tests to include init code in prepare UserOp and sign UserOp
k-g-j Jan 24, 2024
4ffd780
debugging deploying account with init code
k-g-j Jan 25, 2024
c2b8fd7
Fixed bug in testing deployment of account
k-g-j Jan 26, 2024
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
1 change: 1 addition & 0 deletions .github/workflows/build-lint-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ jobs:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
- run: yarn --immutable --immutable-cache
- run: yarn build
- run: yarn test
- name: Require clean working directory
shell: bash
Expand Down
8 changes: 6 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ node_modules/
.yarn-integrity

# dotenv environment variables file
.env
packages/snap/.env
.env.test

# Stores VSCode versions used for testing VSCode extensions
Expand All @@ -80,4 +80,8 @@ node_modules/
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
!.yarn/versions

# IntelliJ
.idea/
/.idea/
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
packages/snap/artifacts
packages/snap/cache
packages/snap/coverage
18 changes: 9 additions & 9 deletions .yarn/releases/yarn-3.6.3.cjs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Simple Keyring Snap
# Simple Account Abstraction Snap

This repository contains a simple example of a keyring snap.

Expand Down
4 changes: 2 additions & 2 deletions packages/site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
"dependencies": {
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@metamask/keyring-api": "^1.0.0-rc.1",
"@metamask/providers": "^13.0.0",
"@metamask/keyring-api": "^2.0.0",
"@metamask/providers": "^14.0.2",
"@mui/icons-material": "^5.14.0",
"@mui/material": "^5.14.0",
"@types/react-helmet": "^6.1.6",
Expand Down
2 changes: 1 addition & 1 deletion packages/site/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export const Header = () => {
return (
<HeaderWrapper>
<LogoWrapper>
<Title>🔑 Snap Simple Keyring</Title>
<Title>🔑 Snap Account Abstraction Keyring</Title>
</LogoWrapper>
<RightContainer>
<Version />
Expand Down
92 changes: 38 additions & 54 deletions packages/site/src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import type { KeyringAccount, KeyringRequest } from '@metamask/keyring-api';
import { KeyringSnapRpcClient } from '@metamask/keyring-api';
import Grid from '@mui/material/Grid';
import React, { useCallback, useContext, useEffect, useState } from 'react';
import React, { useContext, useEffect, useState } from 'react';

import {
Accordion,
AccountList,
Card,
ConnectButton,
Toggle,
} from '../components';
import { Accordion, AccountList, Card, ConnectButton } from '../components';
import {
CardContainer,
Container,
Expand All @@ -18,15 +12,10 @@ import {
StyledBox,
} from '../components/styledComponents';
import { defaultSnapOrigin } from '../config';
import { MetaMaskContext, MetamaskActions } from '../hooks';
import { MetamaskActions, MetaMaskContext } from '../hooks';
import { InputType } from '../types';
import type { KeyringState } from '../utils';
import {
connectSnap,
getSnap,
isSynchronousMode,
toggleSynchronousApprovals,
} from '../utils';
import { connectSnap, getSnap, isSynchronousMode } from '../utils';

const snapId = defaultSnapOrigin;

Expand All @@ -47,11 +36,11 @@ const Index = () => {
// a component but for this case it should be ok since this is an
// internal development and testing tool.
const [privateKey, setPrivateKey] = useState<string | null>();
const [salt, setSalt] = useState<string | null>();
const [accountId, setAccountId] = useState<string | null>();
const [accountObject, setAccountObject] = useState<string | null>();
const [requestId, setRequestId] = useState<string | null>(null);
// const [accountPayload, setAccountPayload] =
// useState<Pick<KeyringAccount, 'name' | 'options'>>();

const client = new KeyringSnapRpcClient(snapId, window.ethereum);

useEffect(() => {
Expand Down Expand Up @@ -86,14 +75,9 @@ const Index = () => {
};

const createAccount = async () => {
const newAccount = await client.createAccount();
await syncAccounts();
return newAccount;
};

const importAccount = async () => {
const newAccount = await client.createAccount({
privateKey: privateKey as string,
salt: salt as string,
});
await syncAccounts();
return newAccount;
Expand Down Expand Up @@ -128,45 +112,44 @@ const Index = () => {
}
};

const handleUseSyncToggle = useCallback(async () => {
console.log('Toggling synchronous approval');
await toggleSynchronousApprovals();
setSnapState({
...snapState,
useSynchronousApprovals: !snapState.useSynchronousApprovals,
});
}, [snapState]);
// Note: not using this for now
// const handleUseSyncToggle = useCallback(async () => {
// console.log('Toggling synchronous approval');
// await toggleSynchronousApprovals();
// setSnapState({
// ...snapState,
// useSynchronousApprovals: !snapState.useSynchronousApprovals,
// });
// }, [snapState]);

const accountManagementMethods = [
{
name: 'Create account',
description: 'Create a new account',
inputs: [],
action: {
callback: async () => await createAccount(),
label: 'Create Account',
},
successMessage: 'Account created',
},
{
name: 'Import account',
description: 'Import an account using a private key',
description: 'Create a 4337 account using an admin private key',
inputs: [
{
id: 'import-account-private-key',
id: 'create-account-private-key',
title: 'Private key',
value: privateKey,
type: InputType.TextField,
placeholder:
'E.g. 0000000000000000000000000000000000000000000000000000000000000000',
onChange: (event: any) => setPrivateKey(event.currentTarget.value),
},
{
id: 'create-account-salt',
title: 'Salt (optional)',
value: salt,
type: InputType.TextField,
placeholder: 'E.g. 0x123',
onChange: (event: any) => setSalt(event.currentTarget.value),
},
],
action: {
callback: async () => await importAccount(),
label: 'Import Account',
callback: async () => await createAccount(),
label: 'Create Account',
},
successMessage: 'Account imported',
successMessage: 'Smart Contract Account Created',
},
{
name: 'Get account',
Expand Down Expand Up @@ -352,14 +335,15 @@ const Index = () => {
<StyledBox sx={{ flexGrow: 1 }}>
<Grid container spacing={4} columns={[1, 2, 3]}>
<Grid item xs={8} sm={4} md={2}>
<DividerTitle>Options</DividerTitle>
<Toggle
title="Use Synchronous Approval"
defaultChecked={snapState.useSynchronousApprovals}
onToggle={handleUseSyncToggle}
enabled={Boolean(state.installedSnap)}
/>
<Divider>&nbsp;</Divider>
{/* Not using this for now*/}
{/* <DividerTitle>Options</DividerTitle>*/}
{/* <Toggle*/}
{/* title="Use Synchronous Approval"*/}
{/* defaultChecked={snapState.useSynchronousApprovals}*/}
{/* onToggle={handleUseSyncToggle}*/}
{/* enabled={Boolean(state.installedSnap)}*/}
{/*/ >*/}
{/* <Divider>&nbsp;</Divider>*/}
<DividerTitle>Methods</DividerTitle>
<Accordion items={accountManagementMethods} />
<Divider />
Expand Down
16 changes: 9 additions & 7 deletions packages/site/src/utils/snap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,16 @@ export const toggleSynchronousApprovals = async () => {
});
};

// Note: not used in the example
export const isSynchronousMode = async (): Promise<boolean> => {
return (await window.ethereum.request({
method: 'wallet_invokeSnap',
params: {
snapId: defaultSnapOrigin,
request: { method: 'snap.internal.isSynchronousMode' },
},
})) as boolean;
// return (await window.ethereum.request({
// method: 'wallet_invokeSnap',
// params: {
// snapId: defaultSnapOrigin,
// request: { method: 'snap.internal.isSynchronousMode' },
// },
// })) as boolean;
return true;
};

export const isLocalSnap = (snapId: string) => snapId.startsWith('local:');
4 changes: 3 additions & 1 deletion packages/snap/.env.sample
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
INFURA_PROJECT_ID=YOUR_INFURA_PROJECT_ID
MNEMONIC=YOUR_MNEMONIC
MNEMONIC=YOUR_MNEMONIC
BUNDLER_URL=BUNDLER_URL
VERIFYING_PAYMASTER_ADDRESS=PAYMASTER_ADDRESS
9 changes: 8 additions & 1 deletion packages/snap/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,12 @@ module.exports = {
},
],

ignorePatterns: ['!.eslintrc.js', 'dist/'],
ignorePatterns: [
'!.eslintrc.js',
'dist/',
'contracts/',
'coverage/',
'cache/',
'artifacts/',
],
};
6 changes: 6 additions & 0 deletions packages/snap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,9 @@ can customize the wallet experience.
1. `yarn install` to install the dependencies
2. `yarn compile` to build the types for the contracts.
3. `yarn serve` to create a local instance of the snap.

# Deploying Factory Contracts

Deploying the contracts will use eth from the first account of your mnemonic.

1. `yarn hardhat --network <chain name specified in hardhat config> run scripts/deployFactory.ts`
86 changes: 51 additions & 35 deletions packages/snap/contracts/samples/SimpleAccountFactory.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;

import "@openzeppelin/contracts/utils/Create2.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import '@openzeppelin/contracts/utils/Create2.sol';
import '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol';

import "./SimpleAccount.sol";
import './SimpleAccount.sol';

/**
* A sample factory contract for SimpleAccount
Expand All @@ -13,40 +13,56 @@ import "./SimpleAccount.sol";
* This way, the entryPoint.getSenderAddress() can be called either before or after the account is created.
*/
contract SimpleAccountFactory {
SimpleAccount public immutable accountImplementation;
SimpleAccount public immutable accountImplementation;

constructor(IEntryPoint _entryPoint) {
accountImplementation = new SimpleAccount(_entryPoint);
}
constructor(IEntryPoint _entryPoint) {
accountImplementation = new SimpleAccount(_entryPoint);
}

/**
* create an account, and return its address.
* returns the address even if the account is already deployed.
* Note that during UserOperation execution, this method is called only if the account is not deployed.
* This method returns an existing account address so that entryPoint.getSenderAddress() would work even after account creation
*/
function createAccount(address owner,uint256 salt) public returns (SimpleAccount ret) {
address addr = getAddress(owner, salt);
uint codeSize = addr.code.length;
if (codeSize > 0) {
return SimpleAccount(payable(addr));
}
ret = SimpleAccount(payable(new ERC1967Proxy{salt : bytes32(salt)}(
address(accountImplementation),
abi.encodeCall(SimpleAccount.initialize, (owner))
)));
/**
* create an account, and return its address.
* returns the address even if the account is already deployed.
* Note that during UserOperation execution, this method is called only if the account is not deployed.
* This method returns an existing account address so that entryPoint.getSenderAddress() would work even after account creation
*/
function createAccount(
address owner,
uint256 salt
) public returns (SimpleAccount ret) {
address addr = getAccountAddress(owner, salt);
uint codeSize = addr.code.length;
if (codeSize > 0) {
return SimpleAccount(payable(addr));
}
ret = SimpleAccount(
payable(
new ERC1967Proxy{salt: bytes32(salt)}(
address(accountImplementation),
abi.encodeCall(SimpleAccount.initialize, (owner))
)
)
);
}

/**
* calculate the counterfactual address of this account as it would be returned by createAccount()
*/
function getAddress(address owner,uint256 salt) public view returns (address) {
return Create2.computeAddress(bytes32(salt), keccak256(abi.encodePacked(
type(ERC1967Proxy).creationCode,
abi.encode(
address(accountImplementation),
abi.encodeCall(SimpleAccount.initialize, (owner))
)
)));
}
/**
* calculate the counterfactual address of this account as it would be returned by createAccount()
*/
function getAccountAddress(
address owner,
uint256 salt
) public view returns (address) {
return
Create2.computeAddress(
bytes32(salt),
keccak256(
abi.encodePacked(
type(ERC1967Proxy).creationCode,
abi.encode(
address(accountImplementation),
abi.encodeCall(SimpleAccount.initialize, (owner))
)
)
)
);
}
}
Loading