From 1c44801d6768e38cde194c38c916ec5dad5c7d8a Mon Sep 17 00:00:00 2001 From: Gerhard Steenkamp Date: Fri, 22 Dec 2023 12:07:24 +0200 Subject: [PATCH 01/15] create base component logic --- src/components/IconTenderly.vue | 27 ++++++ .../TransactionBuilder/TenderlySimulation.vue | 82 +++++++++++++++++++ .../TransactionBuilder/TransactionBuilder.vue | 7 ++ 3 files changed, 116 insertions(+) create mode 100644 src/components/IconTenderly.vue create mode 100644 src/plugins/oSnap/components/TransactionBuilder/TenderlySimulation.vue diff --git a/src/components/IconTenderly.vue b/src/components/IconTenderly.vue new file mode 100644 index 000000000..11fce4c75 --- /dev/null +++ b/src/components/IconTenderly.vue @@ -0,0 +1,27 @@ + diff --git a/src/plugins/oSnap/components/TransactionBuilder/TenderlySimulation.vue b/src/plugins/oSnap/components/TransactionBuilder/TenderlySimulation.vue new file mode 100644 index 000000000..bfdd010e6 --- /dev/null +++ b/src/plugins/oSnap/components/TransactionBuilder/TenderlySimulation.vue @@ -0,0 +1,82 @@ + + + diff --git a/src/plugins/oSnap/components/TransactionBuilder/TransactionBuilder.vue b/src/plugins/oSnap/components/TransactionBuilder/TransactionBuilder.vue index afaa45019..64c61de01 100644 --- a/src/plugins/oSnap/components/TransactionBuilder/TransactionBuilder.vue +++ b/src/plugins/oSnap/components/TransactionBuilder/TransactionBuilder.vue @@ -64,6 +64,13 @@ const safeLink = computed(() => @update-transaction="(...args) => emit('updateTransaction', ...args)" @remove-transaction="(...args) => emit('removeTransaction', ...args)" /> + Date: Fri, 26 Jan 2024 15:02:47 +0200 Subject: [PATCH 02/15] update styling --- src/assets/css/main.scss | 4 + src/components/IconTenderly.vue | 14 ++-- .../TransactionBuilder/TenderlySimulation.vue | 80 +++++++++++++------ .../TransactionBuilder/TransactionBuilder.vue | 2 + tailwind.config.js | 4 +- 5 files changed, 67 insertions(+), 37 deletions(-) diff --git a/src/assets/css/main.scss b/src/assets/css/main.scss index 3e02db768..192ea450d 100644 --- a/src/assets/css/main.scss +++ b/src/assets/css/main.scss @@ -19,6 +19,8 @@ --header-bg: #1c1b20; --block-bg: transparent; --shadow-color: rgba(255, 255, 255, 0.036); + --green: 151 69% 42%; + --red: 351 100% 61%; } [data-color-scheme='light'] { @@ -32,6 +34,8 @@ --header-bg: white; --block-bg: transparent; --shadow-color: #0001; + --green: 151 69% 42%; + --red: 351 100% 61%; } @layer base { diff --git a/src/components/IconTenderly.vue b/src/components/IconTenderly.vue index 11fce4c75..af2cc44bd 100644 --- a/src/components/IconTenderly.vue +++ b/src/components/IconTenderly.vue @@ -1,26 +1,22 @@ diff --git a/src/plugins/oSnap/components/TransactionBuilder/TransactionBuilder.vue b/src/plugins/oSnap/components/TransactionBuilder/TransactionBuilder.vue index 64c61de01..846e612c9 100644 --- a/src/plugins/oSnap/components/TransactionBuilder/TransactionBuilder.vue +++ b/src/plugins/oSnap/components/TransactionBuilder/TransactionBuilder.vue @@ -4,6 +4,7 @@ import { shorten } from '@/helpers/utils'; import { NFT, Network, Transaction as TTransaction, Token } from '../../types'; import { getSafeAppLink } from '../../utils'; import Transaction from './Transaction.vue'; +import TenderlySimulation from './TenderlySimulation.vue'; const props = defineProps<{ safeAddress: string; @@ -70,6 +71,7 @@ const safeLink = computed(() => :safe-address="safeAddress" :module-address="moduleAddress" :network="props.network" + class="mt-4" /> diff --git a/tailwind.config.js b/tailwind.config.js index ac51f8850..f23a318c6 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -14,8 +14,8 @@ module.exports = { 'skin-block-bg': 'var(--block-bg)', 'skin-header-bg': 'var(--header-bg)', 'skin-heading': 'var(--heading-color)', - green: '#21b66f', - red: '#ff3856' + green: 'hsl(var(--green) / )', + red: 'hsl(var(--red) / )' }, keyframes: { fadeIn: { From b142899b5bc43f76fb1cd83b97af70d4994165a3 Mon Sep 17 00:00:00 2001 From: Gerhard Steenkamp Date: Tue, 30 Jan 2024 13:13:35 +0200 Subject: [PATCH 03/15] validate payload, handle request and update styles --- src/plugins/oSnap/Create.vue | 1 + .../TransactionBuilder/TenderlySimulation.vue | 128 +++++++++++------- .../TransactionBuilder/TransactionBuilder.vue | 12 +- src/plugins/oSnap/types.ts | 23 +++- src/plugins/oSnap/utils/tenderly.ts | 55 ++++++++ src/plugins/oSnap/utils/validators.ts | 4 +- 6 files changed, 168 insertions(+), 55 deletions(-) create mode 100644 src/plugins/oSnap/utils/tenderly.ts diff --git a/src/plugins/oSnap/Create.vue b/src/plugins/oSnap/Create.vue index 7bbe3e9ff..9bfc8b9ea 100644 --- a/src/plugins/oSnap/Create.vue +++ b/src/plugins/oSnap/Create.vue @@ -286,6 +286,7 @@ onMounted(async () => { :collectables="collectables" :network="newPluginData.safe.network" :transactions="newPluginData.safe.transactions" + :safe="newPluginData.safe" @add-transaction="addTransaction" @remove-transaction="removeTransaction" @update-transaction="updateTransaction" diff --git a/src/plugins/oSnap/components/TransactionBuilder/TenderlySimulation.vue b/src/plugins/oSnap/components/TransactionBuilder/TenderlySimulation.vue index 38b668bdc..f86d0ea09 100644 --- a/src/plugins/oSnap/components/TransactionBuilder/TenderlySimulation.vue +++ b/src/plugins/oSnap/components/TransactionBuilder/TenderlySimulation.vue @@ -1,73 +1,90 @@ From 303b548b1dd1e549bb2645bed8b3925906dbc05b Mon Sep 17 00:00:00 2001 From: Gerhard Steenkamp <51655063+gsteenkamp89@users.noreply.github.com> Date: Thu, 1 Feb 2024 10:51:03 +0200 Subject: [PATCH 06/15] feat: show warning if gas exceeds 500_000, refactor state (#121) --- .../TransactionBuilder/TenderlySimulation.vue | 150 ++++++++++++------ src/plugins/oSnap/utils/tenderly.ts | 9 +- 2 files changed, 109 insertions(+), 50 deletions(-) diff --git a/src/plugins/oSnap/components/TransactionBuilder/TenderlySimulation.vue b/src/plugins/oSnap/components/TransactionBuilder/TenderlySimulation.vue index 176f3b7fb..b5ebe7e0b 100644 --- a/src/plugins/oSnap/components/TransactionBuilder/TenderlySimulation.vue +++ b/src/plugins/oSnap/components/TransactionBuilder/TenderlySimulation.vue @@ -7,40 +7,74 @@ import { GnosisSafe, isErrorWithMessage } from '../../types'; -import { computed } from 'vue'; import { ref } from 'vue'; import { SIMULATION_ENDPOINT, + exceedsOsnapGasSubsidy, prepareTenderlySimulationPayload, - validatePayload + validatePayload, + OSNAP_GAS_SUBSIDY } from '../../utils/tenderly'; -// ERROR => unable to simulate -// FAIL => tx Failed in simulation -// SUCCESS => tx Succeeded in simulation -type Status = 'SUCCESS' | 'FAIL' | 'ERROR' | 'LOADING' | 'IDLE'; - const props = defineProps<{ transactions: TTransaction[]; safe: GnosisSafe | null; network: Network; }>(); -const simulationState = ref('IDLE'); -const simulationLink = ref(); -const simulationError = ref(); +type State = + | { + status: 'SUCCESS'; + simulationLink: TenderlySimulationResult['resultUrl']; + gasUsed: TenderlySimulationResult['gasUsed']; + exceedsGasSubsidy: boolean; + } + | { + status: 'FAIL'; + simulationLink: TenderlySimulationResult['resultUrl']; + gasUsed: TenderlySimulationResult['gasUsed']; + exceedsGasSubsidy: boolean; + } + | { + status: 'ERROR'; + error: string; + } + | { + status: 'LOADING'; + } + | { + status: 'IDLE'; + }; + +const simulationState = ref({ status: 'IDLE' }); + +const resetState = () => { + simulationState.value = { status: 'IDLE' }; +}; function handleSimulationResult(res: TenderlySimulationResult) { + // if gas exceeds osnap gas subsidy, tx will not be automatically executed + const exceedsGasSubsidy = exceedsOsnapGasSubsidy(res); + if (res.status === true) { - simulationState.value = 'SUCCESS'; + simulationState.value = { + status: 'SUCCESS', + simulationLink: res.resultUrl, + gasUsed: res.gasUsed, + exceedsGasSubsidy + }; } else { - simulationState.value = 'FAIL'; + simulationState.value = { + status: 'FAIL', + simulationLink: res.resultUrl, + gasUsed: res.gasUsed, + exceedsGasSubsidy + }; } - simulationLink.value = res.resultUrl.url; } async function simulate() { - simulationState.value = 'LOADING'; + simulationState.value = { status: 'LOADING' }; try { const payload = prepareTenderlySimulationPayload(props); @@ -64,84 +98,102 @@ async function simulate() { } catch (error) { console.error(error); if (isErrorWithMessage(error)) { - simulationError.value = error.message; + simulationState.value = { status: 'ERROR', error: error.message }; + } else { + simulationState.value = { + status: 'ERROR', + error: 'Failed to simulate!' + }; } - simulationState.value = 'ERROR'; await sleep(5_000); - simulationState.value = 'IDLE'; + simulationState.value = { + status: 'IDLE' + }; } } - -const errorMessage = simulationError ?? 'Failed to simulate!'; - -const showResult = computed(() => { - return ( - simulationState.value === 'FAIL' || simulationState.value === 'SUCCESS' - ); -}); - -const resetState = () => { - simulationState.value = 'IDLE'; - simulationLink.value = undefined; - simulationError.value = undefined; -}; diff --git a/src/plugins/oSnap/utils/tenderly.ts b/src/plugins/oSnap/utils/tenderly.ts index e9860b86e..2edd25d96 100644 --- a/src/plugins/oSnap/utils/tenderly.ts +++ b/src/plugins/oSnap/utils/tenderly.ts @@ -2,7 +2,8 @@ import { OsnapPluginData, Transaction as TTransaction, GnosisSafe, - Network + Network, + TenderlySimulationResult } from '../types'; import { validateModuleAddress, @@ -12,6 +13,8 @@ import { export const SIMULATION_ENDPOINT = 'https://ethereum-api-read-prod-77jg7zf4ea-ue.a.run.app/osnap/simulate'; +export const OSNAP_GAS_SUBSIDY = 500_000; + export function validatePayload(data: OsnapPluginData): void | never { const { safe } = data; if (!safe) { @@ -53,3 +56,7 @@ export function prepareTenderlySimulationPayload(props: { return { safe: payload }; } + +export function exceedsOsnapGasSubsidy(res: TenderlySimulationResult): boolean { + return res.gasUsed > OSNAP_GAS_SUBSIDY; +} From ea6595e5e7c30f4073128729d8c671679d561a5e Mon Sep 17 00:00:00 2001 From: Gerhard Steenkamp <51655063+gsteenkamp89@users.noreply.github.com> Date: Thu, 1 Feb 2024 14:57:25 +0200 Subject: [PATCH 07/15] feat: add simulation in proposal view (#122) --- src/plugins/oSnap/Proposal.vue | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/plugins/oSnap/Proposal.vue b/src/plugins/oSnap/Proposal.vue index 4a2261290..ad5fc57fa 100644 --- a/src/plugins/oSnap/Proposal.vue +++ b/src/plugins/oSnap/Proposal.vue @@ -8,6 +8,7 @@ import ReadOnly from './components/Input/ReadOnly.vue'; import SafeLinkWithAvatar from './components/SafeLinkWithAvatar.vue'; import { GnosisSafe, Transaction } from './types'; import OsnapMarketingWidget from './components/OsnapMarketingWidget.vue'; +import TenderlySimulation from './components/TransactionBuilder/TenderlySimulation.vue'; const keyOrder = [ 'to', @@ -59,9 +60,11 @@ function enrichTransactionForDisplay(transaction: Transaction) { ...commonProperties, type: 'Contract interaction', 'method name': method.name, - ...Object.fromEntries(method.inputs.map((input,i)=>{ - return [`${input.name} (param ${i+1}): `,parameters[i]] - })) + ...Object.fromEntries( + method.inputs.map((input, i) => { + return [`${input.name} (param ${i + 1}): `, parameters[i]]; + }) + ) }; } if (transaction.type === 'transferFunds') { @@ -97,7 +100,7 @@ function enrichTransactionForDisplay(transaction: Transaction) {