Skip to content

Commit

Permalink
Token approvals section (baking-bad#510)
Browse files Browse the repository at this point in the history
  • Loading branch information
aopoltorzhicky authored Jan 21, 2023
1 parent a41960f commit 14cbeb4
Show file tree
Hide file tree
Showing 8 changed files with 438 additions and 74 deletions.
10 changes: 10 additions & 0 deletions src/api/bcd.js
Original file line number Diff line number Diff line change
Expand Up @@ -750,4 +750,14 @@ export class BetterCallApi {
return this.api.get(`/helpers/contracts/${network}`, {params})
.then(this.returnResponseData);
}

approveSchema() {
return this.api.get(`/helpers/approve/schema`, {})
.then(this.returnResponseData);
}

approveData(data = {}) {
return this.api.post(`/helpers/approve/data`, data)
.then(this.returnResponseData);
}
}
47 changes: 37 additions & 10 deletions src/components/schema/Schema.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
:import-actions="importActions"
:execution="execution"
:execute-actions="executeActions"
:approve-model="approveModel"
@getRandomContract="getRandomContract"
@executeAction="stopGettingWallet"
@selectedNetwork="setSelectedNetwork"
Expand Down Expand Up @@ -83,6 +84,7 @@ import SchemaHeader from "./schemaComponents/SchemaHeader";
import SchemaAlertCustomSuccess from "./schemaAlert/SchemaAlertCustomSuccess";
import { TezosOperationType, AbortedBeaconError, BroadcastBeaconError, defaultEventCallbacks } from '@airgap/beacon-sdk'
import {Wallet} from "@/utils/wallet";
import { approveData } from "@/utils/approve";
import ConfirmDialog from "@/components/Dialogs/ConfirmDialog";
const walletsToIcons = {
Expand Down Expand Up @@ -116,7 +118,7 @@ export default {
header: String,
title: String,
type: String,
script: Array,
script: Array
},
data: () => ({
show: true,
Expand Down Expand Up @@ -153,6 +155,7 @@ export default {
},
],
model: {},
approveModel: {}
}),
created() {
this.selectedNetwork = this.network;
Expand Down Expand Up @@ -502,19 +505,13 @@ export default {
let parameter = await this.generateParameters(true);
if (!parameter) return;
let operations = this.buildTransactions(parameter);
this.execution = true;
try {
let client = await this.getClient();
const result = await client.requestOperation({
operationDetails: [{
kind: TezosOperationType.TRANSACTION,
destination: this.address,
amount: String(parseInt(this.settings.amount || "0")),
parameters: {
entrypoint: this.name,
value: parameter
},
}]
operationDetails: operations,
});
this.injectedOpHash = result.opHash;
} catch (err) {
Expand All @@ -524,6 +521,36 @@ export default {
this.execution = false;
}
},
buildTransactions(parameter) {
let contractCall = {
kind: TezosOperationType.TRANSACTION,
destination: this.address,
amount: String(parseInt(this.settings.amount || "0")),
parameters: {
entrypoint: this.name,
value: parameter
},
};
if (this.approveModel && this.approveModel.allowances && this.approveModel.allowances.length > 0){
return this.buildApproveTransactions(contractCall);
}
return [contractCall];
},
buildApproveTransactions(contractCall) {
let transactions = [];
let response = approveData(this.approveModel.allowances, this.address);
transactions.push(...response.fa1.revokes);
transactions.push(...response.fa1.approves);
transactions.push(...response.fa2.approves);
transactions.push(contractCall);
transactions.push(...response.fa2.revokes);
return transactions;
},
prepareContractToFork(show) {
if (this.execution) return;
Expand Down
94 changes: 47 additions & 47 deletions src/components/schema/schemaForm/SchemaForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
:schema="schema"
:options="{
initialValidation: false,
arrayItemCardProps: {
'elevation': 0,
'tile': true,
'outlined': true
}
}"
>
<template slot="custom-codemirror" slot-scope="{value, label, on}">
Expand Down Expand Up @@ -94,18 +99,41 @@
<div v-else-if="fallbackText">
<p class="text--disabled">{{ fallbackText }}</p>
</div>
<SchemaOptionalSettings
v-if="isOptionalSettings"
:is-storage="isStorage"
:is-deploy="isDeploy"
:networks="networks"
:settings="settings"
:importing="importing"
:import-actions="importActions"
:schema-selected-network="schemaSelectedNetwork"
@selectedNetwork="(val) => this.$emit('selectedNetwork', val)"
@settingsChange="(args) => this.$emit('settingsChange', args)"
/>

<div class="mb-4">
<span class="caption font-weight-medium text-uppercase text--disabled">Optional</span>
</div>
<v-expansion-panels flat hover multiple tile class="mb-6 pr-2" v-model="optional">
<v-expansion-panel>
<v-expansion-panel-header class="canvas caption font-weight-medium text-uppercase text--disabled">Settings</v-expansion-panel-header>
<v-expansion-panel-content class="canvas">
<SchemaOptionalSettings
v-if="isOptionalSettings"
:is-storage="isStorage"
:is-deploy="isDeploy"
:networks="networks"
:settings="settings"
:importing="importing"
:import-actions="importActions"
:schema-selected-network="schemaSelectedNetwork"
@selectedNetwork="(val) => this.$emit('selectedNetwork', val)"
@settingsChange="(args) => this.$emit('settingsChange', args)"
/>
</v-expansion-panel-content>
</v-expansion-panel>
<v-expansion-panel v-if="!isStorage && !isDeploy">
<v-expansion-panel-header class="canvas caption font-weight-medium text-uppercase text--disabled">
Token approvals
{{ approveModel.allowances && approveModel.allowances.length > 0 ? '(' + approveModel.allowances.length + ')' : '' }}
</v-expansion-panel-header>
<v-expansion-panel-content class="canvas">
<SchemaFormApprove
:model="approveModel"
/>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>

<SchemaFormExecutionActions
:execution="execution"
:execute-actions="executeActions"
Expand All @@ -117,16 +145,18 @@

<script>
import SchemaOptionalSettings from "./SchemaOptionalSettings";
import SchemaFormApprove from "./SchemaFormApprove.vue";
import SchemaFormExecutionActions from "./SchemaFormExecutionActions";
import Michelson from "@/components/Michelson";
import { isKT1Address, isTzAddress } from "@/utils/tz.js";
import { validationRules } from "@/utils/tz.js";
export default {
name: "SchemaForm",
components: {
Michelson,
SchemaFormExecutionActions,
SchemaOptionalSettings
SchemaOptionalSettings,
SchemaFormApprove
},
props: {
schema: Object,
Expand All @@ -149,6 +179,7 @@ name: "SchemaForm",
importActions: Array,
executeActions: Array,
fallbackText: String,
approveModel: Object
},
watch: {
selectedFillType(val) {
Expand All @@ -168,40 +199,9 @@ name: "SchemaForm",
return {
selectedFillType: 'empty',
model: {},
rules: {
contract:[
v => v.length == 36 || 'The length of the contract address is 36 characters',
v => isKT1Address(v) || 'In this field you should write the address of the contract. It begins with KT.'
],
nat: [
v => /^\d+$/.test(v) || 'Only digits are allowed',
v => this.validateNat(v)
],
bytes: [
v => v.length % 2 == 0 || "The length of the byte string must be even",
v => /^[0-9a-fA-F]*$/.test(v) || 'Only 0-9 and a-f are allowed',
],
address: [
v => v.length == 36 || 'The length of the address is 36 characters',
v => isTzAddress(v) || isKT1Address(v) || 'In this field you should write the address'
]
}
optional: !this.isStorage && !this.isDeploy ? [] : [0],
rules: validationRules
};
},
methods: {
validateNat(value) {
if (value.length == 0) {
return 'Nat field is required';
}
let nat = parseInt(value);
if (nat < 0) {
return 'Nat must be positive';
}
if (value.length > 1 && value[0] === '0') {
return "Nat can't starts from zero";
}
return true;
}
}
}
</script>
87 changes: 87 additions & 0 deletions src/components/schema/schemaForm/SchemaFormApprove.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<template>
<v-form>
<div class="pa-2 canvas">
<v-jsf
v-model="model"
:schema="schema"
:options="{
initialValidation: false,
arrayItemCardProps: {
'elevation': 0,
'tile': true,
'outlined': true,
'autoFixArrayItems': false
}
}"
>
<template slot="custom-nat" slot-scope="props">
<v-text-field
:ref="props.fullKey"
:label="props.label"
v-on="props.on"
dense
outlined
numeric
:value="props.value"
:rules="rules.nat"
:placeholder="props.label">
</v-text-field>
</template>
<template slot="custom-address" slot-scope="props">
<v-text-field
:ref="props.fullKey"
:label="props.label"
v-on="props.on"
dense
outlined
:value="props.value"
:placeholder="props.label"
:rules="rules.address"
>
</v-text-field>
</template>
<template slot="custom-wallet-address" slot-scope="props">
<v-text-field
:ref="props.fullKey"
:label="props.label"
v-on="props.on"
dense
outlined
:value="props.value"
:placeholder="props.label"
:rules="rules.address"
hint="If you attached a wallet, its address will be pasted automatically"
persistent-hint
class="mb-2"
>
</v-text-field>
</template>
</v-jsf>
</div>
</v-form>
</template>

<script>
import { getSchema } from '@/utils/approve.js';
import { validationRules } from '@/utils/tz';
import { Wallet } from "@/utils/wallet";
export default {
name: "SchemaFormApprove",
props: {
model: Object,
},
created() {
let account = Wallet.getLastUsedAccount();
if (account){
this.schema = getSchema(account.address)
}
},
data() {
return {
schema: getSchema(),
rules: validationRules
}
}
}
</script>
7 changes: 1 addition & 6 deletions src/components/schema/schemaForm/SchemaOptionalSettings.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
<template>
<div class="px-6 pt-4 pb-0 mr-2 mb-6 canvas optional-settings">
<div class="mb-6">
<span
class="caption font-weight-medium text-uppercase text--disabled"
>Optional settings</span>
</div>
<div class="pb-0 mr-2canvas optional-settings">
<div class="mb-6">
<v-btn-toggle
v-model="selectedNetwork"
Expand Down
Loading

0 comments on commit 14cbeb4

Please sign in to comment.