From 78f0e66a628e670e86096c2ac0cbf34908fe6d9a Mon Sep 17 00:00:00 2001 From: "joh@deep-ink.ventures" Date: Fri, 13 Oct 2023 14:05:01 +0800 Subject: [PATCH 1/6] add checkers before executing utilities/services. Update multisig interface. fix copy to clipboard preimagehash --- src/components/Settings.tsx | 55 ++++++++++++++++++-------------- src/components/Transactions.tsx | 5 ++- src/hooks/useMC.ts | 5 +++ src/types/multiCliqueAccount.ts | 5 +++ src/types/multisigTransaction.ts | 6 ++-- 5 files changed, 48 insertions(+), 28 deletions(-) diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx index 7a144bc..e94588c 100644 --- a/src/components/Settings.tsx +++ b/src/components/Settings.tsx @@ -89,19 +89,18 @@ const Settings = (props: { accountId: string }) => { return; } - await createMCTransactionDB(txn.toXDR(), jwt); + const response = await createMCTransactionDB(txn.toXDR(), jwt); - addTxnNotification({ - title: 'Success', - message: 'Add a signer transaction has been submitted', - type: TxnResponse.Success, - timestamp: Date.now(), - }); + if (response?.id != null) { + addTxnNotification({ + title: 'Success', + message: 'Add a signer transaction has been submitted', + type: TxnResponse.Success, + timestamp: Date.now(), + }); + } } catch (err) { handleErrors('Error in changing threshold', err); - useLoadingModal.setAction({ - type: 'CLOSE', - }); } finally { useLoadingModal.setAction({ type: 'CLOSE', @@ -122,18 +121,19 @@ const Settings = (props: { accountId: string }) => { if (!jwt) { return; } - await createMCTransactionDB(txn.toXDR(), jwt); - addTxnNotification({ - title: 'Success', - message: 'Add a signer transaction has been submitted', - type: TxnResponse.Success, - timestamp: Date.now(), - }); + + const response = await createMCTransactionDB(txn.toXDR(), jwt); + + if (response?.id != null) { + addTxnNotification({ + title: 'Success', + message: 'Add a signer transaction has been submitted', + type: TxnResponse.Success, + timestamp: Date.now(), + }); + } } catch (err) { handleErrors('Error in adding signer', err); - useLoadingModal.setAction({ - type: 'CLOSE', - }); } finally { useLoadingModal.setAction({ type: 'CLOSE', @@ -157,13 +157,20 @@ const Settings = (props: { accountId: string }) => { if (!jwt) { return; } - await createMCTransactionDB(txn.toXDR(), jwt); - useLoadingModal.setAction({ - type: 'CLOSE', - }); + const response = await createMCTransactionDB(txn.toXDR(), jwt); + + if (response?.id != null) { + addTxnNotification({ + title: 'Success', + message: 'Remove a signer transaction has been submitted', + type: TxnResponse.Success, + timestamp: Date.now(), + }); + } } catch (err) { handleErrors('Error in removing signer', err); + } finally { useLoadingModal.setAction({ type: 'CLOSE', }); diff --git a/src/components/Transactions.tsx b/src/components/Transactions.tsx index dacd7ff..1973f97 100644 --- a/src/components/Transactions.tsx +++ b/src/components/Transactions.tsx @@ -146,7 +146,10 @@ const Transactions = ({ address }: ITransactionsProps) => {
Call hash:
-
+
+ {item.preimageHash} +
+
{/* TODO: update hash */} {truncateMiddle(item.preimageHash, 16, 3)}
diff --git a/src/hooks/useMC.ts b/src/hooks/useMC.ts index 582e272..b334a49 100644 --- a/src/hooks/useMC.ts +++ b/src/hooks/useMC.ts @@ -618,6 +618,11 @@ const useMC = () => { }, jwtToken ); + + if (!mcTxnRes?.preimageHash) { + throw new Error('Error creating a Multiclique Transaction'); + } + const signedHash = await signBlob(mcTxnRes.preimageHash, { accountToSign: currentWalletAccount?.publicKey, }); diff --git a/src/types/multiCliqueAccount.ts b/src/types/multiCliqueAccount.ts index 4016b08..a540a98 100644 --- a/src/types/multiCliqueAccount.ts +++ b/src/types/multiCliqueAccount.ts @@ -24,3 +24,8 @@ export type MultiCliquePolicy = { name: string; active: boolean; }; + +export interface Signature { + signature: string; + signatory: Signatory; +} diff --git a/src/types/multisigTransaction.ts b/src/types/multisigTransaction.ts index f884f80..dc8c905 100644 --- a/src/types/multisigTransaction.ts +++ b/src/types/multisigTransaction.ts @@ -1,5 +1,5 @@ import type { CamelCaseObject } from '@/utils/transformer'; -import type { Signatory } from './multiCliqueAccount'; +import type { Signatory, Signature } from './multiCliqueAccount'; export enum MultiSigTransactionStatus { Pending = 'PENDING', @@ -14,8 +14,8 @@ export interface RawMultisigTransaction { preimage_hash: string; call_func: string; call_args: Record; - approvals: { signature: string; signatory: Signatory }[]; - rejections: { signature: string; signatory: Signatory }[]; + approvals?: Signature[]; + rejections?: Signature[]; status: MultiSigTransactionStatus; executed_at: string; created_at: string; From e724777c21c21e894155f0ab361cfeff7638bb27 Mon Sep 17 00:00:00 2001 From: "joh@deep-ink.ventures" Date: Fri, 13 Oct 2023 14:25:28 +0800 Subject: [PATCH 2/6] map badge to status --- src/components/Transactions.tsx | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/components/Transactions.tsx b/src/components/Transactions.tsx index 1973f97..3747980 100644 --- a/src/components/Transactions.tsx +++ b/src/components/Transactions.tsx @@ -1,11 +1,11 @@ import { - Accordion, - EmptyPlaceholder, - LoadingPlaceholder, - Pagination, - Timeline, - TransactionBadge, - UserTally, +Accordion, +EmptyPlaceholder, +LoadingPlaceholder, +Pagination, +Timeline, +TransactionBadge, +UserTally, } from '@/components'; import useCopyToClipboard from '@/hooks/useCopyToClipboard'; import { useDebounce } from '@/hooks/useDebounce'; @@ -20,7 +20,7 @@ import type { JwtToken } from '@/types/auth'; import { MultiSigTransactionStatus } from '@/types/multisigTransaction'; import { truncateMiddle } from '@/utils'; import dayjs from 'dayjs'; -import { useEffect, useState } from 'react'; +import { useEffect,useState } from 'react'; interface ITransactionsProps { address?: string; @@ -33,6 +33,13 @@ const StatusStepMap: Record = { [MultiSigTransactionStatus.Executed]: 3, }; +const StatusBadgeMap: Record = { + [MultiSigTransactionStatus.Executable]: 'Active', + [MultiSigTransactionStatus.Pending]: 'Pending', + [MultiSigTransactionStatus.Executed]: 'Approved', + [MultiSigTransactionStatus.Rejected]: 'Cancelled', +}; + const Transactions = ({ address }: ITransactionsProps) => { const [jwt] = useMCStore((s) => [s.jwt]); const { getJwtToken } = useMC(); @@ -140,7 +147,7 @@ const Transactions = ({ address }: ITransactionsProps) => { value={item.approvals?.length} over={item.signatories?.length} /> - +
From 7c7cb2a7200c65c3a0eacdeb98faf2f20e7a0a8a Mon Sep 17 00:00:00 2001 From: "joh@deep-ink.ventures" Date: Fri, 13 Oct 2023 14:27:22 +0800 Subject: [PATCH 3/6] format --- src/components/Transactions.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/Transactions.tsx b/src/components/Transactions.tsx index 3747980..094642f 100644 --- a/src/components/Transactions.tsx +++ b/src/components/Transactions.tsx @@ -1,11 +1,11 @@ import { -Accordion, -EmptyPlaceholder, -LoadingPlaceholder, -Pagination, -Timeline, -TransactionBadge, -UserTally, + Accordion, + EmptyPlaceholder, + LoadingPlaceholder, + Pagination, + Timeline, + TransactionBadge, + UserTally, } from '@/components'; import useCopyToClipboard from '@/hooks/useCopyToClipboard'; import { useDebounce } from '@/hooks/useDebounce'; @@ -20,7 +20,7 @@ import type { JwtToken } from '@/types/auth'; import { MultiSigTransactionStatus } from '@/types/multisigTransaction'; import { truncateMiddle } from '@/utils'; import dayjs from 'dayjs'; -import { useEffect,useState } from 'react'; +import { useEffect, useState } from 'react'; interface ITransactionsProps { address?: string; From 29e66ab428521054692dd052ee83083cd33f3a67 Mon Sep 17 00:00:00 2001 From: "joh@deep-ink.ventures" Date: Fri, 13 Oct 2023 19:18:51 +0800 Subject: [PATCH 4/6] fix signer payload type --- src/hooks/useMC.ts | 7 ++++--- src/services/transaction.ts | 2 +- src/utils/index.ts | 5 ++++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/hooks/useMC.ts b/src/hooks/useMC.ts index 582e272..9e00e25 100644 --- a/src/hooks/useMC.ts +++ b/src/hooks/useMC.ts @@ -16,6 +16,7 @@ import { isValidXDR, numberToU32ScVal, toBase64, + toScValBytes, } from '@/utils'; import { signBlob, signTransaction } from '@stellar/freighter-api'; import * as SorobanClient from 'soroban-client'; @@ -560,7 +561,7 @@ const useMC = () => { currentWalletAccount?.publicKey, coreAddress, 'add_signer', - accountToScVal(signerAddress) + toScValBytes(signerAddress) ); return txn; }; @@ -576,7 +577,7 @@ const useMC = () => { currentWalletAccount?.publicKey, coreAddress, 'remove_signer', - accountToScVal(signerAddress) + toScValBytes(signerAddress) ); return txn; }; @@ -631,7 +632,7 @@ const useMC = () => { name: currentWalletAccount.publicKey, address: currentWalletAccount.publicKey, }, - signature: signedHash, + signature: toBase64(signedHash), }, ], }, diff --git a/src/services/transaction.ts b/src/services/transaction.ts index eb4b3ce..e419524 100644 --- a/src/services/transaction.ts +++ b/src/services/transaction.ts @@ -130,7 +130,7 @@ export const patchMultiCliqueTransaction = async ( const body = JSON.stringify(keysToSnakeCase(payload)); const response = await fetch( - `${SERVICE_URL}/multiclique/transactions/${id}`, + `${SERVICE_URL}/multiclique/transactions/${id}/`, { method: 'PATCH', body, diff --git a/src/utils/index.ts b/src/utils/index.ts index 218335d..79e0c13 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,4 +1,4 @@ -import { DAO_UNITS, XLM_UNITS } from '@/config'; +import { DAO_UNITS,XLM_UNITS } from '@/config'; import BigNumber from 'bignumber.js'; import * as SorobanClient from 'soroban-client'; // @ts-ignore @@ -97,6 +97,9 @@ export const toBase64 = (str: string): string => { export const accountToScVal = (account: string) => new SorobanClient.Address(account).toScVal(); +export const toScValBytes = (value: string) => + SorobanClient.xdr.ScVal.scvBytes(new SorobanClient.Address(value).toBuffer()); + export const isValidXDR = (xdrString: string, networkParaphrase: string) => { try { SorobanClient.TransactionBuilder.fromXDR(xdrString, networkParaphrase); From 4677325952625cd9245638e6a64d75093f83b193 Mon Sep 17 00:00:00 2001 From: "joh@deep-ink.ventures" Date: Fri, 13 Oct 2023 19:40:25 +0800 Subject: [PATCH 5/6] fix submit threshold txn success message --- src/components/Settings.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx index e94588c..7577a21 100644 --- a/src/components/Settings.tsx +++ b/src/components/Settings.tsx @@ -94,7 +94,7 @@ const Settings = (props: { accountId: string }) => { if (response?.id != null) { addTxnNotification({ title: 'Success', - message: 'Add a signer transaction has been submitted', + message: 'Change threshold transaction has been submitted', type: TxnResponse.Success, timestamp: Date.now(), }); @@ -250,7 +250,7 @@ const Settings = (props: { accountId: string }) => { })}> { - handleChangeThreshold(data?.threshold); + handleChangeThreshold(data); }}> Date: Fri, 13 Oct 2023 20:43:33 +0800 Subject: [PATCH 6/6] fix filter and fix pagination loader --- src/components/Transactions.tsx | 134 ++++++++++++++++---------------- 1 file changed, 69 insertions(+), 65 deletions(-) diff --git a/src/components/Transactions.tsx b/src/components/Transactions.tsx index 094642f..10a179f 100644 --- a/src/components/Transactions.tsx +++ b/src/components/Transactions.tsx @@ -75,7 +75,6 @@ const Transactions = ({ address }: ITransactionsProps) => { offset: Math.max(pagination.offset - 1, 0), limit: 5, search: debouncedSearchTerm, - multicliqueAccountAddress: `${address}`, }, jwt ); @@ -128,73 +127,78 @@ const Transactions = ({ address }: ITransactionsProps) => { {!listTransactions.pending && listTransactions.fulfilled && !listTransactions.value?.results?.length && } - {listTransactions?.value?.results?.map((item, index) => { - return ( - - setActiveAccordion(activeAccordion === index ? null : index) - } - color='base' - expanded={index === activeAccordion}> - -
{item.callFunc}
-
- {dayjs(item.createdAt).format('MMMM D, YYYY - h:mm:ss A')} -
- - -
- -
-
-
Call hash:
-
- {item.preimageHash} -
-
- {/* TODO: update hash */} - {truncateMiddle(item.preimageHash, 16, 3)} + {!listTransactions.pending && + listTransactions?.value?.results?.map((item, index) => { + return ( + + setActiveAccordion(activeAccordion === index ? null : index) + } + color='base' + expanded={index === activeAccordion}> + +
{item.callFunc}
+
+ {dayjs(item.createdAt).format('MMMM D, YYYY - h:mm:ss A')} +
+ + +
+ +
+
+
Call hash:
+
+ {item.preimageHash} +
+
+ {/* TODO: update hash */} + {truncateMiddle(item.preimageHash, 16, 3)} +
+ + +
- - -
-
-
- - {['Created', 'Approved', 'Executed'].map( - (step, stepIndex) => ( - - {step} - - ) - )} - -
Can be executed once threshold is reached
-
- - - {/* TODO add execute button */} +
+ + {['Created', 'Approved', 'Executed'].map( + (step, stepIndex) => ( + + {step} + + ) + )} + +
Can be executed once threshold is reached
+
+ + + {/* TODO add execute button */} +
-
- - - ); - })} + + + ); + })}
{!listTransactions.pending && Boolean(listTransactions.value?.results?.length) && (