Skip to content

Commit

Permalink
Merge pull request #84 from valory-xyz/tanya/govern-donate
Browse files Browse the repository at this point in the history
(govern) feat: migrate donate to govern
  • Loading branch information
DavidMinarsch authored Aug 27, 2024
2 parents ba978bd + fde79af commit 1c7fbb0
Show file tree
Hide file tree
Showing 15 changed files with 648 additions and 13 deletions.
102 changes: 99 additions & 3 deletions apps/govern/common-util/functions/requests.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
import { readContract, readContracts } from '@wagmi/core';
import { ethers } from 'ethers';
import { AbiFunction, TransactionReceipt, parseUnits } from 'viem';
import { Abi, AbiFunction, TransactionReceipt, parseUnits } from 'viem';
import { Address } from 'viem';
import { mainnet } from 'viem/chains';

import { sendTransaction } from '@autonolas/frontend-library';

import { STAKING_FACTORY, VE_OLAS } from 'libs/util-contracts/src/lib/abiAndAddresses';
import {
SERVICE_REGISTRY,
STAKING_FACTORY,
VE_OLAS,
} from 'libs/util-contracts/src/lib/abiAndAddresses';
import { getEstimatedGasLimit } from 'libs/util-functions/src';

import { SUPPORTED_CHAINS, wagmiConfig } from 'common-util/config/wagmi';
import { RPC_URLS } from 'common-util/constants/rpcs';

import { getAddressFromBytes32 } from './addresses';
import { getUnixNextWeekStartTimestamp } from './time';
import { getOlasContract, getVeOlasContract, getVoteWeightingContract } from './web3';
import {
getOlasContract,
getTokenomicsContract,
getTreasuryContract,
getVeOlasContract,
getVoteWeightingContract,
} from './web3';

type VoteForNomineeWeightsParams = {
account: Address | undefined;
Expand Down Expand Up @@ -288,3 +298,89 @@ export const withdrawVeolasRequest = async ({ account }: { account: Address }) =
throw error;
}
};

/**
* Start new epoch
*/
export const checkpointRequest = async ({ account }: { account: Address }) => {
const contract = getTokenomicsContract();
try {
const checkpointFn = contract.methods.checkpoint();
const estimatedGas = await getEstimatedGasLimit(checkpointFn, account);
const fn = checkpointFn.send({ from: account, gasLimit: estimatedGas });

const response = await sendTransaction(fn, account, {
supportedChains: SUPPORTED_CHAINS,
rpcUrls: RPC_URLS,
});

return (response as TransactionReceipt)?.transactionHash;
} catch (error) {
window.console.log('Error occurred on starting new epoch');
throw error;
}
};

/**
* Check services are eligible for donating
*/
export const checkServicesTerminatedOrNotDeployed = async (ids: string[]) => {
const invalidServiceIds: string[] = [];

try {
const response = await readContracts(wagmiConfig, {
contracts: ids.map((id) => ({
abi: SERVICE_REGISTRY.abi as Abi,
address: (SERVICE_REGISTRY.addresses as Record<number, Address>)[mainnet.id],
chainId: mainnet.id,
functionName: 'getService',
args: [id],
})),
});

response.forEach((service, index) => {
const serviceData = service.result as { state: number } | null;
if (serviceData && serviceData.state !== 4 && serviceData.state !== 5) {
invalidServiceIds.push(ids[index]);
}
});
} catch (error) {
window.console.log('Error on checking service status');
throw error;
}

return invalidServiceIds;
};

/**
* Donate to services
*/
export const depositServiceDonationRequest = async ({
account,
serviceIds,
amounts,
totalAmount,
}: {
account: Address;
serviceIds: string[];
amounts: string[];
totalAmount: string;
}) => {
const contract = getTreasuryContract();

try {
const depositFn = contract.methods.depositServiceDonationsETH(serviceIds, amounts);
const estimatedGas = await getEstimatedGasLimit(depositFn, account, totalAmount);
const fn = depositFn.send({ from: account, value: totalAmount, gasLimit: estimatedGas });

const response = await sendTransaction(fn, account, {
supportedChains: SUPPORTED_CHAINS,
rpcUrls: RPC_URLS,
});

return (response as TransactionReceipt)?.transactionHash;
} catch (error) {
window.console.log('Error occurred on depositing service donation');
throw error;
}
};
22 changes: 21 additions & 1 deletion apps/govern/common-util/functions/web3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ import { mainnet } from 'viem/chains';
import Web3 from 'web3';
import { AbiItem } from 'web3-utils';

