Skip to content

Commit

Permalink
Merge branch 'master' into feat-resizable-proposal-sidebar
Browse files Browse the repository at this point in the history
  • Loading branch information
wa0x6e committed Jan 6, 2025
2 parents 0118df1 + e79b4ef commit 157bdd3
Show file tree
Hide file tree
Showing 32 changed files with 768 additions and 310 deletions.
5 changes: 5 additions & 0 deletions .changeset/lucky-kangaroos-approve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@snapshot-labs/sx": patch
---

add flagProposal method to offchain EthereumSig client
1 change: 1 addition & 0 deletions apps/ui/.env
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ VITE_OPENSEA_API_KEY=dad1ec57d9024a1d9cb72e6d82c2d015
VITE_GA_MEASUREMENT_ID=G-8MQS50MVZX
VITE_TENDERLY_ACCESS_KEY=8-1V1FGLxFqhs75T7bUs4lK1BaPOnfcT
VITE_WC_PROJECT_ID=b191e242d2f2163c99bcf9d44297e946
VITE_ETHERSCAN_API_KEY=2UAJBTBZRQTSZUF9JW953W9XMGDM3YAZWY
VITE_HOST=localhost
6 changes: 3 additions & 3 deletions apps/ui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
<div id="app"></div>
<div id="modal"></div>
<script type="module" src="/src/main.ts"></script>
<script>
var global = global || window;
</script>
</body>
</html>
<script>
var global = global || window;
</script>
2 changes: 1 addition & 1 deletion apps/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"@snapshot-labs/lock": "^0.2.10",
"@snapshot-labs/pineapple": "^1.1.0",
"@snapshot-labs/prettier-config": "^0.1.0-beta.18",
"@snapshot-labs/snapshot.js": "^0.12.36",
"@snapshot-labs/snapshot.js": "^0.12.41",
"@snapshot-labs/sx": "^0.1.0",
"@vueuse/core": "^10.4.1",
"@walletconnect/core": "^2.11.0",
Expand Down
5 changes: 3 additions & 2 deletions apps/ui/src/components/FormSpaceAdvanced.vue
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,9 @@ watchEffect(() => {
type="info"
:learn-more-link="'https://docs.snapshot.box/spaces/add-custom-domain'"
>
To setup a custom domain you additionally need to open a pull request on
GitHub after you have created the space.
To set up a custom domain, you must subscribe to the Turbo plan and create a
CNAME record pointing to "cname.snapshot.box" with your DNS provider or
registrar.
</UiMessage>
<div class="s-box mt-3">
<UiInputString
Expand Down
2 changes: 1 addition & 1 deletion apps/ui/src/components/Layout/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ router.afterEach(() => {
@add="handleTransactionAccept"
@close="handleTransactionReject"
/>
<FlashMessageWelcome />
<FlashMessageWelcome v-if="!whiteLabelSpace" />
</div>
</template>

Expand Down
80 changes: 71 additions & 9 deletions apps/ui/src/components/Modal/Delegate.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
<script setup lang="ts">
import { clone } from '@/helpers/utils';
import networks from '@snapshot-labs/snapshot.js/src/networks.json';
import { h, VNode } from 'vue';
import { clone, getUrl } from '@/helpers/utils';
import { getValidator } from '@/helpers/validation';
import { METADATA as STARKNET_NETWORK_METADATA } from '@/networks/starknet';
import { Space, SpaceMetadataDelegation } from '@/types';
const DEFAULT_FORM_STATE = {
delegatee: ''
delegatee: '',
selectedIndex: 0
};
const props = defineProps<{
open: boolean;
space: Space;
delegation: SpaceMetadataDelegation;
delegation?: SpaceMetadataDelegation;
initialState?: any;
}>();
Expand Down Expand Up @@ -39,18 +43,62 @@ const { delegate } = useActions();
const form: {
delegatee: string;
selectedIndex: number;
} = reactive(clone(DEFAULT_FORM_STATE));
const formValidated = ref(false);
const showPicker = ref(false);
const searchValue = ref('');
const sending = ref(false);
const formErrors = ref({} as Record<string, any>);
const selectedDelegation = computed<SpaceMetadataDelegation>(() => {
return props.delegation || props.space.delegations[form.selectedIndex];
});
const spaceDelegationsOptions = computed<
{ id: number; name: string; icon: VNode }[]
>(() => {
return props.space.delegations
.filter(d => d.chainId)
.map((d, i) => {
const network = getNetworkDetails(d.chainId as string);
return {
id: i,
name: d.name || '',
icon: h('img', {
src: getUrl(network.logo),
alt: network.name,
class: 'rounded-full'
})
};
});
});
function getNetworkDetails(chainId: number | string) {
if (typeof chainId === 'number') {
return networks[chainId];
}
const starknetNetwork = Object.entries(STARKNET_NETWORK_METADATA).find(
([, { chainId: starknetChainId }]) => starknetChainId === chainId
)?.[0];
if (!starknetNetwork) {
return { name: 'Unknown network', logo: '' };
}
return {
name: STARKNET_NETWORK_METADATA[starknetNetwork].name,
logo: STARKNET_NETWORK_METADATA[starknetNetwork].avatar
};
}
async function handleSubmit() {
if (
!props.delegation.apiType ||
!props.delegation.contractAddress ||
!props.delegation.chainId
!selectedDelegation.value.apiType ||
!selectedDelegation.value.contractAddress ||
!selectedDelegation.value.chainId
) {
return;
}
Expand All @@ -60,10 +108,10 @@ async function handleSubmit() {
try {
await delegate(
props.space,
props.delegation.apiType,
selectedDelegation.value.apiType,
form.delegatee,
props.delegation.contractAddress,
props.delegation.chainId
selectedDelegation.value.contractAddress,
selectedDelegation.value.chainId
);
emit('close');
} catch (e) {
Expand All @@ -78,8 +126,11 @@ watch(
() => {
if (props.initialState) {
form.delegatee = props.initialState.delegatee;
form.selectedIndex =
props.initialState.selectedIndex || DEFAULT_FORM_STATE.selectedIndex;
} else {
form.delegatee = DEFAULT_FORM_STATE.delegatee;
form.selectedIndex = DEFAULT_FORM_STATE.selectedIndex;
}
}
);
Expand Down Expand Up @@ -127,6 +178,17 @@ watchEffect(async () => {
/>
</template>
<div v-else class="s-box p-4">
<Combobox
v-if="!delegation && props.space.delegations.length > 1"
v-model="form.selectedIndex"
:definition="{
type: ['number'],
title: 'Delegation scheme',
examples: ['Select delegation scheme'],
enum: spaceDelegationsOptions.map(d => d.id),
options: spaceDelegationsOptions
}"
/>
<UiInputAddress
v-model="form.delegatee"
:definition="DELEGATEE_DEFINITION"
Expand Down
5 changes: 3 additions & 2 deletions apps/ui/src/components/ProposalExecutionsList.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { getGenericExplorerUrl } from '@/helpers/explorer';
import { getProposalCurrentQuorum } from '@/helpers/quorum';
import { buildBatchFile } from '@/helpers/safe/ build';
import { getExecutionName } from '@/helpers/ui';
import { shorten, toBigIntOrNumber } from '@/helpers/utils';
Expand Down Expand Up @@ -101,8 +102,8 @@ function downloadExecution(execution: ProposalExecution) {
proposal.executions &&
proposal.executions.length > 0 &&
proposal.scores.length > 0 &&
toBigIntOrNumber(proposal.scores_total) >=
toBigIntOrNumber(proposal.quorum) &&
getProposalCurrentQuorum(proposal.network, proposal) >=
proposal.quorum &&
toBigIntOrNumber(proposal.scores[0]) >
toBigIntOrNumber(proposal.scores[1]) &&
proposal.has_execution_window_opened
Expand Down
101 changes: 72 additions & 29 deletions apps/ui/src/components/ProposalResults.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
quorumProgress
} from '@/helpers/quorum';
import { _n, _p, _vp } from '@/helpers/utils';
import { getNetwork, offchainNetworks } from '@/networks';
import { Proposal as ProposalType } from '@/types';
const DEFAULT_MAX_CHOICES = 6;
Expand All @@ -26,6 +27,8 @@ const props = withDefaults(
}
);
const proposalsStore = useProposalsStore();
const displayAllChoices = ref(false);
const totalProgress = computed(() => quorumProgress(props.proposal));
Expand Down Expand Up @@ -87,29 +90,64 @@ const otherResultsSummary = computed(() => {
}
);
});
const isFinalizing = computed(() => {
return (
!props.proposal.completed &&
['passed', 'executed', 'rejected'].includes(props.proposal.state)
);
});
async function refreshScores() {
try {
const network = getNetwork(props.proposal.network);
const hubUrl = network.api.apiUrl.replace('/graphql', '');
const response = await fetch(`${hubUrl}/api/scores/${props.proposal.id}`);
const result = await response.json();
if (result.result === true) {
proposalsStore.reset(props.proposal.space.id, props.proposal.network);
await proposalsStore.fetchProposal(
props.proposal.space.id,
props.proposal.id,
props.proposal.network
);
}
} catch (e) {
console.warn('Failed to refresh scores', e);
}
}
onMounted(() => {
if (offchainNetworks.includes(props.proposal.network) && isFinalizing.value) {
refreshScores();
}
});
</script>

<template>
<div v-if="isFinalizing" class="border rounded-lg px-3 py-2.5">
<div class="flex items-center gap-2 text-skin-link">
<IH-exclamation-circle class="shrink-0" />
Finalizing results
</div>
Please allow few minutes while final results are being calculated.
</div>
<div
v-if="!!props.proposal.privacy && !props.proposal.completed && withDetails"
v-else-if="
!!props.proposal.privacy &&
props.proposal.state === 'active' &&
withDetails
"
class="space-y-1"
>
<div class="mb-1">
<div>
All votes are encrypted and will be decrypted only after the voting period
is over, making the results visible.
</div>
<div>
<a
:href="SHUTTER_URL"
class="flex items-center text-skin-link"
target="_blank"
>
<IC-Shutter class="w-[80px]" />
<IH-arrow-sm-right class="-rotate-45" />
</a>
<div v-if="proposal.quorum" class="mt-3.5">
{{ quorumLabel(proposal.quorum_type) }}:
<span class="text-skin-link">{{ formatQuorum(totalProgress) }}</span>
</div>
<div v-if="proposal.quorum">
{{ quorumLabel(proposal.quorum_type) }}:
<span class="text-skin-link">{{ formatQuorum(totalProgress) }}</span>
</div>
</div>
<template v-else>
Expand Down Expand Up @@ -154,10 +192,16 @@ const otherResultsSummary = computed(() => {
class="truncate grow"
v-text="proposal.choices[result.choice - 1]"
/>
<div>
{{ _vp(result.score / 10 ** decimals) }}
</div>
<div v-text="_p(result.progress / 100)" />
<IH-lock-closed
v-if="!!proposal.privacy && !proposal.completed"
class="size-[16px] shrink-0"
/>
<template v-else>
<div>
{{ _vp(result.score / 10 ** decimals) }}
</div>
<div v-text="_p(result.progress / 100)" />
</template>
</div>
<button
v-if="!displayAllChoices && otherResultsSummary.count > 0"
Expand Down Expand Up @@ -190,16 +234,6 @@ const otherResultsSummary = computed(() => {
{{ quorumLabel(proposal.quorum_type) }}:
<span class="text-skin-link">{{ formatQuorum(totalProgress) }}</span>
</div>
<div v-if="proposal.privacy === 'shutter'" class="mt-2.5">
<a
:href="SHUTTER_URL"
class="flex items-center text-skin-link"
target="_blank"
>
<IC-Shutter class="w-[80px]" />
<IH-arrow-sm-right class="-rotate-45" />
</a>
</div>
</div>
<div
v-else-if="!props.proposal.privacy || props.proposal.completed"
Expand Down Expand Up @@ -231,4 +265,13 @@ const otherResultsSummary = computed(() => {
</div>
</div>
</template>
<a
v-if="proposal.privacy == 'shutter' && withDetails"
:href="SHUTTER_URL"
class="flex items-center text-skin-link mt-2.5"
target="_blank"
>
<IC-Shutter class="w-[80px]" />
<IH-arrow-sm-right class="-rotate-45" />
</a>
</template>
20 changes: 20 additions & 0 deletions apps/ui/src/composables/useActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,25 @@ export function useActions() {
return true;
}

async function flagProposal(proposal: Proposal) {
if (!web3.value.account) {
await forceLogin();
return false;
}

const network = getNetwork(proposal.network);
if (!network.managerConnectors.includes(web3.value.type as Connector)) {
throw new Error(`${web3.value.type} is not supported for this action`);
}

await wrapPromise(
proposal.network,
network.actions.flagProposal(auth.web3, proposal)
);

return true;
}

async function cancelProposal(proposal: Proposal) {
if (!web3.value.account) {
await forceLogin();
Expand Down Expand Up @@ -634,6 +653,7 @@ export function useActions() {
vote: wrapWithErrors(vote),
propose: wrapWithErrors(propose),
updateProposal: wrapWithErrors(updateProposal),
flagProposal: wrapWithErrors(flagProposal),
cancelProposal: wrapWithErrors(cancelProposal),
finalizeProposal: wrapWithErrors(finalizeProposal),
executeTransactions: wrapWithErrors(executeTransactions),
Expand Down
Loading

0 comments on commit 157bdd3

Please sign in to comment.