Skip to content

Commit

Permalink
TW-1600 Implement sending EVM transactions (raw version)
Browse files Browse the repository at this point in the history
  • Loading branch information
keshan3262 committed Dec 30, 2024
1 parent 8bb2ce2 commit 3e3a20c
Show file tree
Hide file tree
Showing 54 changed files with 1,627 additions and 999 deletions.
6 changes: 6 additions & 0 deletions public/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3796,5 +3796,11 @@
},
"disabledInTestnetMode": {
"message": "Disabled in Testnet Mode"
},
"unknownTransaction": {
"message": "Unknown Transaction"
},
"interactionWith": {
"message": "Interaction With"
}
}
60 changes: 46 additions & 14 deletions src/app/ConfirmPage/confirm-dapp-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,28 @@ import { StoredAccount, TempleAccountType, TempleDAppPayload } from 'lib/temple/
import { useBooleanState, useSafeState } from 'lib/ui/hooks';
import { delay } from 'lib/utils';
import { useCurrentAccountId } from 'temple/front';
import { TempleChainKind } from 'temple/types';

import { ConfirmPageSelectors } from './selectors';

export interface ConfirmDAppFormContentProps {
selectedAccount: StoredAccount;
error: any;
formId: string;
setCustomTitle: ReactSetStateFn<ReactNode>;
openAccountsModal: EmptyFn;
onSubmit: EmptyFn;
}

interface ConfirmDAppFormProps {
accounts: StoredAccount[];
payload: TempleDAppPayload;
onConfirm: (confirmed: boolean, selectedAccount: StoredAccount) => Promise<void>;
children: (openAccountsModal: EmptyFn, selectedAccount: StoredAccount) => ReactNode | ReactNode[];
children: (props: ConfirmDAppFormContentProps) => ReactNode | ReactNode[];
}

const CONFIRM_OPERATIONS_FORM_ID = 'confirm-operations-form';

