Skip to content

Commit

Permalink
better validation, state setting for nft trasnfer & token transfer
Browse files Browse the repository at this point in the history
  • Loading branch information
gsteenkamp89 committed Feb 5, 2024
1 parent d4ab63c commit a06b992
Show file tree
Hide file tree
Showing 9 changed files with 279 additions and 118 deletions.
44 changes: 13 additions & 31 deletions src/plugins/oSnap/Create.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ import {
Transaction
} from './types';
import {
allTransactionsValid,
getGnosisSafeBalances,
getGnosisSafeCollectibles,
getIsOsnapEnabled,
getModuleAddressForTreasury,
validateTransaction
validateOsnapTransaction
} from './utils';
import OsnapMarketingWidget from './components/OsnapMarketingWidget.vue';
Expand All @@ -44,14 +45,14 @@ const safes = ref<GnosisSafe[]>([]);
const tokens = ref<Token[]>([]);
const collectables = ref<NFT[]>([]);
const transactionsValid = ref(false);
function addTransaction(transaction: Transaction) {
if (newPluginData.value.safe === null) return;
newPluginData.value.safe.transactions.push({
...transaction,
isValid: validateTransaction(transaction)
});
newPluginData.value.safe.transactions.push(
validateOsnapTransaction(transaction)
);
newPluginData.value.safe.isValid = allTransactionsValid(
newPluginData.value.safe.transactions
);
update(newPluginData.value);
}
Expand All @@ -63,11 +64,11 @@ function removeTransaction(transactionIndex: number) {
function updateTransaction(transaction: Transaction, transactionIndex: number) {
if (!newPluginData.value.safe) return;
newPluginData.value.safe.transactions[transactionIndex] = {
...transaction,
isValid: validateTransaction(transaction)
};
newPluginData.value.safe.transactions[transactionIndex] =
validateOsnapTransaction(transaction);
newPluginData.value.safe.isValid = allTransactionsValid(
newPluginData.value.safe.transactions
);
update(newPluginData.value);
}
Expand Down Expand Up @@ -234,25 +235,6 @@ onMounted(async () => {
update(newPluginData.value);
isLoading.value = false;
});
watch(newPluginData, () => {
// validate form here, set isValid accordingly upstream
if (!newPluginData.value.safe) {
return;
}
// can't publish without transactions
if (newPluginData.value.safe.transactions.length === 0) {
transactionsValid.value = false;
return;
}
// check ALL transactions
if (newPluginData.value.safe.transactions.every(validateTransaction)) {
transactionsValid.value = false;
return;
}
// default to invalid
transactionsValid.value = false;
});
</script>

<template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
createContractInteractionTransaction,
getABIWriteFunctions,
getContractABI,
processContractInteractionTransaction,
validateTransaction
} from '../../utils';
import AddressInput from '../Input/Address.vue';
Expand Down Expand Up @@ -40,23 +41,17 @@ const selectedMethod = computed(
const parameters = ref<string[]>([]);
function updateTransaction() {
if (!isValueValid || !isToValid || !isAbiValid) return;
try {
const transaction = createContractInteractionTransaction({
to: to.value,
value: value.value,
abi: abi.value,
method: selectedMethod.value,
parameters: parameters.value
});
if (validateTransaction(transaction)) {
emit('updateTransaction', transaction);
return;
}
} catch (error) {
console.warn('ContractInteraction - Invalid Transaction:',error);
}
// if (!isValueValid || !isToValid || !isAbiValid) return;
const transaction = processContractInteractionTransaction({
to: to.value,
value: value.value,
abi: abi.value,
method: selectedMethod.value,
parameters: parameters.value
});
emit('updateTransaction', transaction);
}
function updateParameter(index: number, value: string) {
Expand All @@ -73,7 +68,6 @@ function updateMethod(methodName: string) {
function updateAbi(newAbi: string) {
abi.value = newAbi;
methods.value = [];
try {
methods.value = getABIWriteFunctions(abi.value);
isAbiValid.value = true;
Expand Down Expand Up @@ -137,8 +131,11 @@ function updateValue(newValue: string) {
</option>
</UiSelect>

<div v-if="selectedMethod && selectedMethod.inputs.length">
<div class="divider"></div>
<div
v-if="selectedMethod && selectedMethod.inputs.length"
class="flex flex-col gap-2"
>
<div class="divider h-[1px] bg-skin-border my-3" />

<MethodParameterInput
v-for="(input, index) in selectedMethod.inputs"
Expand Down
39 changes: 9 additions & 30 deletions src/plugins/oSnap/components/TransactionBuilder/TransferFunds.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
<script setup lang="ts">
import { ETH_CONTRACT } from '@/helpers/constants';
import { shorten } from '@/helpers/utils';
import { isAddress } from '@ethersproject/address';
import { isBigNumberish } from '@ethersproject/bignumber/lib/bignumber';
import { Network, Token, TransferFundsTransaction } from '../../types';
import {
createTransferFundsTransaction,
getERC20TokenTransferTransactionData,
getNativeAsset,
validateTransaction
} from '../../utils';
import { getNativeAsset, processTransferFundsInput } from '../../utils';
import AddressInput from '../Input/Address.vue';
import AmountInput from '../Input/Amount.vue';
import TokensModal from './TokensModal.vue';
Expand All @@ -32,36 +25,22 @@ const tokens = ref<Token[]>([nativeAsset, ...props.tokens]);
const selectedTokenAddress = ref<Token['address']>(
props.transaction?.token?.address ?? 'main'
);
const selectedToken = computed(
() =>
tokens.value.find(token => token.address === selectedTokenAddress.value) ??
nativeAsset
);
const selectedTokenIsNative = computed(
() => selectedToken.value?.address === 'main'
);
const isTokenModalOpen = ref(false);
function updateTransaction() {
try {
const data = selectedTokenIsNative.value
? '0x'
: getERC20TokenTransferTransactionData(recipient.value, amount.value);
const transaction = createTransferFundsTransaction({
data,
amount: amount.value,
recipient: recipient.value,
token: selectedToken.value
});
emit('updateTransaction', transaction);
const isTransactionValid = validateTransaction(transaction);
if (!isTransactionValid) {
console.warn('invalid transaction');
}
} catch (error) {
console.warn('invalid transaction', error);
}
const processedTransaction = processTransferFundsInput({
recipient: recipient.value,
amount: amount.value,
token: selectedToken.value
});
emit('updateTransaction', processedTransaction);
}
function openModal() {
Expand Down
36 changes: 8 additions & 28 deletions src/plugins/oSnap/components/TransactionBuilder/TransferNFT.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
<script setup lang="ts">
import { shorten } from '@/helpers/utils';
import { isAddress } from '@ethersproject/address';
import { NFT, Network, TransferNftTransaction } from '../../types';
import {
createTransferNftTransaction,
getERC721TokenTransferTransactionData,
validateTransaction
} from '../../utils';
import { processTransferNftInput } from '../../utils';
import AddressInput from '../Input/Address.vue';
const props = defineProps<{
Expand All @@ -32,28 +27,13 @@ const selectedCollectable = computed(() => {
});
function updateTransaction() {
if (!isAddress(recipient.value) || !selectedCollectable.value) return;
try {
const data = getERC721TokenTransferTransactionData(
props.safeAddress,
recipient.value,
selectedCollectable.value.id
);
const transaction = createTransferNftTransaction({
data,
recipient: recipient.value,
collectable: selectedCollectable.value
});
if (validateTransaction(transaction)) {
emit('updateTransaction', transaction);
return;
}
} catch (error) {
console.warn('invalid transaction');
}
// if (!isAddress(recipient.value) || !selectedCollectable.value) return;
const processedTransaction = processTransferNftInput({
safeAddress: props.safeAddress,
recipient: recipient.value,
collectible: selectedCollectable.value
});
emit('updateTransaction', processedTransaction);
}
watch(recipient, updateTransaction);
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/oSnap/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,13 +221,15 @@ export type BalanceResponse = {
* @field `network` field is the id for network that the safe is on.
* @field `moduleAddress` field is the address of the Optimistic Governor contract that was deployed for this safe.
* @field `transactions` field is the list of transactions that the Optimistic Governor contract will execute.
* @field `isValid?` field check if ALL transactions have passed their respective validation checks
*/
export type GnosisSafe = {
safeName: string;
safeAddress: string;
network: Network;
moduleAddress: string;
transactions: Transaction[];
isValid?: boolean;
};

/**
Expand Down
6 changes: 5 additions & 1 deletion src/plugins/oSnap/utils/coins.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Network } from '../types';
import { Network, Token } from '../types';

export const ETHEREUM_COIN = {
name: 'Ether',
Expand Down Expand Up @@ -59,3 +59,7 @@ export function getNativeAsset(network: Network) {

return ETHEREUM_COIN;
}

export function isNativeAsset(token: Token | undefined) {
return token ? token.address === 'main' : false;
}
Loading

0 comments on commit a06b992

Please sign in to comment.