Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nft transfers #311

Merged
merged 14 commits into from
Dec 3, 2021
327 changes: 327 additions & 0 deletions customabis/ERC721.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"fmt": "prettier --check '**/*.ts'",
"fmt:write": "prettier --write '**/*.ts'",
"prepare": "husky install",
"generate-types": "typechain --target=ethers-v5 --out-dir src/contracts './node_modules/@openzeppelin/contracts/build/contracts/ERC20.json'",
"generate-types": "typechain --target=ethers-v5 --out-dir src/contracts './node_modules/@openzeppelin/contracts/build/contracts/ERC20.json' './customabis/ERC721.json' './node_modules/@openzeppelin/contracts/build/contracts/ERC1155.json'",
bh2smith marked this conversation as resolved.
Show resolved Hide resolved
"postinstall": "yarn generate-types"
},
"dependencies": {
Expand Down
9 changes: 5 additions & 4 deletions public/sample.csv
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
token_address,receiver,amount
0x6810e776880c02933d47db1b9fc05908e5386b96,0x1000000000000000000000000000000000000000,0.0001
0x6b175474e89094c44da98b954eedeac495271d0f,0x2000000000000000000000000000000000000000,0.0001
,0x3000000000000000000000000000000000000000,0.0001
token_type,token_address,receiver,value,id
erc20,0x6810e776880c02933d47db1b9fc05908e5386b96,0x1000000000000000000000000000000000000000,0.0001
erc20,0x6b175474e89094c44da98b954eedeac495271d0f,0x2000000000000000000000000000000000000000,0.0001
native,,0x3000000000000000000000000000000000000000,0.0001
erc721,0x57f1887a8bf19b14fc0df6fd9b2acc9af147ea85,0x4000000000000000000000000000000000000000,,42
bh2smith marked this conversation as resolved.
Show resolved Hide resolved
bh2smith marked this conversation as resolved.
Show resolved Hide resolved
130 changes: 69 additions & 61 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,54 @@
import { useSafeAppsSDK } from "@gnosis.pm/safe-apps-react-sdk";
import { GenericModal, Icon, Loader, Text, Title, Divider, Button } from "@gnosis.pm/safe-react-components";
import { Fab } from "@material-ui/core";
import { BaseTransaction } from "@gnosis.pm/safe-apps-sdk";
import { Button, Card, Divider, Loader, Text } from "@gnosis.pm/safe-react-components";
import { setUseWhatChange } from "@simbathesailor/use-what-changed";
import React, { useState } from "react";
import React, { useCallback, useState } from "react";
import styled from "styled-components";

import { CSVForm } from "./components/CSVForm";
import { FAQModal } from "./components/FAQModal";
import { Header } from "./components/Header";
import { Summary } from "./components/Summary";
import { CSVForm } from "./components/assets/CSVForm";
import { useTokenList, networkMap } from "./hooks/token";
import { AssetTransfer, CollectibleTransfer, Transfer } from "./parser/csvParser";
import { buildAssetTransfers, buildCollectibleTransfers } from "./transfers/transfers";

setUseWhatChange(process.env.NODE_ENV === "development");

const App: React.FC = () => {
const { isLoading } = useTokenList();
const { safe } = useSafeAppsSDK();
const [showHelp, setShowHelp] = useState(false);
const [csvText, setCsvText] = useState<string>("token_type,token_address,receiver,value,id");
const [tokenTransfers, setTokenTransfers] = useState<Transfer[]>([]);

const [submitting, setSubmitting] = useState(false);
const [parsing, setParsing] = useState(false);
const { sdk } = useSafeAppsSDK();

const assetTransfers = tokenTransfers.filter(
(transfer) => transfer.token_type === "erc20" || transfer.token_type === "native",
) as AssetTransfer[];
const collectibleTransfers = tokenTransfers.filter(
(transfer) => transfer.token_type === "erc1155" || transfer.token_type === "erc721",
) as CollectibleTransfer[];

const submitTx = useCallback(async () => {
setSubmitting(true);
try {
const txs: BaseTransaction[] = [];
txs.push(...buildAssetTransfers(assetTransfers));
txs.push(...buildCollectibleTransfers(collectibleTransfers));

console.log(`Encoded ${txs.length} transfers.`);
const sendTxResponse = await sdk.txs.send({ txs });
const safeTx = await sdk.txs.getBySafeTxHash(sendTxResponse.safeTxHash);
console.log({ safeTx });
} catch (e) {
console.error(e);
}
setSubmitting(false);
}, [assetTransfers, collectibleTransfers, sdk.txs]);

return (
<Container>
<Header />
Expand All @@ -26,67 +60,41 @@ const App: React.FC = () => {
<Text size={"lg"}>Loading Tokenlist...</Text>
</>
) : (
<CSVForm />
<Card className="cardWithCustomShadow">
<CSVForm
updateCsvContent={setCsvText}
csvContent={csvText}
updateTransferTable={setTokenTransfers}
setParsing={setParsing}
/>
<Divider />
<Summary assetTransfers={assetTransfers} collectibleTransfers={collectibleTransfers} />
{submitting ? (
<>
<Loader size="md" />
<br />
<Button size="lg" color="secondary" onClick={() => setSubmitting(false)}>
Cancel
</Button>
</>
) : (
<Button
style={{ alignSelf: "flex-start", marginTop: 16, marginBottom: 16 }}
size="lg"
color="primary"
onClick={submitTx}
disabled={parsing || tokenTransfers.length + collectibleTransfers.length === 0}
>
{parsing ? <Loader size="sm" color="primaryLight" /> : "Submit"}
</Button>
)}
</Card>
)}
</>
) : (
<Text size={"xl"}>Network with chainId {safe.chainId} not yet supported.</Text>
)}
<Fab
variant="extended"
size="small"
style={{ position: "absolute", top: 24, right: 24, textTransform: "none" }}
onClick={() => setShowHelp(true)}
>
<Icon size="md" type="question" />
<Text size="xl">Help</Text>
</Fab>
{showHelp && (
<GenericModal
onClose={() => setShowHelp(false)}
title={<Title size="lg">How to use the CSV Airdrop Gnosis App</Title>}
body={
<div>
<Title size="md" strong>
Preparing a Transfer File
</Title>
<Text size="lg">
Transfer files are expected to be in CSV format with the following required columns:
<ul>
<li>
<code>receiver</code>: Ethereum address of transfer receiver.
</li>
<li>
<code>token_address</code>: Ethereum address of ERC20 token to be transferred.
</li>
<li>
<code>amount</code>: the amount of token to be transferred.
</li>
</ul>
<p>
<b>
Important: The CSV file has to use "," as a separator and the header row always has to be provided
as the first row and include the described column names.
</b>
</p>
</Text>
<Divider />
<Title size="md" strong>
Native Token Transfers
</Title>
<Text size="lg">
Since native tokens do not have a token address, you must leave the <code>token_address</code> column
blank for native transfers.
</Text>
</div>
}
footer={
<Button size="md" color="secondary" onClick={() => setShowHelp(false)}>
Close
</Button>
}
></GenericModal>
)}
<FAQModal />
</Container>
);
};
Expand Down
11 changes: 11 additions & 0 deletions src/GlobalStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ const GlobalStyle = createGlobalStyle`
.MuiPaper-elevation3 {
box-shadow: 0px 3px 3px -2px #F7F5F5,0px 3px 4px 0px #F7F5F5,0px 1px 8px 0px #F7F5F5 !important;
}

.navLabel {
flex: 1;
}

.tableContainer {
display: flex;
flex-direction: horizontal;
gap: 16px;
width: 100%;
}
`;

export default GlobalStyle;
Loading