export const ConfirmDAppForm = memo<ConfirmDAppFormProps>(({ accounts, payload, onConfirm, children }) => {
const [accountsModalIsOpen, openAccountsModal, closeAccountsModal] = useBooleanState(false);
const [bottomEdgeIsVisible, setBottomEdgeIsVisible] = useState(true);
Expand Down Expand Up @@ -82,6 +94,7 @@ export const ConfirmDAppForm = memo<ConfirmDAppFormProps>(({ accounts, payload,
}, [confirm, isConfirming, isDeclining, setIsConfirming, setIsDeclining]);

const handleErrorAlertClose = useCallback(() => setError(null), [setError]);
const [customTitle, setCustomTitle] = useSafeState<ReactNode | null>(null);

const { title, confirmButtonName, confirmTestID, declineTestID } = useMemo(() => {
switch (payload.type) {
Expand All @@ -94,24 +107,34 @@ export const ConfirmDAppForm = memo<ConfirmDAppFormProps>(({ accounts, payload,
: ConfirmPageSelectors.ConnectAction_ConnectButton,
declineTestID: ConfirmPageSelectors.ConnectAction_CancelButton
};
case 'confirm_operations':
case 'sign_typed':
case 'personal_sign':
case 'sign':
return {
title: <T id="signatureRequest" />,
confirmButtonName: <T id="signAction" />,
confirmTestID: ConfirmPageSelectors.SignAction_SignButton,
declineTestID: ConfirmPageSelectors.SignAction_RejectButton
};
default:
return {
title: <T id="confirmAction" substitutions={<T id="operations" />} />,
title:
customTitle ??
(payload.chainType === TempleChainKind.EVM ? (
<T id="unknownTransaction" />
) : (
<T id="confirmAction" substitutions={<T id="transfer" />} />
)),
confirmButtonName: <T id={error ? 'retry' : 'confirm'} />,
confirmTestID: error
? ConfirmPageSelectors.ConfirmOperationsAction_RetryButton
: ConfirmPageSelectors.ConfirmOperationsAction_ConfirmButton,
declineTestID: ConfirmPageSelectors.ConfirmOperationsAction_RejectButton
};
default:
return {
title: <T id="signatureRequest" />,
confirmButtonName: <T id="signAction" />,
confirmTestID: ConfirmPageSelectors.SignAction_SignButton,
declineTestID: ConfirmPageSelectors.SignAction_RejectButton
};
}
}, [error, payload.type]);
}, [error, payload.type, payload.chainType, customTitle]);

const isOperationsConfirm = payload.type === 'confirm_operations';

return (
<PageModal
Expand Down Expand Up @@ -160,7 +183,7 @@ export const ConfirmDAppForm = memo<ConfirmDAppFormProps>(({ accounts, payload,
</Anchor>
</div>

{error && (
{error && !isOperationsConfirm && (
<Alert
closable
onClose={handleErrorAlertClose}
Expand All @@ -171,7 +194,14 @@ export const ConfirmDAppForm = memo<ConfirmDAppFormProps>(({ accounts, payload,
/>
)}

{children(openAccountsModal, selectedAccount)}
{children({
openAccountsModal,
selectedAccount,
setCustomTitle,
formId: CONFIRM_OPERATIONS_FORM_ID,
onSubmit: handleConfirmClick,
error
})}
</ScrollView>

<ActionsButtonsBox shouldCastShadow={!bottomEdgeIsVisible} flexDirection="row">
Expand All @@ -192,7 +222,9 @@ export const ConfirmDAppForm = memo<ConfirmDAppFormProps>(({ accounts, payload,
className="w-full"
loading={isConfirming}
testID={confirmTestID}
onClick={handleConfirmClick}
type={isOperationsConfirm ? 'submit' : 'button'}
onClick={isOperationsConfirm ? undefined : handleConfirmClick}
form={isOperationsConfirm ? CONFIRM_OPERATIONS_FORM_ID : undefined}
>
{confirmButtonName}
</StyledButton>
Expand Down
52 changes: 37 additions & 15 deletions src/app/ConfirmPage/evm-confirm-dapp-form.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,38 @@
import React, { memo, useCallback, useMemo } from 'react';
import React, { memo, useCallback, useMemo, useRef, useState } from 'react';

import { CustomEvmChainIdContext } from 'lib/analytics';
import { useTempleClient } from 'lib/temple/front/client';
import { StoredAccount, TempleEvmDAppPayload } from 'lib/temple/types';
import { EvmTransactionRequestWithSender, StoredAccount, TempleEvmDAppPayload } from 'lib/temple/types';
import { getAccountForEvm, isAccountOfActableType } from 'temple/accounts';
import { useAllAccounts, useAllEvmChains } from 'temple/front';

import { ConfirmDAppForm } from './confirm-dapp-form';
import { ConfirmDAppForm, ConfirmDAppFormContentProps } from './confirm-dapp-form';
import { EvmPayloadContent } from './payload-content';

interface EvmConfirmDAppFormProps {
payload: TempleEvmDAppPayload;
id: string;
}

const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';

export const EvmConfirmDAppForm = memo<EvmConfirmDAppFormProps>(({ payload, id }) => {
const { confirmDAppPermission, confirmDAppSign } = useTempleClient();
const { confirmDAppPermission, confirmDAppSign, confirmEvmDAppOperation } = useTempleClient();

const [finalEvmTransaction, setFinalEvmTransaction] = useState<EvmTransactionRequestWithSender>(() =>
payload.type === 'confirm_operations' ? payload.req : { to: ZERO_ADDRESS, from: ZERO_ADDRESS }
);
const evmTransactionRef = useRef(finalEvmTransaction);
const updateFinalEvmTransaction = useCallback<ReactSetStateFn<EvmTransactionRequestWithSender>>(newEvmTransaction => {
setFinalEvmTransaction(newEvmTransaction);
evmTransactionRef.current =
typeof newEvmTransaction === 'function' ? newEvmTransaction(evmTransactionRef.current) : newEvmTransaction;
}, []);

const modifiedPayload = useMemo(
() => (payload.type === 'confirm_operations' ? { ...payload, req: finalEvmTransaction } : payload),
[payload, finalEvmTransaction]
);

const allAccountsStored = useAllAccounts();
const allAccounts = useMemo(
Expand All @@ -24,44 +41,49 @@ export const EvmConfirmDAppForm = memo<EvmConfirmDAppFormProps>(({ payload, id }
);

const evmChains = useAllEvmChains();
const payloadError = payload!.error;
const chainId = Number(payload.chainId);
const rpcBaseURL = evmChains[chainId].rpcBaseURL;

const network = useMemo(() => ({ chainId, rpcBaseURL }), [chainId, rpcBaseURL]);

const handleConfirm = useCallback(
async (confimed: boolean, selectedAccount: StoredAccount) => {
async (confirmed: boolean, selectedAccount: StoredAccount) => {
const accountPkh = getAccountForEvm(selectedAccount)!.address;
switch (payload.type) {
case 'connect':
return confirmDAppPermission(id, confimed, accountPkh);
return confirmDAppPermission(id, confirmed, accountPkh);

case 'personal_sign':
case 'sign_typed':
return confirmDAppSign(id, confimed);
return confirmDAppSign(id, confirmed);

case 'confirm_operations':
return confirmEvmDAppOperation(id, confirmed, evmTransactionRef.current);
}
},
[id, payload.type, confirmDAppPermission, confirmDAppSign]
[payload.type, confirmDAppPermission, id, confirmDAppSign, confirmEvmDAppOperation]
);

const renderPayload = useCallback(
(openAccountsModal: EmptyFn, selectedAccount: StoredAccount) => (
({ openAccountsModal, selectedAccount, setCustomTitle, formId, onSubmit, error }: ConfirmDAppFormContentProps) => (
<EvmPayloadContent
network={network}
error={payloadError}
modifyFeeAndLimit={undefined}
error={error}
setCustomTitle={setCustomTitle}
setFinalEvmTransaction={updateFinalEvmTransaction}
account={selectedAccount}
payload={payload}
payload={modifiedPayload}
openAccountsModal={openAccountsModal}
formId={formId}
onSubmit={onSubmit}
/>
),
[network, payload, payloadError]
[modifiedPayload, network, updateFinalEvmTransaction]
);

return (
<CustomEvmChainIdContext.Provider value={chainId}>
<ConfirmDAppForm accounts={allAccounts} payload={payload} onConfirm={handleConfirm}>
<ConfirmDAppForm accounts={allAccounts} payload={modifiedPayload} onConfirm={handleConfirm}>
{renderPayload}
</ConfirmDAppForm>
</CustomEvmChainIdContext.Provider>
Expand Down
Loading

0 comments on commit 3e3a20c

Please sign in to comment.