Skip to content

Commit

Permalink
Create View for creating musig addresses in multisig-toolkit (MystenL…
Browse files Browse the repository at this point in the history
…abs#12963)

## Description 

Add a tab to the multisig-toolkit for creating Sui MultiSig Addresses
'on-the-fly' ✈️
Ref MystenLabs#12932

## Test Plan 

* Get PubKeys!
```
  AB3VXSdvFq6ym0ulqnVNuEI9xxI5b8RY21azMU6ybWp1
  ADue3nTTYz9pE75pMKEnnLIrcTSS/c0uwr6WEU5nz4RM
  AIPVXOb2rbm8dX0LBL4PEgN4HPQDpwUIHpIy2THr/it1
```

* run locally `pnpm run dev`
* goto
[localhost:5173/multisig-address](http://localhost:5173/multisig-address)
* add pubkeys and weights
* create!
---
If your changes are not user-facing and not a breaking change, you can
skip the following section. Otherwise, please indicate what changed, and
then add to the Release Notes section as highlighted during the release
process.

### Type of Change (Check all that apply)

- [ ] protocol change
- [ ] user-visible impact
- [ ] breaking change for a client SDKs
- [ ] breaking change for FNs (FN binary must upgrade)
- [ ] breaking change for validators or node operators (must upgrade
binaries)
- [ ] breaking change for on-chain data layout
- [ ] necessitate either a data wipe or data migration

### Release notes

---------

Co-authored-by: “George <george.digkas@mystenlabs.com>
  • Loading branch information
jnaulty and georgedigkas authored Jul 26, 2023
1 parent 1b4ed77 commit 3c1b69c
Show file tree
Hide file tree
Showing 3 changed files with 202 additions and 0 deletions.
1 change: 1 addition & 0 deletions dapps/multisig-toolkit/src/components/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { NavLink } from 'react-router-dom';
const links = [
{ to: '/offline-signer', label: 'Offline Signer' },
{ to: '/signature-analyzer', label: 'Signature Analyzer' },
{ to: '/multisig-address', label: 'MultiSig Address' },
];

export function Header() {
Expand Down
5 changes: 5 additions & 0 deletions dapps/multisig-toolkit/src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { createBrowserRouter, Navigate } from 'react-router-dom';
import OfflineSigner from './offline-signer';
import SignatureAnalyzer from './signature-analyzer';
import { Root } from './root';
import MultiSigAddressGenerator from './multisig-address';

export const router = createBrowserRouter([
{
Expand All @@ -23,6 +24,10 @@ export const router = createBrowserRouter([
path: 'signature-analyzer',
element: <SignatureAnalyzer />,
},
{
path: 'multisig-address',
element: <MultiSigAddressGenerator />,
},
],
},
]);
196 changes: 196 additions & 0 deletions dapps/multisig-toolkit/src/routes/multisig-address.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import { Button } from '@/components/ui/button';
import {
PubkeyWeightPair,
publicKeyFromSerialized,
SIGNATURE_FLAG_TO_SCHEME,
toB64,
toMultiSigAddress,
SignatureScheme,
fromB64,
} from '@mysten/sui.js';
import { useState } from 'react';
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '@/components/ui/card';

import { useForm, useFieldArray, FieldValues } from 'react-hook-form';

/*
Pubkeys for playing with
ABr818VXt+6PLPRoA7QnsHBfRpKJdWZPjt7ppiTl6Fkq
ANRdB4M6Hj73R+gRM4N6zUPNidLuatB9uccOzHBc/0bP
*/

export default function MultiSigAddressGenerator() {
const [msAddress, setMSAddress] = useState('');
const { register, control, handleSubmit } = useForm({
defaultValues: {
pubKeys: [{ pubKey: 'Sui Pubkey', weight: '' }],
threshold: 1,
},
});
const { fields, append, remove } = useFieldArray({
control,
name: 'pubKeys',
});

// Perform generation of multisig address
const onSubmit = (data: FieldValues) => {
console.log('data', data);

let pks: PubkeyWeightPair[] = [];
data.pubKeys.forEach((item: any) => {
console.log(item.pubKey);
const pkBytes = fromB64(item.pubKey);
const flag: number = pkBytes[0];
console.log(flag);
const rawPkBytes = toB64(pkBytes.slice(1));
const schemeFlag = (SIGNATURE_FLAG_TO_SCHEME as { [key: number]: string })[flag];
const scheme = schemeFlag as SignatureScheme;

const pk = publicKeyFromSerialized(scheme, rawPkBytes);
console.log(pk);
pks.push({ pubKey: pk, weight: item.weight });
});
console.log('pks:', pks);
const multisigSuiAddress = toMultiSigAddress(pks, data.threshold);
console.log('multisigSuiAddress', multisigSuiAddress);
setMSAddress(multisigSuiAddress);
};

// if you want to control your fields with watch
// const watchResult = watch("pubKeys");
// console.log(watchResult);

// The following is useWatch example
// console.log(useWatch({ name: "pubKeys", control }));

return (
<div className="flex flex-col gap-4">
<h2 className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl">
MultiSig Address Creator
</h2>

<form className="flex flex-col gap-4" onSubmit={handleSubmit(onSubmit)}>
<p>The following demo allow you to create Sui MultiSig addresses.</p>
<code>
Sui Pubkeys for playing with
<p>ABr818VXt+6PLPRoA7QnsHBfRpKJdWZPjt7ppiTl6Fkq</p>
<p>ANRdB4M6Hj73R+gRM4N6zUPNidLuatB9uccOzHBc/0bP</p>
</code>
<ul className="grid w-full gap-1.5">
{fields.map((item, index) => {
return (
<li key={item.id}>
<input
className="min-h-[80px] rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
{...register(`pubKeys.${index}.pubKey`, { required: true })}
/>

<input
className="min-h-[80px] rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
type="number"
{...register(`pubKeys.${index}.weight`, { required: true })}
/>

{/* <Controller
render={({ field }) => (
<input
className="min-h-[80px] rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
{...field}
/>
)}
name={`pubKeys.${index}.weight`}
control={control}
/> */}
<Button
className="min-h-[80px] rounded-md border border-input px-3 py-2 text-sm padding-2"
type="button"
onClick={() => remove(index)}
>
Delete
</Button>
</li>
);
})}
</ul>
<section>
<Button
type="button"
onClick={() => {
append({ pubKey: 'Sui Pubkey', weight: '' });
}}
>
New PubKey
</Button>
</section>
<section>
<label className="form-label min-h-[80px] rounded-md border text-sm px-3 py-2 ring-offset-background">
MultiSig Threshold Value:
</label>
<input
className="min-h-[80px] rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
type="number"
{...register(`threshold`, { valueAsNumber: true, required: true })}
/>
</section>

{/* <input
{...register('threshold', { valueAsNumber: true })}
id="threshold"
type="number"
className="form-control"
/> */}

<Button
type="submit"
onClick={() => {
console.log('fields', fields);
}}
>
Submit
</Button>
</form>
{msAddress && (
<Card key={msAddress}>
<CardHeader>
<CardTitle>Sui MultiSig Address</CardTitle>
<CardDescription>
https://docs.sui.io/testnet/learn/cryptography/sui-multisig
</CardDescription>
</CardHeader>
<CardContent>
<div className="flex flex-col gap-2">
<div className="bg-muted rounded text-sm font-mono p-2 break-all">{msAddress}</div>
</div>
</CardContent>
</Card>
)}
</div>
);
}

/*
➜ multisig-toolkit git:(jnaulty/multisig-create-address) ✗ sui keytool multi-sig-address --pks ABr818VXt+6PLPRoA7QnsHBfRpKJdWZPjt7ppiTl6Fkq ANRdB4M6Hj73R+gRM4N6zUPNidLuatB9uccOzHBc/0bP --weights 1 2 --threshold 2
MultiSig address: 0x27b17213bc702893bb3e92ba84071589a6331f35f066ad15b666b9527a288c16
Participating parties:
Sui Address | Public Key (Base64) | Weight
----------------------------------------------------------------------------------------------------
0x504f656b7bc467f6eb1d05dc26447477921f05e5ea88c5715682ad28835268ce | ABr818VXt+6PLPRoA7QnsHBfRpKJdWZPjt7ppiTl6Fkq | 1
0x611f6a023c5d1c98b4de96e9da64daffaeb372fed0176536168908e50f6e07c0 | ANRdB4M6Hj73R+gRM4N6zUPNidLuatB9uccOzHBc/0bP | 2
➜ multisig-toolkit git:(jnaulty/multisig-create-address) ✗ sui keytool multi-sig-address --pks ABr818VXt+6PLPRoA7QnsHBfRpKJdWZPjt7ppiTl6Fkq ANRdB4M6Hj73R+gRM4N6zUPNidLuatB9uccOzHBc/0bP --weights 1 1 --threshold 2
MultiSig address: 0x9134bd58a25a6b48811d1c65770dd1d01e113931ed35c13f1a3c26ed7eccf9bc
Participating parties:
Sui Address | Public Key (Base64) | Weight
----------------------------------------------------------------------------------------------------
0x504f656b7bc467f6eb1d05dc26447477921f05e5ea88c5715682ad28835268ce | ABr818VXt+6PLPRoA7QnsHBfRpKJdWZPjt7ppiTl6Fkq | 1
0x611f6a023c5d1c98b4de96e9da64daffaeb372fed0176536168908e50f6e07c0 | ANRdB4M6Hj73R+gRM4N6zUPNidLuatB9uccOzHBc/0bP | 1
➜ multisig-toolkit git:(jnaulty/multisig-create-address) ✗ sui keytool multi-sig-address --pks ABr818VXt+6PLPRoA7QnsHBfRpKJdWZPjt7ppiTl6Fkq ANRdB4M6Hj73R+gRM4N6zUPNidLuatB9uccOzHBc/0bP --weights 1 1 --threshold 1
MultiSig address: 0xda3f8c1ba647d63b89a396a64eeac835d25a59323a1b8fd4697424f62374b0de
Participating parties:
Sui Address | Public Key (Base64) | Weight
----------------------------------------------------------------------------------------------------
0x504f656b7bc467f6eb1d05dc26447477921f05e5ea88c5715682ad28835268ce | ABr818VXt+6PLPRoA7QnsHBfRpKJdWZPjt7ppiTl6Fkq | 1
0x611f6a023c5d1c98b4de96e9da64daffaeb372fed0176536168908e50f6e07c0 | ANRdB4M6Hj73R+gRM4N6zUPNidLuatB9uccOzHBc/0bP | 1
*/

0 comments on commit 3c1b69c

Please sign in to comment.