diff --git a/src/components/complex/AssetSelection/index.jsx b/src/components/complex/AssetSelection/index.jsx index 89a7322..a1b7cb8 100644 --- a/src/components/complex/AssetSelection/index.jsx +++ b/src/components/complex/AssetSelection/index.jsx @@ -39,12 +39,12 @@ const SelectContainer = styled.div` display: ${({ mode }) => (mode === 'normal' ? 'normal' : 'none')}; ` -const AssetSelection = ({ onSelect: _onSelect }) => { +const AssetSelection = ({ onSelect: _onSelect, assets: _assets = settings.assets }) => { const [mode, setMode] = useState('normal') const [customValue, setCustomValue] = useState('') const [lastOption, setLastOption] = useState(null) - const options = [...settings.assets, { name: 'custom' }].map(({ address, logo, name, symbol }) => ({ + const options = [..._assets, { name: 'custom' }].map(({ address, logo, name, symbol }) => ({ option: name === 'custom' ? name : address, component: name === 'custom' ? ( diff --git a/src/settings/index.js b/src/settings/index.js index 40f9214..92a9da5 100644 --- a/src/settings/index.js +++ b/src/settings/index.js @@ -106,9 +106,10 @@ const settings = { ], chains: [ { - name: 'BSC', - logo: './assets/svg/BSC.svg', - chainId: '0x00e4b170' + name: 'Gnosis', + logo: './assets/svg/GNOSIS.svg', + endpoint: 'https://rpc.gnosischain.com', + chainId: '0x00f1918e' }, { name: 'Ethereum', @@ -116,10 +117,9 @@ const settings = { chainId: '0x005fe7f9' }, { - name: 'Gnosis', - logo: './assets/svg/GNOSIS.svg', - endpoint: 'https://rpc.gnosischain.com', - chainId: '0x00f1918e' + name: 'BSC', + logo: './assets/svg/BSC.svg', + chainId: '0x00e4b170' }, { name: 'Polygon', diff --git a/src/utils/__tests__/migrateTreasuryFunds.test.js b/src/utils/__tests__/migrateTreasuryFunds.test.js new file mode 100644 index 0000000..758289e --- /dev/null +++ b/src/utils/__tests__/migrateTreasuryFunds.test.js @@ -0,0 +1,48 @@ +import { getVotePresets } from '../vote-presets' +import { encodeCallScript } from '../voting-scripts' +const wagmi = require('@wagmi/core') + +describe('migrateTreasuryFunds', () => { + test('Should match the generated script', async () => { + jest.spyOn(wagmi, 'readContract').mockReturnValue(18) + const presets = getVotePresets({ + presetParams: { + 0: '0xf4ea6b892853413bd9d9f1a5d3a620a0ba39c5b2', + 1: 100, + 2: '0x00f1918e', + 3: '0xf1f6568a76559d85cF68E6597fA587544184dD46' + }, + setPresetParams: () => null, + provider: () => null + }) + const preset = presets['migrateTreasuryFunds'] + const actions = await preset.prepare() + const script = encodeCallScript(actions) + + const expectedScript = + '0x00000001dd92eb1478d3189707ab7f4a5ace3a615cdd047600000064beabacc8000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b20000000000000000000000002211bfd97b1c02ae8ac305d206e9780ba7d8bff40000000000000000000000000000000000000000000000056bc75e2d63100000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b200000044095ea7b3000000000000000000000000e396757ec7e6ac7c8e5abe7285dde47b98f22db80000000000000000000000000000000000000000000000056bc75e2d63100000e396757ec7e6ac7c8e5abe7285dde47b98f22db800000124c322525d0000000000000000000000000000000000000000000000056bc75e2d63100000000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b200000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000010000f1918e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a307866316636353638613736353539643835634636384536353937664135383735343431383464443436000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + + expect(script).toStrictEqual(expectedScript) + }) + + test('Should match the generated script with userData', async () => { + jest.spyOn(wagmi, 'readContract').mockReturnValue(18) + const presets = getVotePresets({ + presetParams: { + 1: 100, + 3: '0xf1f6568a76559d85cF68E6597fA587544184dD46', + 4: '0xf00dbabe' + }, + setPresetParams: () => null, + provider: () => null + }) + const preset = presets['migrateTreasuryFunds'] + const actions = await preset.prepare() + const script = encodeCallScript(actions) + + const expectedScript = + '0x00000001dd92eb1478d3189707ab7f4a5ace3a615cdd047600000064beabacc8000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b20000000000000000000000002211bfd97b1c02ae8ac305d206e9780ba7d8bff40000000000000000000000000000000000000000000000056bc75e2d63100000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b200000044095ea7b3000000000000000000000000e396757ec7e6ac7c8e5abe7285dde47b98f22db80000000000000000000000000000000000000000000000056bc75e2d63100000e396757ec7e6ac7c8e5abe7285dde47b98f22db800000144c322525d0000000000000000000000000000000000000000000000056bc75e2d63100000000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b200000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000010000f1918e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a307866316636353638613736353539643835634636384536353937664135383735343431383464443436000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004f00dbabe00000000000000000000000000000000000000000000000000000000' + + expect(script).toStrictEqual(expectedScript) + }) +}) diff --git a/src/utils/__tests__/withdrawInflation.test.js b/src/utils/__tests__/withdrawInflation.test.js index 69e7963..e111f9b 100644 --- a/src/utils/__tests__/withdrawInflation.test.js +++ b/src/utils/__tests__/withdrawInflation.test.js @@ -13,7 +13,7 @@ describe('withdrawInflationAndPegin', () => { const script = encodeCallScript(actions) const expectedScript = - '0x00000001f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b2000000443352d49b000000000000000000000000dd92eb1478d3189707ab7f4a5ace3a615cdd04760000000000000000000000000000000000000000000000000de0b6b3a7640000dd92eb1478d3189707ab7f4a5ace3a615cdd047600000064beabacc8000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b20000000000000000000000002211bfd97b1c02ae8ac305d206e9780ba7d8bff40000000000000000000000000000000000000000000000000de0b6b3a7640000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b200000044095ea7b3000000000000000000000000e396757ec7e6ac7c8e5abe7285dde47b98f22db80000000000000000000000000000000000000000000000000de0b6b3a7640000e396757ec7e6ac7c8e5abe7285dde47b98f22db800000124c322525d0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b200000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000010000e4b17000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a307861343136353762663232354638456337453230313043383963334630383431373239343832363444000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + '0x00000001f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b2000000443352d49b000000000000000000000000dd92eb1478d3189707ab7f4a5ace3a615cdd04760000000000000000000000000000000000000000000000000de0b6b3a7640000dd92eb1478d3189707ab7f4a5ace3a615cdd047600000064beabacc8000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b20000000000000000000000002211bfd97b1c02ae8ac305d206e9780ba7d8bff40000000000000000000000000000000000000000000000000de0b6b3a7640000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b200000044095ea7b3000000000000000000000000e396757ec7e6ac7c8e5abe7285dde47b98f22db80000000000000000000000000000000000000000000000000de0b6b3a7640000e396757ec7e6ac7c8e5abe7285dde47b98f22db800000124c322525d0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b200000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000010000f1918e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a307861343136353762663232354638456337453230313043383963334630383431373239343832363444000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' expect(script).toStrictEqual(expectedScript) }) diff --git a/src/utils/presets/migrateTreasuryFunds.js b/src/utils/presets/migrateTreasuryFunds.js new file mode 100644 index 0000000..1a2af82 --- /dev/null +++ b/src/utils/presets/migrateTreasuryFunds.js @@ -0,0 +1,143 @@ +import { ethers } from 'ethers' +import { erc20ABI } from 'wagmi' +import { readContract } from '@wagmi/core' + +import { getEthPNTAsset, getRawAmount, pNetworkV2Vault, vaultContract } from './utils' +import settings from '../../settings' + +const migrateTreasuryFunds = ({ presetParams, setPresetParams }) => ({ + id: 'migrateTreasuryFunds', + name: 'Migrate Treasury Funds', + description: 'Pegin Treasury funds to new chain', + args: [ + { + id: 'select-token-address', + name: 'tokenAddress', + component: 'AssetSelection', + props: { + assets: settings.assets.filter((asset) => asset.symbol === 'ethPNT' || asset.symbol === 'PNT'), + onSelect: (_address) => + setPresetParams({ + ...presetParams, + 0: _address + }) + } + }, + { + id: 'input-amount', + name: 'amount', + component: 'Input', + props: { + type: 'number', + style: { + fontSize: 15 + }, + placeholder: 'Amount ...', + value: presetParams[1] || '', + onChange: (_e) => + setPresetParams({ + ...presetParams, + 1: _e.target.value + }) + } + }, + { + id: 'select-chain', + name: 'destinationChain', + component: 'ChainSelection', + props: { + onSelect: (_chainId) => + setPresetParams({ + ...presetParams, + 2: _chainId + }) + } + }, + { + id: 'input-receiver-address', + name: 'receiverAddress', + component: 'Input', + props: { + style: { + fontSize: 15 + }, + placeholder: 'New Treasury Address (receiver address) ...', + value: presetParams[3] || '', + onChange: (_e) => + setPresetParams({ + ...presetParams, + 3: _e.target.value + }) + } + }, + { + id: 'input-user-data', + name: 'userData', + component: 'Input', + props: { + style: { + fontSize: 15 + }, + placeholder: 'Optional User Data ...', + value: presetParams[4] || '', + onChange: (_e) => + setPresetParams({ + ...presetParams, + 4: _e.target.value + }) + } + } + ], + prepare: async () => { + if (Object.values(presetParams).length < 2) return null + const assetAddress = presetParams[0] ? presetParams[0] : getEthPNTAsset().address + const amount = presetParams[1] + const destinationChainId = !presetParams[2] ? settings.chains[0].chainId : presetParams[2] + const destinationAddress = presetParams[3] + const userData = presetParams[4] ? presetParams[4] : '0x' + + if (!ethers.utils.isAddress(destinationAddress)) throw new Error('Inserted destination address is not valid') + + const assetDecimals = await readContract({ + address: assetAddress, + abi: erc20ABI, + functionName: 'decimals' + }) + + const rawAmount = getRawAmount(amount, assetDecimals) + + const transfer = { + to: settings.contracts.financeVault, + calldata: vaultContract.encodeFunctionData('transfer', [ + assetAddress, + settings.contracts.dandelionVoting, + rawAmount + ]) + } + + const erc20Contract = new ethers.utils.Interface(erc20ABI) + + const approve = { + to: assetAddress, + calldata: erc20Contract.encodeFunctionData('approve', [ + settings.contracts.pNetworkV2EthereumVaultAddess, + rawAmount + ]) + } + + const pegin = { + to: settings.contracts.pNetworkV2EthereumVaultAddess, + calldata: pNetworkV2Vault.encodeFunctionData('pegIn(uint256, address, string, bytes, bytes4)', [ + rawAmount, + assetAddress, + destinationAddress, + ethers.utils.arrayify(userData), + destinationChainId + ]) + } + + return [transfer, approve, pegin] + } +}) + +export default migrateTreasuryFunds diff --git a/src/utils/presets/utils.js b/src/utils/presets/utils.js index 1845fd0..bf6d806 100644 --- a/src/utils/presets/utils.js +++ b/src/utils/presets/utils.js @@ -7,7 +7,7 @@ import RewardsManagerABI from '../abis/RewardsManager.json' import MerklDistributionCreatorABI from '../abis/MerklDistributionCreator.json' import BigNumber from 'bignumber.js' import { ethers } from 'ethers' -import { readContract } from '@wagmi/core' +import { readContract, getProvider } from '@wagmi/core' import settings from '../../settings' @@ -21,17 +21,25 @@ export const dandelionVotingContract = new ethers.utils.Interface(DandelionVotin const ONE_DAY = 60 * 60 * 24 -export const prepareInflationData = (amount) => { +export const getEthPNTAsset = () => { const ethPNTAsset = settings.assets.find((asset) => asset.symbol == 'ethPNT') if (!ethPNTAsset) throw new Error('ethPNT asset config not found!') + return ethPNTAsset +} + +export const getRawAmount = (amount, decimals) => + BigNumber(amount) + .multipliedBy(10 ** decimals) + .toFixed() + +export const prepareInflationData = (amount) => { + const ethPNTAsset = getEthPNTAsset() const ethPNTAddress = ethPNTAsset.address if (!ethPNTAddress) throw new Error('ethPNT asset address not found!') const ethPNTDecimals = ethPNTAsset.decimals if (!ethPNTDecimals) throw new Error('ethPNT asset decimals not found!') - const rawAmount = BigNumber(amount) - .multipliedBy(10 ** ethPNTDecimals) - .toFixed() + const rawAmount = getRawAmount(amount, ethPNTDecimals) return { rawAmount: rawAmount, diff --git a/src/utils/vote-presets.js b/src/utils/vote-presets.js index c820c95..f47724d 100644 --- a/src/utils/vote-presets.js +++ b/src/utils/vote-presets.js @@ -1,4 +1,5 @@ import changeInflationOwner from './presets/changeInflationOwner' +import migrateTreasuryFunds from './presets/migrateTreasuryFunds' import createMerklIncentive from './presets/createMerklIncentive' import paymentFromTreasury from './presets/paymentFromTreasury' import withdrawInflationAndPegin from './presets/withdrawInflationAndPegin' @@ -15,6 +16,7 @@ const getVotePresets = ({ presetParams, setPresetParams, provider }) => { withdrawInflationAndDepositRewards: withdrawInflationAndDepositRewards({ presetParams, setPresetParams }), createMerklIncentive: createMerklIncentive({ presetParams, setPresetParams }), changeInflationOwner: changeInflationOwner({ presetParams, setPresetParams }), + migrateTreasuryFunds: migrateTreasuryFunds({ presetParams, setPresetParams }), custom: { id: 'custom', name: 'Custom - encoded script',