mirror of
https://github.com/status-im/safe-react.git
synced 2025-01-13 03:24:09 +00:00
add processTransaction action
This commit is contained in:
parent
d16f79f289
commit
87c41e4d78
@ -61,13 +61,27 @@ export const executeTransaction = async (
|
||||
operation: Operation,
|
||||
nonce: string | number,
|
||||
sender: string,
|
||||
signatures?: string,
|
||||
) => {
|
||||
console.log({
|
||||
to,
|
||||
valueInWei,
|
||||
data,
|
||||
operation,
|
||||
nonce,
|
||||
sender,
|
||||
signatures,
|
||||
})
|
||||
try {
|
||||
let sigs = signatures
|
||||
|
||||
// https://gnosis-safe.readthedocs.io/en/latest/contracts/signatures.html#pre-validated-signatures
|
||||
const sigs = `0x000000000000000000000000${sender.replace(
|
||||
'0x',
|
||||
'',
|
||||
)}000000000000000000000000000000000000000000000000000000000000000001`
|
||||
if (!sigs) {
|
||||
sigs = `0x000000000000000000000000${sender.replace(
|
||||
'0x',
|
||||
'',
|
||||
)}000000000000000000000000000000000000000000000000000000000000000001`
|
||||
}
|
||||
|
||||
const receipt = await safeInstance.execTransaction(
|
||||
to,
|
||||
|
@ -34,6 +34,7 @@ type Props = SelectorProps & {
|
||||
granted: boolean,
|
||||
updateSafe: Function,
|
||||
createTransaction: Function,
|
||||
processTransaction: Function,
|
||||
fetchTransactions: Function,
|
||||
}
|
||||
|
||||
@ -104,6 +105,7 @@ class Layout extends React.Component<Props, State> {
|
||||
tokens,
|
||||
activeTokens,
|
||||
createTransaction,
|
||||
processTransaction,
|
||||
fetchTransactions,
|
||||
updateSafe,
|
||||
transactions,
|
||||
@ -169,6 +171,7 @@ class Layout extends React.Component<Props, State> {
|
||||
userAddress={userAddress}
|
||||
granted={granted}
|
||||
createTransaction={createTransaction}
|
||||
processTransaction={processTransaction}
|
||||
/>
|
||||
)}
|
||||
{tabIndex === 2 && (
|
||||
|
@ -20,10 +20,11 @@ type Props = {
|
||||
onClose: () => void,
|
||||
classes: Object,
|
||||
isOpen: boolean,
|
||||
createTransaction: Function,
|
||||
processTransaction: Function,
|
||||
tx: Transaction,
|
||||
nonce: string,
|
||||
safeAddress: string,
|
||||
threshold: number,
|
||||
thresholdReached: boolean,
|
||||
}
|
||||
|
||||
@ -42,10 +43,18 @@ const getModalTitleAndDescription = (thresholdReached: boolean) => {
|
||||
}
|
||||
|
||||
const ApproveTxModal = ({
|
||||
onClose, isOpen, classes, createTransaction, tx, safeAddress, thresholdReached,
|
||||
onClose,
|
||||
isOpen,
|
||||
classes,
|
||||
processTransaction,
|
||||
tx,
|
||||
safeAddress,
|
||||
threshold,
|
||||
thresholdReached,
|
||||
}: Props) => {
|
||||
const [shouldExecuteTx, setShouldExecuteTx] = useState<boolean>(false)
|
||||
const { title, description } = getModalTitleAndDescription(thresholdReached)
|
||||
const oneConfirmationLeft = tx.confirmations.size + 1 === threshold
|
||||
|
||||
const handleExecuteCheckbox = () => setShouldExecuteTx(prevShouldExecute => !prevShouldExecute)
|
||||
|
||||
@ -53,14 +62,7 @@ const ApproveTxModal = ({
|
||||
<SharedSnackbarConsumer>
|
||||
{({ openSnackbar }) => {
|
||||
const approveTx = () => {
|
||||
createTransaction(
|
||||
safeAddress,
|
||||
tx.recipient,
|
||||
tx.value,
|
||||
tx.data,
|
||||
openSnackbar,
|
||||
thresholdReached || shouldExecuteTx,
|
||||
)
|
||||
processTransaction(safeAddress, tx, openSnackbar, thresholdReached || shouldExecuteTx)
|
||||
onClose()
|
||||
}
|
||||
|
||||
@ -83,7 +85,7 @@ const ApproveTxModal = ({
|
||||
<br />
|
||||
<Bold className={classes.nonceNumber}>{tx.nonce}</Bold>
|
||||
</Paragraph>
|
||||
{!thresholdReached && (
|
||||
{!thresholdReached && oneConfirmationLeft && (
|
||||
<>
|
||||
<Paragraph color="error">
|
||||
Approving transaction does not execute it immediately. If you want to approve and execute the
|
||||
|
@ -37,6 +37,7 @@ type Props = {
|
||||
userAddress: string,
|
||||
safeAddress: string,
|
||||
createTransaction: Function,
|
||||
processTransaction: Function,
|
||||
}
|
||||
|
||||
type OpenModal = 'cancelTx' | 'approveTx' | null
|
||||
@ -55,7 +56,6 @@ const txStatusToLabel = {
|
||||
|
||||
const isCancellationTransaction = (tx: Transaction, safeAddress: string) => !tx.value && tx.data === EMPTY_DATA && tx.recipient === safeAddress
|
||||
|
||||
|
||||
const ExpandedTx = ({
|
||||
classes,
|
||||
tx,
|
||||
@ -65,6 +65,7 @@ const ExpandedTx = ({
|
||||
userAddress,
|
||||
safeAddress,
|
||||
createTransaction,
|
||||
processTransaction,
|
||||
}: Props) => {
|
||||
const [tabIndex, setTabIndex] = useState<number>(0)
|
||||
const [openModal, setOpenModal] = useState<OpenModal>(null)
|
||||
@ -74,7 +75,7 @@ const ExpandedTx = ({
|
||||
const cancellationTx = isCancellationTransaction(tx, safeAddress)
|
||||
const confirmedLabel = `Confirmed [${tx.confirmations.size}/${threshold}]`
|
||||
const unconfirmedLabel = `Unconfirmed [${owners.size - tx.confirmations.size}]`
|
||||
const thresholdReached = owners.size <= tx.confirmations.size
|
||||
const thresholdReached = threshold <= tx.confirmations.size
|
||||
|
||||
const ownersWhoConfirmed = []
|
||||
const ownersUnconfirmed = []
|
||||
@ -195,11 +196,13 @@ to:
|
||||
/>
|
||||
<ApproveTxModal
|
||||
isOpen={openModal === 'approveTx'}
|
||||
createTransaction={createTransaction}
|
||||
processTransaction={processTransaction}
|
||||
onClose={closeModal}
|
||||
tx={tx}
|
||||
safeAddress={safeAddress}
|
||||
threshold={threshold}
|
||||
thresholdReached={thresholdReached}
|
||||
currentUserAlreadyConfirmed={currentUserAlreadyConfirmed}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
@ -36,6 +36,7 @@ type Props = {
|
||||
granted: boolean,
|
||||
safeAddress: string,
|
||||
createTransaction: Function,
|
||||
processTransaction: Function,
|
||||
}
|
||||
|
||||
const TxsTable = ({
|
||||
@ -47,6 +48,7 @@ const TxsTable = ({
|
||||
userAddress,
|
||||
safeAddress,
|
||||
createTransaction,
|
||||
processTransaction,
|
||||
}: Props) => {
|
||||
const [expandedTx, setExpandedTx] = useState<string | null>(null)
|
||||
|
||||
@ -113,6 +115,7 @@ const TxsTable = ({
|
||||
granted={granted}
|
||||
userAddress={userAddress}
|
||||
createTransaction={createTransaction}
|
||||
processTransaction={processTransaction}
|
||||
safeAddress={safeAddress}
|
||||
/>
|
||||
</TableCell>
|
||||
|
@ -15,6 +15,7 @@ type Props = {
|
||||
userAddress: string,
|
||||
granted: boolean,
|
||||
createTransaction: Function,
|
||||
processTransaction: Function,
|
||||
}
|
||||
|
||||
const Transactions = ({
|
||||
@ -25,6 +26,7 @@ const Transactions = ({
|
||||
granted,
|
||||
safeAddress,
|
||||
createTransaction,
|
||||
processTransaction,
|
||||
fetchTransactions,
|
||||
}: Props) => {
|
||||
useEffect(() => {
|
||||
@ -44,6 +46,7 @@ const Transactions = ({
|
||||
granted={granted}
|
||||
safeAddress={safeAddress}
|
||||
createTransaction={createTransaction}
|
||||
processTransaction={processTransaction}
|
||||
/>
|
||||
) : (
|
||||
<NoTransactions />
|
||||
|
@ -2,6 +2,7 @@
|
||||
import fetchSafe from '~/routes/safe/store/actions/fetchSafe'
|
||||
import fetchTokenBalances from '~/routes/safe/store/actions/fetchTokenBalances'
|
||||
import createTransaction from '~/routes/safe/store/actions/createTransaction'
|
||||
import processTransaction from '~/routes/safe/store/actions/processTransaction'
|
||||
import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions'
|
||||
import updateSafe from '~/routes/safe/store/actions/updateSafe'
|
||||
import fetchTokens from '~/logic/tokens/store/actions/fetchTokens'
|
||||
@ -13,12 +14,14 @@ export type Actions = {
|
||||
fetchTransactions: typeof fetchTransactions,
|
||||
updateSafe: typeof updateSafe,
|
||||
fetchTokens: typeof fetchTokens,
|
||||
processTransaction: typeof processTransaction,
|
||||
}
|
||||
|
||||
export default {
|
||||
fetchSafe,
|
||||
fetchTokenBalances,
|
||||
createTransaction,
|
||||
processTransaction,
|
||||
fetchTokens,
|
||||
fetchTransactions,
|
||||
updateSafe,
|
||||
|
@ -63,6 +63,7 @@ class SafeView extends React.Component<Props> {
|
||||
network,
|
||||
tokens,
|
||||
createTransaction,
|
||||
processTransaction,
|
||||
fetchTransactions,
|
||||
updateSafe,
|
||||
transactions,
|
||||
@ -79,6 +80,7 @@ class SafeView extends React.Component<Props> {
|
||||
network={network}
|
||||
granted={granted}
|
||||
createTransaction={createTransaction}
|
||||
processTransaction={processTransaction}
|
||||
fetchTransactions={fetchTransactions}
|
||||
updateSafe={updateSafe}
|
||||
transactions={transactions}
|
||||
|
@ -7,6 +7,20 @@ import { type GlobalState } from '~/store'
|
||||
import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
|
||||
import { approveTransaction, executeTransaction, CALL } from '~/logic/safe/transactions'
|
||||
|
||||
// https://gnosis-safe.readthedocs.io/en/latest/contracts/signatures.html#pre-validated-signatures
|
||||
// https://github.com/gnosis/safe-contracts/blob/master/test/gnosisSafeTeamEdition.js#L26
|
||||
const generateSignaturesFromTxConfirmations = (tx: Transaction) => {
|
||||
let sigs = '0x'
|
||||
tx.confirmations.forEach((conf) => {
|
||||
sigs
|
||||
+= `000000000000000000000000${
|
||||
conf.owner.address.replace('0x', '')
|
||||
}0000000000000000000000000000000000000000000000000000000000000000`
|
||||
+ '01'
|
||||
})
|
||||
return sigs
|
||||
}
|
||||
|
||||
const processTransaction = (
|
||||
safeAddress: string,
|
||||
tx: Transaction,
|
||||
@ -18,11 +32,12 @@ const processTransaction = (
|
||||
const safeInstance = await getGnosisSafeInstanceAt(safeAddress)
|
||||
const from = userAccountSelector(state)
|
||||
const nonce = (await safeInstance.nonce()).toString()
|
||||
const sigs = generateSignaturesFromTxConfirmations(tx)
|
||||
|
||||
let txHash
|
||||
if (shouldExecute) {
|
||||
openSnackbar('Transaction has been submitted', 'success')
|
||||
txHash = await executeTransaction(safeInstance, tx.recipient, tx.value, tx.data, CALL, nonce, from)
|
||||
txHash = await executeTransaction(safeInstance, tx.recipient, tx.value, tx.data, CALL, nonce, from, sigs)
|
||||
openSnackbar('Transaction has been confirmed', 'success')
|
||||
} else {
|
||||
openSnackbar('Approval transaction has been submitted', 'success')
|
||||
|
Loading…
x
Reference in New Issue
Block a user