Skip to content

Commit

Permalink
verse claim and send WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
ma12ki committed Dec 26, 2022
1 parent 959c837 commit a3c96bd
Show file tree
Hide file tree
Showing 14 changed files with 458 additions and 74 deletions.
Binary file added public/img/verse.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
135 changes: 135 additions & 0 deletions src/abi/VerseClaimer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
[
{
"inputs": [
{ "internalType": "bytes32", "name": "_merkleRoot", "type": "bytes32" },
{ "internalType": "uint256", "name": "_minimumTimeFrame", "type": "uint256" },
{ "internalType": "address", "name": "_verseTokenAddress", "type": "address" }
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{ "indexed": true, "internalType": "address", "name": "recipient", "type": "address" },
{ "indexed": false, "internalType": "uint256", "name": "timeFrame", "type": "uint256" },
{ "indexed": false, "internalType": "uint256", "name": "tokensLocked", "type": "uint256" },
{ "indexed": false, "internalType": "uint256", "name": "tokensOpened", "type": "uint256" }
],
"name": "recipientEnrolled",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": true, "internalType": "address", "name": "scraper", "type": "address" },
{ "indexed": false, "internalType": "uint256", "name": "scrapedAmount", "type": "uint256" },
{ "indexed": false, "internalType": "uint256", "name": "timestamp", "type": "uint256" }
],
"name": "tokensScraped",
"type": "event"
},
{
"inputs": [{ "internalType": "address", "name": "_recipient", "type": "address" }],
"name": "availableBalance",
"outputs": [{ "internalType": "uint256", "name": "balance", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "createTime",
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{ "internalType": "uint256", "name": "_index", "type": "uint256" },
{ "internalType": "uint256", "name": "_tokensLocked", "type": "uint256" },
{ "internalType": "uint256", "name": "_tokensOpened", "type": "uint256" },
{ "internalType": "uint256", "name": "_timeFrame", "type": "uint256" },
{ "internalType": "bytes32[]", "name": "_merkleProof", "type": "bytes32[]" }
],
"name": "enrollAndScrape",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{ "internalType": "uint256", "name": "_index", "type": "uint256" },
{ "internalType": "address", "name": "_recipient", "type": "address" },
{ "internalType": "uint256", "name": "_tokensLocked", "type": "uint256" },
{ "internalType": "uint256", "name": "_tokensOpened", "type": "uint256" },
{ "internalType": "uint256", "name": "_timeFrame", "type": "uint256" },
{ "internalType": "bytes32[]", "name": "_merkleProof", "type": "bytes32[]" }
],
"name": "enrollRecipient",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{ "internalType": "uint256", "name": "_index", "type": "uint256" },
{ "internalType": "address[]", "name": "_recipient", "type": "address[]" },
{ "internalType": "uint256[]", "name": "_tokensLocked", "type": "uint256[]" },
{ "internalType": "uint256[]", "name": "_tokensOpened", "type": "uint256[]" },
{ "internalType": "uint256[]", "name": "_timeFrame", "type": "uint256[]" },
{ "internalType": "bytes32[][]", "name": "_merkleProof", "type": "bytes32[][]" }
],
"name": "enrollRecipientBulk",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "getNow",
"outputs": [{ "internalType": "uint256", "name": "time", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{ "internalType": "address", "name": "", "type": "address" }],
"name": "keeperList",
"outputs": [
{ "internalType": "uint256", "name": "keeperRate", "type": "uint256" },
{ "internalType": "uint256", "name": "keeperTill", "type": "uint256" },
{ "internalType": "uint256", "name": "keeperInstant", "type": "uint256" },
{ "internalType": "uint256", "name": "keeperPayouts", "type": "uint256" }
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{ "internalType": "address", "name": "_recipient", "type": "address" }],
"name": "lockedBalance",
"outputs": [{ "internalType": "uint256", "name": "balance", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "merkleRoot",
"outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
"stateMutability": "view",
"type": "function"
},
{ "inputs": [], "name": "scrapeMyTokens", "outputs": [], "stateMutability": "nonpayable", "type": "function" },
{
"inputs": [],
"name": "totalRequired",
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "verseToken",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
"stateMutability": "view",
"type": "function"
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ const tx: IStrategyBlockTx = {
data: callData,
};

export function getTx() {
return tx;
}

function Arbitrum_Bridgeworld_Claim() {
const setTx = useStrategyStore((state) => state.setTx);
const { account } = useAutomateConnection();
Expand Down
14 changes: 10 additions & 4 deletions src/components/Strategies/Blocks/Arbitrum_Magic_Send.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { useAutomateConnection, useStrategyStore } from '../../../hooks';
import { ethereum, StrategyBlock } from '../../../constants';
import { ethereumAddressValidator, retryRpcCallOnIntermittentError } from '../../../utils';
import { MAGIC_ADDRESS, MAGIC_DECIMAL_UNIT } from '../../../constants';
import { IStrategyBlockTxWithFallback } from '../../../types';
import { getStrategyByUrl } from '../strategyData';
import BaseBlock from './BaseBlock';

const { Text } = Typography;
Expand All @@ -17,9 +19,10 @@ const web3 = new Web3(ethereum as any);
const magicContract = new web3.eth.Contract(ERC20ABI as any, MAGIC_ADDRESS);

function Arbitrum_Magic_Send() {
const strategyName = useStrategyStore((state) => state.strategyName);
const strategyChainId = useStrategyStore((state) => state.chainId);
const setTx = useStrategyStore((state) => state.setTx);
const { account, chainId } = useAutomateConnection();
const strategyChainId = useStrategyStore((state) => state.chainId);
const [address, setAddress] = useState('');
const [amount, setAmount] = useState('');
const isCorrectChain = chainId === strategyChainId;
Expand All @@ -29,16 +32,19 @@ function Arbitrum_Magic_Send() {
const amountWei = web3.utils.toWei(amount, MAGIC_DECIMAL_UNIT);
const callData = magicContract.methods.transfer(address, amountWei).encodeABI();

setTx(StrategyBlock.Arbitrum_Magic_Send, {
const tx: IStrategyBlockTxWithFallback = {
to: MAGIC_ADDRESS,
data: callData,
amount: amountWei,
asset: MAGIC_ADDRESS,
});
fallback: getStrategyByUrl(strategyName).fallbacks![StrategyBlock.Ethereum_Verse_Send]!(),
};

setTx(StrategyBlock.Arbitrum_Magic_Send, tx);
} catch (e) {
console.error(e);
}
}, [address, amount, setTx]);
}, [address, amount, setTx, strategyName]);

return (
<Container>
Expand Down
72 changes: 72 additions & 0 deletions src/components/Strategies/Blocks/Ethereum_Verse_Claim.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { useEffect } from 'react';
import { Col, Row, Typography } from 'antd';
import { GiftOutlined } from '@ant-design/icons';
import styled from 'styled-components';
import Web3 from 'web3';

import VerseClaimerABI from '../../../abi/VerseClaimer.json';
import { IStrategyBlockTx } from '../../../types';
import { StrategyBlock } from '../../../constants';
import { useStrategyStore } from '../../../hooks';
import BaseBlock from './BaseBlock';

const { Title, Text } = Typography;

const VERSE_CLAIMER_ADDRESS = '0xE5aC5142BdE69cfA722662D9C3E4C8111f60B8d5';

const web3 = new Web3();
const callData = new web3.eth.Contract(VerseClaimerABI as any).methods.scrapeMyTokens().encodeABI();

const tx: IStrategyBlockTx = {
to: VERSE_CLAIMER_ADDRESS,
data: callData,
};

export function getTx(): IStrategyBlockTx {
return tx;
}

function Ethereum_Verse_Claim() {
const setTx = useStrategyStore((state) => state.setTx);

useEffect(() => {
setTx(StrategyBlock.Ethereum_Verse_Claim, tx);
}, [setTx]);

return (
<Container>
<BaseBlock
title={
<>
<GiftOutlined />
<Text className="cardTitle">Claim Rewards</Text>
</>
}
>
<Row gutter={12}>
<Col span={6}>
<img alt="Verse" src="/img/verse.png" height="72px" />
</Col>
<Col>
<div>
<Title className="secondary" level={5}>
Claim from{' '}
<a
href="https://etherscan.io/address/0xE5aC5142BdE69cfA722662D9C3E4C8111f60B8d5"
rel="noopener noreferrer"
target="_blank"
>
VerseClaimer
</a>
</Title>
</div>
</Col>
</Row>
</BaseBlock>
</Container>
);
}

const Container = styled.div``;

export default Ethereum_Verse_Claim;
131 changes: 131 additions & 0 deletions src/components/Strategies/Blocks/Ethereum_Verse_Send.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { useEffect, useState } from 'react';
import { Col, Row, Typography, Input, Form, Checkbox } from 'antd';
import { ExportOutlined } from '@ant-design/icons';
import styled from 'styled-components';
import Web3 from 'web3';

import ERC20ABI from '../../../abi/ERC20.json';
import { useAutomateConnection, useStrategyStore } from '../../../hooks';
import { IStrategyBlockTxWithFallback } from '../../../types';
import { ethereum, StrategyBlock } from '../../../constants';
import { ethereumAddressValidator, retryRpcCallOnIntermittentError } from '../../../utils';
import { getStrategyByUrl } from '../strategyData';
import BaseBlock from './BaseBlock';

const { Text } = Typography;
const web3 = new Web3(ethereum as any);

const verseAddress = '0x249cA82617eC3DfB2589c4c17ab7EC9765350a18';
const verseContract = new web3.eth.Contract(ERC20ABI as any, verseAddress);
const verseDecimalUnit = 'ether';

function Ethereum_Verse_Send() {
const strategyName = useStrategyStore((state) => state.strategyName);
const setTx = useStrategyStore((state) => state.setTx);
const strategyChainId = useStrategyStore((state) => state.chainId);
const { account, chainId } = useAutomateConnection();
const [address, setAddress] = useState('');
const [amount, setAmount] = useState('');
const [withFallback, setWithFallback] = useState(true);
const isCorrectChain = chainId === strategyChainId;

useEffect(() => {
try {
const amountWei = web3.utils.toWei(amount, verseDecimalUnit);
const callData = verseContract.methods.transfer(address, amountWei).encodeABI();

const tx: IStrategyBlockTxWithFallback = {
to: verseAddress,
data: callData,
amount: amountWei,
asset: verseAddress,
};

if (withFallback) {
tx.fallback = getStrategyByUrl(strategyName).fallbacks![StrategyBlock.Ethereum_Verse_Send]!();
}

setTx(StrategyBlock.Ethereum_Verse_Send, tx);
} catch (e) {
console.error(e);
}
}, [address, amount, withFallback, setTx, strategyName]);

return (
<Container>
<BaseBlock
title={
<>
<ExportOutlined />
<Text className="cardTitle">Send $VERSE</Text>
</>
}
>
<Row gutter={24}>
<Col span={16}>
<Form.Item
name={`${StrategyBlock.Ethereum_Verse_Send}_to`}
validateFirst
rules={[
{ required: true, message: 'Recipient address is required' },
{ validator: (_, value) => ethereumAddressValidator(value) },
]}
>
<Input size="large" placeholder="To address" onChange={(e) => setAddress(e.target.value)} />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name={`${StrategyBlock.Ethereum_Verse_Send}_amount`}
validateFirst
rules={[
{ required: true, message: 'Amount is required' },
{
validator: (_, value) =>
isCorrectChain ? tokenBalanceValidator(account!, value) : Promise.resolve(value),
},
]}
>
<Input size="large" placeholder="Amount" onChange={(e) => setAmount(e.target.value)} />
</Form.Item>
</Col>
</Row>
<Row gutter={24}>
<Col span={24}>
<Form.Item
name={`${StrategyBlock.Ethereum_Verse_Send}_withFallback`}
label="Fallback"
tooltip="Enabling this option will generate a fallback Claim tx for every Send. The fallback tx will be executed if there's not enough $VERSE tokens in your wallet"
colon={false}
>
<Checkbox checked={withFallback} onChange={(e) => setWithFallback(!withFallback)} />
</Form.Item>
</Col>
</Row>
</BaseBlock>
</Container>
);
}

async function tokenBalanceValidator(account?: string, amount?: number): Promise<void> {
if (!amount) {
return;
}

if (!ethereum || !account) {
throw new Error('Connect to Automate to validate amount');
}

const balanceWei = await retryRpcCallOnIntermittentError<string>(async () =>
verseContract.methods.balanceOf(account).call()
);
const balanceEth = Number(web3.utils.fromWei(balanceWei, verseDecimalUnit));

if (balanceEth < amount) {
throw new Error(`You need at least ${amount} $VERSE in your wallet to be able to Automate`);
}
}

const Container = styled.div``;

export default Ethereum_Verse_Send;
Loading

0 comments on commit a3c96bd

Please sign in to comment.