mirror of
https://github.com/getwax/eth-global-lisbon-hackathon.git
synced 2026-01-09 15:57:55 -05:00
Merge branch 'main' of github.com:web3well/eth-global-lisbon-hackathon
This commit is contained in:
@@ -3,6 +3,8 @@ import SideBar from './components/Sidebar';
|
||||
import Propose from './routes/Propose';
|
||||
import Create from './routes/Create';
|
||||
import Sign from './routes/Sign';
|
||||
import Wallet from './routes/Wallet';
|
||||
import Debug from './routes/Debug';
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
@@ -12,6 +14,8 @@ export default function App() {
|
||||
<Route index element={<Create />} />
|
||||
<Route path="propose" element={<Propose />} />
|
||||
<Route path="sign" element={<Sign />} />
|
||||
<Route path="wallet" element={<Wallet />} />
|
||||
<Route path="debug" element={<Debug />} />
|
||||
<Route path="*" element={<NoMatch />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BigNumber, BigNumberish } from 'ethers';
|
||||
import { BigNumber, BigNumberish, ethers } from 'ethers';
|
||||
import {
|
||||
SafeProxy,
|
||||
SafeProxy__factory,
|
||||
@@ -16,6 +16,7 @@ import { Signer } from '@ethersproject/abstract-signer';
|
||||
import { BaseAccountAPI } from '@account-abstraction/sdk';
|
||||
import { BaseApiParams } from '@account-abstraction/sdk/src/BaseAccountAPI';
|
||||
import { TransactionDetailsForUserOp } from '@account-abstraction/sdk/src/TransactionDetailsForUserOp';
|
||||
import { solG1 } from '@thehubbleproject/bls/dist/mcl';
|
||||
|
||||
/**
|
||||
* constructor params, added no top of base params:
|
||||
@@ -71,8 +72,11 @@ export class AccountAPI extends BaseAccountAPI {
|
||||
);
|
||||
}
|
||||
|
||||
setNextAggBlsSignature(sig: string) {
|
||||
this.nextAggBlsSignature = sig;
|
||||
setNextAggBlsSignature(sig: solG1) {
|
||||
this.nextAggBlsSignature = ethers.utils.defaultAbiCoder.encode(
|
||||
['uint256[2]'],
|
||||
[sig],
|
||||
);
|
||||
}
|
||||
|
||||
async _getAccountContract(): Promise<SafeProxy> {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { BigNumber, ethers } from 'ethers';
|
||||
import { FormEvent } from 'react';
|
||||
import { BLSGroupVerifier__factory } from 'account-abstraction';
|
||||
import AppContext from '../AppContext';
|
||||
import createWallet from '../createWallet';
|
||||
import { solG2 } from '@thehubbleproject/bls/dist/mcl';
|
||||
|
||||
interface CreateWalletFieldProps {
|
||||
label: string;
|
||||
@@ -10,28 +11,52 @@ interface CreateWalletFieldProps {
|
||||
const SetupWalletField = ({ label, name }: CreateWalletFieldProps) => (
|
||||
<div className="mt-6 grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
|
||||
<div className="sm:col-span-4">
|
||||
<label
|
||||
htmlFor={name}
|
||||
className="block text-sm font-medium leading-6 text-white"
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
justifyItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '1rem',
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</label>
|
||||
<div className="mt-2">
|
||||
<input
|
||||
id={name}
|
||||
name={name}
|
||||
type={name}
|
||||
autoComplete={name}
|
||||
className="block w-full rounded-md border-0 bg-white/5 py-1.5 text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-2 focus:ring-inset focus:ring-indigo-500 sm:text-sm sm:leading-6"
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<label
|
||||
htmlFor={name}
|
||||
className="block text-sm font-medium leading-6 text-white"
|
||||
style={{ textAlign: 'center', justifyContent: 'center' }}
|
||||
>
|
||||
{label}
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
flexGrow: 1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<input
|
||||
id={name}
|
||||
name={name}
|
||||
type={name}
|
||||
autoComplete={name}
|
||||
className="block w-full rounded-md border-0 bg-white/5 py-1.5 text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-2 focus:ring-inset focus:ring-indigo-500 sm:text-sm sm:leading-6"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default function Page() {
|
||||
const appContext = AppContext.use();
|
||||
|
||||
const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -51,7 +76,7 @@ export default function Page() {
|
||||
'public-key-5',
|
||||
) as HTMLInputElement;
|
||||
|
||||
const pubKeys = [
|
||||
const pubKeyStrings = [
|
||||
pubKey1.value,
|
||||
pubKey2.value,
|
||||
pubKey3.value,
|
||||
@@ -65,8 +90,18 @@ export default function Page() {
|
||||
).deploy();
|
||||
await blsGroupVerifier.deployed();
|
||||
|
||||
const setupGroup = await blsGroupVerifier.setupGroup([]);
|
||||
await setupGroup.wait();
|
||||
const pubKeys = pubKeyStrings
|
||||
.filter((str) => str !== '')
|
||||
.map(
|
||||
(str) =>
|
||||
ethers.utils.defaultAbiCoder
|
||||
.decode(['uint256', 'uint256', 'uint256', 'uint256'], str)
|
||||
.map((x: BigNumber) => x.toHexString()) as solG2,
|
||||
);
|
||||
|
||||
const walletAddress = await createWallet(pubKeys);
|
||||
|
||||
location.href = `/wallet?address=${walletAddress}`;
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -74,26 +109,26 @@ export default function Page() {
|
||||
<div className="space-y-12">
|
||||
<div className="border-b border-white/10 pb-12">
|
||||
<h2 className="text-base font-semibold leading-7 text-white">
|
||||
Setup Multi-sig
|
||||
Create a Wallet
|
||||
</h2>
|
||||
<p className="mt-1 text-sm leading-6 text-gray-400">
|
||||
Setup a Multi-sig wallet with a list of addresses and a threshold
|
||||
Enter the BLS public keys that should have access to this wallet.
|
||||
</p>
|
||||
|
||||
<SetupWalletField name="public-key-1" label="Signer public key 1" />
|
||||
<SetupWalletField name="public-key-2" label="Signer public key 2" />
|
||||
<SetupWalletField name="public-key-3" label="Signer public key 3" />
|
||||
<SetupWalletField name="public-key-4" label="Signer public key 4" />
|
||||
<SetupWalletField name="public-key-5" label="Signer public key 5" />
|
||||
<SetupWalletField name="public-key-1" label="Key 1" />
|
||||
<SetupWalletField name="public-key-2" label="Key 2" />
|
||||
<SetupWalletField name="public-key-3" label="Key 3" />
|
||||
<SetupWalletField name="public-key-4" label="Key 4" />
|
||||
<SetupWalletField name="public-key-5" label="Key 5" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 flex items-center justify-end gap-x-6">
|
||||
<div className="mt-6 flex items-center gap-x-6">
|
||||
<button
|
||||
type="submit"
|
||||
className="rounded-xl bg-green-500 px-4 py-2 text-lg font-semibold text-white shadow-sm hover:bg-green-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500"
|
||||
>
|
||||
Setup Wallet
|
||||
Create
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -6,23 +6,29 @@ import {
|
||||
XMarkIcon,
|
||||
WalletIcon,
|
||||
PencilIcon,
|
||||
BugAntIcon,
|
||||
} from '@heroicons/react/24/outline';
|
||||
import PublicKey from './PublicKey';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { Link, Outlet } from 'react-router-dom';
|
||||
|
||||
const navigation = [
|
||||
{ name: 'Create Multi-sig', href: '/', icon: WalletIcon },
|
||||
{ name: 'Create', href: '/', icon: WalletIcon },
|
||||
{
|
||||
name: 'Propose Transaction',
|
||||
name: 'Propose',
|
||||
href: '/propose',
|
||||
icon: UsersIcon,
|
||||
},
|
||||
{
|
||||
name: 'Sign Transaction',
|
||||
name: 'Sign',
|
||||
href: '/sign',
|
||||
icon: PencilIcon,
|
||||
},
|
||||
{
|
||||
name: 'Debug',
|
||||
href: '/debug',
|
||||
icon: BugAntIcon,
|
||||
},
|
||||
];
|
||||
|
||||
function classNames(...classes: string[]) {
|
||||
|
||||
5
frontend/src/createWallet.ts
Normal file
5
frontend/src/createWallet.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { solG2 } from '@thehubbleproject/bls/dist/mcl';
|
||||
|
||||
export default async function createWallet(_publicKeys: solG2[]) {
|
||||
return '0x0000006789000000000000000000001234001234';
|
||||
}
|
||||
@@ -6,60 +6,9 @@ import AppContext from '../AppContext';
|
||||
import { ethers } from 'ethers';
|
||||
|
||||
export default function Create() {
|
||||
const appContext = AppContext.use();
|
||||
|
||||
return (
|
||||
<div className="home">
|
||||
<CreateWalletForm />
|
||||
<div className="flex flex-col mt-10">
|
||||
<h1 className="text-xl">OLD UI TO TEST BUNDLE</h1>
|
||||
<p>Press the fund wallet button and then the new transaction button</p>
|
||||
|
||||
<p className="mt-8">Hardhat wallet: {appContext?.hhSigner.address}</p>
|
||||
<p>
|
||||
Hardhat balance:
|
||||
{(() => {
|
||||
const hhBalance = appContext?.hhBalance;
|
||||
|
||||
if (hhBalance === undefined) {
|
||||
return '...';
|
||||
}
|
||||
|
||||
return ethers.utils.formatEther(hhBalance);
|
||||
})()}
|
||||
</p>
|
||||
<button
|
||||
onClick={() => appContext?.fundWallet()}
|
||||
className="p-2 rounded-lg bg-green-500"
|
||||
>
|
||||
Fund AA wallet
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col mt-8">
|
||||
<div>
|
||||
Smart Account Balance:{' '}
|
||||
{(() => {
|
||||
const balance = appContext?.balance;
|
||||
|
||||
if (balance === undefined) {
|
||||
return '...';
|
||||
}
|
||||
|
||||
return ethers.utils.formatEther(balance);
|
||||
})()}
|
||||
</div>
|
||||
<div>Address: {appContext?.address}</div>
|
||||
<div>
|
||||
<NewTransactionButton provider={appContext?.aaProvider} />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h2>Accounts</h2>
|
||||
<div>0x1234</div>
|
||||
<div>0x1234</div>
|
||||
<div>0x1234</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
62
frontend/src/routes/Debug.tsx
Normal file
62
frontend/src/routes/Debug.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import NewTransactionButton from '../components/NewTransactionButton';
|
||||
import AppContext from '../AppContext';
|
||||
|
||||
import { ethers } from 'ethers';
|
||||
|
||||
export default function Page() {
|
||||
const appContext = AppContext.use();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex flex-col mt-10">
|
||||
<h1 className="text-xl">OLD UI TO TEST BUNDLE</h1>
|
||||
<p>Press the fund wallet button and then the new transaction button</p>
|
||||
|
||||
<p className="mt-8">Hardhat wallet: {appContext?.hhSigner.address}</p>
|
||||
<p>
|
||||
Hardhat balance:
|
||||
{(() => {
|
||||
const hhBalance = appContext?.hhBalance;
|
||||
|
||||
if (hhBalance === undefined) {
|
||||
return '...';
|
||||
}
|
||||
|
||||
return ethers.utils.formatEther(hhBalance);
|
||||
})()}
|
||||
</p>
|
||||
<button
|
||||
onClick={() => appContext?.fundWallet()}
|
||||
className="p-2 rounded-lg bg-green-500"
|
||||
>
|
||||
Fund AA wallet
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col mt-8">
|
||||
<div>
|
||||
Smart Account Balance:{' '}
|
||||
{(() => {
|
||||
const balance = appContext?.balance;
|
||||
|
||||
if (balance === undefined) {
|
||||
return '...';
|
||||
}
|
||||
|
||||
return ethers.utils.formatEther(balance);
|
||||
})()}
|
||||
</div>
|
||||
<div>Address: {appContext?.address}</div>
|
||||
<div>
|
||||
<NewTransactionButton provider={appContext?.aaProvider} />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h2>Accounts</h2>
|
||||
<div>0x1234</div>
|
||||
<div>0x1234</div>
|
||||
<div>0x1234</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import PaymentChannel, { Payment } from '../PaymentChannel';
|
||||
import Transaction from '../components/Transaction';
|
||||
import AppContext from '../AppContext';
|
||||
import calculateSignaturesNeeded from '../utils/calculateSignaturesNeeded';
|
||||
import { IERC20__factory } from '../ERC20/IERC20__factory';
|
||||
import { AccountAPI } from '../account/AccountAPI';
|
||||
|
||||
export default function Page() {
|
||||
const appContext = AppContext.use();
|
||||
@@ -37,6 +39,23 @@ export default function Page() {
|
||||
|
||||
const addSignatureAndSend = async () => {
|
||||
await addSignature();
|
||||
|
||||
const provider = appContext?.aaProvider;
|
||||
const signer = provider?.getSigner();
|
||||
|
||||
if (!id) return;
|
||||
const channel = new PaymentChannel(id);
|
||||
const signedTx = await channel.getSignedPayment();
|
||||
|
||||
const accountApi = provider?.smartAccountAPI as AccountAPI;
|
||||
accountApi.setNextAggBlsSignature(signedTx.signature);
|
||||
|
||||
if (!payment || !signer) return;
|
||||
const ERC20 = IERC20__factory.connect(payment.token, signer);
|
||||
|
||||
const transferTx = await ERC20.transfer(payment.to, payment.amount);
|
||||
const reciept = await transferTx.wait();
|
||||
console.log('reciept', reciept);
|
||||
};
|
||||
|
||||
if (!payment)
|
||||
|
||||
3
frontend/src/routes/Wallet.tsx
Normal file
3
frontend/src/routes/Wallet.tsx
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function Page() {
|
||||
return <>Wallet page</>;
|
||||
}
|
||||
Reference in New Issue
Block a user