Skip to content

Commit

Permalink
adds a batchRefund page
Browse files Browse the repository at this point in the history
  • Loading branch information
FlacoJones committed Jun 22, 2023
1 parent d647efb commit 6b03015
Show file tree
Hide file tree
Showing 4 changed files with 291 additions and 1 deletion.
14 changes: 14 additions & 0 deletions constants/refundBountyTemplate.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"version": "1.0",
"chainId": "137",
"createdAt": 1687467410647,
"meta": {
"name": "Transactions Batch",
"description": "",
"txBuilderVersion": "1.16.0",
"createdFromSafeAddress": "0x8A6668f45E0CFF1233bd178F265D89Abc93b11a7",
"createdFromOwnerAddress": "",
"checksum": "0x919220e6c1e7a35ce2203eb0a0b4d77a6d88e172aefe637b6ff4567e076202d1"
},
"transactions": []
}
21 changes: 21 additions & 0 deletions constants/refundBountyTransactionTemplate.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"to": "0x964aEcdFE3d35B6c57Fb4ea02A7A149c5688516C",
"value": "0",
"data": null,
"contractMethod": {
"inputs": [
{
"internalType": "address",
"name": "_bountyAddress",
"type": "address"
},
{ "internalType": "bytes32", "name": "_depositId", "type": "bytes32" }
],
"name": "refundDeposit",
"payable": false
},
"contractInputsValues": {
"_bountyAddress": "",
"_depositId": ""
}
}
256 changes: 256 additions & 0 deletions pages/batchRefund.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
import React, { useState, useContext, useEffect } from 'react';
import Papa from 'papaparse';
import StoreContext from '../store/Store/StoreContext';
import _ from 'lodash';
import mintBountyTemplate from '../constants/mintBountyTemplate.json';
import refundBountyTransactionTemplate from '../constants/refundBountyTransactionTemplate.json';
import md4 from 'js-md4';
import Link from 'next/link';
import Image from 'next/image';
import BountyCardLean from '../components/BountyCard/BountyCardLean';
import { convertCsvToJson } from '../lib/batchUtils';