import { OLAS, VE_OLAS, VOTE_WEIGHTING } from 'libs/util-contracts/src/lib/abiAndAddresses';
import {
OLAS,
TOKENOMICS,
TREASURY,
VE_OLAS,
VOTE_WEIGHTING,
} from 'libs/util-contracts/src/lib/abiAndAddresses';

import { getChainId, getProvider } from 'common-util/functions/frontend-library';

Expand Down Expand Up @@ -46,3 +52,17 @@ export const getVeOlasContract = () => {
const contract = getContract(abi, address);
return contract;
};

export const getTokenomicsContract = () => {
const abi = TOKENOMICS.abi as unknown as AbiItem[];
const address = TOKENOMICS.addresses[mainnet.id];
const contract = getContract(abi, address);
return contract;
};

export const getTreasuryContract = () => {
const abi = TREASURY.abi as AbiItem[];
const address = TREASURY.addresses[mainnet.id];
const contract = getContract(abi, address);
return contract;
};
132 changes: 132 additions & 0 deletions apps/govern/components/Donate/DonateForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
import { Button, Form, Grid, InputNumber, Space, Typography } from 'antd';
import styled from 'styled-components';
import { useAccount } from 'wagmi';

const { Text } = Typography;
const { useBreakpoint } = Grid;

export const DynamicFormContainer = styled.div`
max-width: 720px;
.ant-input-number {
width: 200px;
}
`;

type DonateFormProps = {
isLoading: boolean;
onSubmit: ({ unitIds, amounts }: { unitIds: number[]; amounts: number[] }) => Promise<void>;
};

export const DonateForm = ({ isLoading, onSubmit }: DonateFormProps) => {
const { address: account } = useAccount();
const [form] = Form.useForm();

const screens = useBreakpoint();
const inputStyle = screens.xs ? { width: '140px' } : { width: 'auto' };

const onFinish = async (values: { units: { unitId: number; amount: number }[] }) => {
try {
await onSubmit({
unitIds: values.units.map((unit) => unit.unitId),
amounts: values.units.map((unit) => unit.amount),
});

form.resetFields();
} catch (error) {
window.console.error(error);
}
};

return (
<DynamicFormContainer>
<Form form={form} name="dynamic_form_complex" onFinish={onFinish} autoComplete="off">
<Form.List
name="units"
initialValue={[{ unitId: undefined, unitType: undefined }]}
rules={[
{
validator: async (_, units) => {
if (!units || units?.length === 0) {
return Promise.reject(new Error('At least 1 unit is required'));
}
return Promise.resolve();
},
},
]}
>
{(fields, { add, remove }, { errors }) => (
<>
{fields.map((field) => (
<Space key={field.key} align="baseline">
<Form.Item
noStyle
shouldUpdate={(prevValues, curValues) => prevValues.units !== curValues.units}
>
{() => (
<Form.Item
{...field}
label="Service ID"
name={[field.name, 'unitId']}
rules={[
{
required: true,
message: 'Please add Service ID',
},
]}
>
<InputNumber
min={0}
className="mr-24"
placeholder="Eg. 1"
style={inputStyle}
/>
</Form.Item>
)}
</Form.Item>

<Form.Item
{...field}
label="Amount (ETH)"
name={[field.name, 'amount']}
rules={[{ required: true, message: 'Please add Amount (ETH)' }]}
>
<InputNumber min={0} placeholder="Eg. 0.065" style={inputStyle} />
</Form.Item>

{fields.length > 1 && <MinusCircleOutlined onClick={() => remove(field.name)} />}
</Space>
))}

<Form.ErrorList errors={errors} />

<Form.Item wrapperCol={{ span: 6 }}>
<Button size="large" onClick={add} block icon={<PlusOutlined />}>
Add row
</Button>
</Form.Item>
</>
)}
</Form.List>

<Form.Item className="mb-0">
<Button
size="large"
type="primary"
htmlType="submit"
loading={isLoading}
disabled={!account}
>
Donate
</Button>

{!account && (
<Text className="ml-8" type="secondary">
To donate, connect a wallet
</Text>
)}
</Form.Item>
</Form>
</DynamicFormContainer>
);
};
Loading

0 comments on commit 1c7fbb0

Please sign in to comment.