function BatchRefund() {
const [refundBountyBatchData, setRefundBountyBatchData] = useState(null);
const [bounties, setBounties] = useState([]);
const [appState] = useContext(StoreContext);
const [file, setFile] = useState(null);

const handleCopyToClipboard = () => {
navigator.clipboard.writeText(JSON.stringify(refundBountyBatchData));
};

const handleDownload = () => {
const stringifiedJsonData = JSON.stringify(refundBountyBatchData);
const element = document.createElement('a');
const file = new Blob([stringifiedJsonData], { type: 'application/json' });
element.href = URL.createObjectURL(file);

const textEncoder = new TextEncoder();
const md4Digest = md4(textEncoder.encode(stringifiedJsonData));

element.download = `mintBountyBatchTransactions-${md4Digest.substring(0, 5)}.json`;
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
};

const loadGithubData = async (githubIssueUrl) => {
const resource = await appState.githubRepository.fetchIssueByUrl(githubIssueUrl);
const bountyId = resource.id;
return { bountyId };
};

const loadOnChainBounty = async (bountyId) => {
const bounty = await appState.openQSubgraphClient.getBountyByGithubId(bountyId);
return bounty;
};

const handleFileUpload = (event) => {
const file = event.target.files[0];
setFile(file);
const reader = new FileReader();

reader.onload = async (event) => {
const csvData = Papa.parse(event.target.result).data;

// Convert CSV data to JSON
const jsonData = convertCsvToJson(csvData);

// Populate the transaction template
const transactions = [];

for (const transactionData of jsonData) {
const { githubIssueUrl } = transactionData;

try {
// Fetch Github Issue ID and Organization ID
const { bountyId } = await loadGithubData(githubIssueUrl);

const { bountyAddress, deposits } = await loadOnChainBounty(bountyId);

// Overwrite contractInputsValues on mintBountyTransactionTemplate
const refundBountyTransactionTemplateCopy = _.cloneDeep(refundBountyTransactionTemplate);

console.log('deposits[0].id', deposits[0].id);

refundBountyTransactionTemplateCopy.to = process.env.NEXT_PUBLIC_DEPOSIT_MANAGER_PROXY_ADDRESS;
refundBountyTransactionTemplateCopy.contractInputsValues._bountyAddress = bountyAddress;
refundBountyTransactionTemplateCopy.contractInputsValues._depositId = deposits[0].id;

transactions.push(refundBountyTransactionTemplateCopy);
} catch (err) {
appState.logger.error(err, 'refundBatch.js1');
}
}

const mintBountyTemplateCopy = _.cloneDeep(mintBountyTemplate);
mintBountyTemplateCopy.transactions = transactions;

setRefundBountyBatchData(mintBountyTemplateCopy);
};

reader.readAsText(file);
};

const parseTransaction = async (transaction) => {
const { contractInputsValues } = transaction;
const githubData = await appState.githubRepository.fetchIssueById(contractInputsValues._bountyId);

return {
...githubData,
};
};

useEffect(() => {
const getBountyData = async () => {
if (refundBountyBatchData) {
const bounties = refundBountyBatchData.transactions.map(async (transaction) => {
const bountyData = await parseTransaction(transaction);
const currentTimestamp = Date.now();

return {
...bountyData,
deposits: [],
payouts: [],
bountyType: '3',
bountyMintTime: currentTimestamp / 1000,
status: '0',
};
});
setBounties(await Promise.all(bounties));
}
};
getBountyData();
}, [refundBountyBatchData]);

return (
<div className='flex flex-col items-center py-14'>
<div className='w-full text-center bg-[#161B22] py-14 border-t border-web-gray'>
<h1 className='text-2xl font-bold'>OpenQ Mint Bounty Batcher</h1>
<div className='text-gray-500 text-md'>
This is a utility to input a CSV of your bounty information and convert it to a format for upload to{' '}
<Link
className='hover:underline text-blue-400'
rel='noopener norefferer'
target='_blank'
href='https://help.safe.global/en/articles/4680071-transaction-builder'
>
Gnosis Safe Transaction Builder
</Link>
</div>
</div>
<div className='flex flex-col space-y-4'>
<h2 className='text-xl pt-8 font-bold'>Step 1: Create Your Bounty CSV</h2>
<div>
Copy{' '}
<Link
className='hover:underline text-blue-400'
rel='noopener norefferer'
target='_blank'
href='https://docs.google.com/spreadsheets/d/1JpJ6xj278Cirez9hldCmUDWlE3ZzwEoFX4kNfNC1oSE/template/preview'
>
this Google Sheets template.
</Link>{' '}
To do this, simply click <b>"Use Template"</b>.
<Image
src='/batchPage/Use_Template_Button.png'
width={1000}
height={80}
alt='use template button'
className='mt-4'
/>
</div>
<h2 className='text-xl pt-8 font-bold'>Step 2: Download your Google Sheet as a CSV</h2>
<div>File =&gt; Download =&gt; Comma Separated Values (.csv)</div>
<Image src='/batchPage/Download_CSV.png' width={1000} height={80} alt='use template button' className='my-2' />
<h2 className='text-xl pt-8 font-bold'>Step 3: Select your CSV file here</h2>
<form className='flex gap-4'>
<label className='btn-primary cursor-pointer whitespace-nowrap' htmlFor='upload'>
{refundBountyBatchData ? 'Update File' : 'Choose File'}
</label>
<input
className='absolute invisible w-full top-0 bottom-0 z-10'
accept='.csv'
type='file'
id='upload'
onChange={handleFileUpload}
/>
<div className='flex items-center border border-web-gray w-full font-semibold h-8 px-2 rounded-sm'>
{file?.name}
</div>
</form>
{refundBountyBatchData && (
<div>
{refundBountyBatchData === null ? (
''
) : (
<div className='flex flex-col space-y-2'>
<div>✅ Success!</div>
<div>Now go on to the next step and download your JSON file below:</div>
</div>
)}
</div>
)}

<h2 className='text-xl pt-8 font-bold'>Step 5: Download the generated JSON file</h2>
{refundBountyBatchData && (
<div className='flex flex-col'>
<h2>
You will use the Gnosis Safe Transaction Builder JSON to refund the{' '}
{refundBountyBatchData.transactions.length} bounties show below.
<br />
<div className='my-4'>
{bounties.map((bounty, index) => {
return (
<BountyCardLean noModal={true} length={bounties.length} index={index} key={index} item={bounty} />
);
})}
</div>
<br />
If this is correct, then download the JSON file and follow the next steps.
</h2>
<div className='pt-4 flex items-center space-x-4'>
<button className='btn-primary' onClick={handleDownload}>
Download JSON
</button>
<div>OR</div>
<button className='btn-primary' onClick={handleCopyToClipboard}>
Copy to Clipboard
</button>
</div>
</div>
)}
<h2 className='text-xl pt-8 font-bold'>Step 6: Navigate to the Transaction Builder Safe App</h2>
<div>
Go to{' '}
<Link
className='hover:underline text-blue-400'
rel='noopener norefferer'
target='_blank'
href='https://app.safe.global'
>
https://app.safe.global
</Link>
, navigate to "Apps" and then search for <b>"Transaction Builder"</b>.
</div>
<div>
For a more detailed guide on how to use the Transaction Builder, see{' '}
<Link
className='hover:underline text-blue-400'
rel='noopener norefferer'
target='_blank'
href='https://help.safe.global/en/articles/4680071-transaction-builder'
>
https://help.safe.global/en/articles/4680071-transaction-builder
</Link>
</div>
<h2 className='text-xl pt-8 font-bold'>
Step 7: Drag and drop the downloaded file to the Gnosis Safe App Transaction Builder
</h2>
</div>
</div>
);
}

export default BatchRefund;
1 change: 0 additions & 1 deletion services/subgraph/graphql/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,6 @@ export const GET_BOUNTIES_BY_CONTRACT_ADDRESSES = gql`
payouts {
id
}
deposits {
id
refunded
Expand Down

0 comments on commit 6b03015

Please sign in to comment.