Skip to content

Commit ec27cc5

Browse files
0xKurthussmartinez
andauthored
Feat/donate to gitcoin (#3801)
* beginning * improvements * updates * chore: refactor ViewCartPage splitting components and fixing hook dependencies * wip * updates * updates * updates * gitcoin donations * update left hook 👀 * rm logs * add addresses and filter by supported chains --------- Co-authored-by: Huss Martinez <husse.dev@gmail.com>
1 parent f605cf7 commit ec27cc5

File tree

17 files changed

+1244
-276
lines changed

17 files changed

+1244
-276
lines changed

lefthook.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,3 @@ pre-push:
4141
run: pnpm turbo run typecheck
4242
build:
4343
run: pnpm turbo run build
44-
test:
45-
run: pnpm turbo run test --concurrency=50%

packages/common/src/allo/backends/allo-v2.ts

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,21 @@ import {
2323
RoundApplicationAnswers,
2424
RoundCategory,
2525
} from "data-layer";
26-
import { Abi, Address, Hex, getAddress, zeroAddress } from "viem";
26+
import {
27+
Abi,
28+
Address,
29+
Hex,
30+
encodeAbiParameters,
31+
getAddress,
32+
parseAbiParameters,
33+
zeroAddress,
34+
} from "viem";
2735
import { AnyJson } from "../..";
28-
import { UpdateRoundParams, MatchingStatsData } from "../../types";
36+
import {
37+
UpdateRoundParams,
38+
MatchingStatsData,
39+
DirectAllocation,
40+
} from "../../types";
2941
import { Allo, AlloError, AlloOperation, CreateRoundArguments } from "../allo";
3042
import {
3143
Result,
@@ -121,7 +133,8 @@ export class AlloV2 implements Allo {
121133
sig: PermitSignature;
122134
deadline: number;
123135
nonce: bigint;
124-
}
136+
},
137+
directAllocation?: DirectAllocation
125138
) {
126139
let tx: Result<Hex>;
127140
const mrcAddress = getChainById(chainId).contracts.multiRoundCheckout;
@@ -132,7 +145,22 @@ export class AlloV2 implements Allo {
132145
});
133146

134147
const data = Object.values(groupedVotes).flat();
148+
const amounts = Object.values(groupedAmounts);
135149

150+
if (directAllocation) {
151+
poolIds.push(directAllocation.poolId);
152+
amounts.push(directAllocation?.amount ?? BigInt(0));
153+
const encoded: `0x${string}` = encodeAbiParameters(
154+
parseAbiParameters("address,uint256,address,uint256"),
155+
[
156+
directAllocation.recipient,
157+
directAllocation.amount,
158+
directAllocation.tokenAddress,
159+
directAllocation.nonce,
160+
]
161+
);
162+
data.push(encoded);
163+
}
136164
/* decide which function to use based on whether token is native, permit-compatible or DAI */
137165
if (token.address === zeroAddress || token.address === NATIVE) {
138166
tx = await sendTransaction(
@@ -141,7 +169,7 @@ export class AlloV2 implements Allo {
141169
address: mrcAddress,
142170
abi: MRC_ABI,
143171
functionName: "allocate",
144-
args: [poolIds, Object.values(groupedAmounts), data],
172+
args: [poolIds, amounts, data],
145173
value: nativeTokenAmount,
146174
},
147175
this.chainId
@@ -157,8 +185,8 @@ export class AlloV2 implements Allo {
157185
args: [
158186
data,
159187
poolIds,
160-
Object.values(groupedAmounts),
161-
Object.values(groupedAmounts).reduce((acc, b) => acc + b),
188+
amounts,
189+
amounts.reduce((acc, b) => acc + b),
162190
token.address as Hex,
163191
BigInt(permit.deadline ?? Number.MAX_SAFE_INTEGER),
164192
permit.nonce,
@@ -179,8 +207,8 @@ export class AlloV2 implements Allo {
179207
args: [
180208
data,
181209
poolIds,
182-
Object.values(groupedAmounts),
183-
Object.values(groupedAmounts).reduce((acc, b) => acc + b),
210+
amounts,
211+
amounts.reduce((acc, b) => acc + b),
184212
token.address as Hex,
185213
BigInt(permit.deadline ?? Number.MAX_SAFE_INTEGER),
186214
permit.sig.v,

packages/common/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export * from "./markdown";
1414
export * from "./allo/common";
1515
export * from "./allo/application";
1616
export * from "./payoutTokens";
17+
export * from "./types";
1718

1819
export * from "./services/passport/passportCredentials";
1920
export { PassportVerifierWithExpiration } from "./services/passport/credentialVerifier";

packages/common/src/types.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Round } from "data-layer";
22
import { AnyJson } from ".";
33
import { BigNumber } from "ethers";
4+
import { Hex } from "viem";
45

56
export type CreateRoundData = {
67
roundMetadataWithProgramContractAddress: Round["roundMetadata"];
@@ -107,3 +108,12 @@ export type PriceSource = {
107108
chainId: number;
108109
address: `0x${string}`;
109110
};
111+
112+
export interface DirectAllocation {
113+
chainId: number;
114+
tokenAddress: Hex;
115+
poolId: string;
116+
amount: bigint;
117+
recipient: Hex;
118+
nonce: bigint;
119+
}

packages/grant-explorer/src/checkoutStore.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { devtools } from "zustand/middleware";
44
import { CartProject, ProgressStatus } from "./features/api/types";
55
import {
66
AlloV2,
7+
DirectAllocation,
78
createEthersTransactionSender,
89
createPinataIpfsUploader,
910
createWaitForIndexerSyncTo,
@@ -32,13 +33,13 @@ import { groupBy, uniq } from "lodash-es";
3233
import { getEnabledChains } from "./app/chainConfig";
3334
import { getPermitType } from "common/dist/allo/voting";
3435
import { getConfig } from "common/src/config";
35-
import { DataLayer } from "data-layer";
3636
import { getEthersProvider, getEthersSigner } from "./app/wagmi";
3737
import { Connector } from "wagmi";
3838

3939
type ChainMap<T> = Record<number, T>;
4040

4141
const isV2 = getConfig().allo.version === "allo-v2";
42+
4243
interface CheckoutState {
4344
permitStatus: ChainMap<ProgressStatus>;
4445
setPermitStatusForChain: (
@@ -62,7 +63,7 @@ interface CheckoutState {
6263
chainsToCheckout: { chainId: number; permitDeadline: number }[],
6364
walletClient: WalletClient,
6465
connector: Connector,
65-
dataLayer: DataLayer
66+
directAllocation?: DirectAllocation
6667
) => Promise<void>;
6768
getCheckedOutProjects: () => CartProject[];
6869
checkedOutProjects: CartProject[];
@@ -109,10 +110,12 @@ export const useCheckoutStore = create<CheckoutState>()(
109110
checkout: async (
110111
chainsToCheckout: { chainId: number; permitDeadline: number }[],
111112
walletClient: WalletClient,
112-
connector: Connector
113+
connector: Connector,
114+
directAllocation?: DirectAllocation
113115
) => {
114116
const userAddress = walletClient.account?.address;
115117
const chainIdsToCheckOut = chainsToCheckout.map((chain) => chain.chainId);
118+
const hasDirectAllocation = !!directAllocation;
116119
get().setChainsToCheckout(
117120
uniq([...get().chainsToCheckout, ...chainIdsToCheckOut])
118121
);
@@ -151,6 +154,8 @@ export const useCheckoutStore = create<CheckoutState>()(
151154
const chainId = currentChain.chainId;
152155
const deadline = currentChain.permitDeadline;
153156
const donations = projectsByChain[chainId];
157+
const isDirectAllocation =
158+
hasDirectAllocation && directAllocation.chainId === chainId;
154159

155160
set({
156161
currentChainBeingCheckedOut: chainId,
@@ -205,7 +210,9 @@ export const useCheckoutStore = create<CheckoutState>()(
205210
tokenName = "cUSD";
206211
sig = await signPermit2612({
207212
walletClient: walletClient,
208-
value: totalDonationPerChain[chainId],
213+
value: isDirectAllocation
214+
? totalDonationPerChain[chainId] + directAllocation.amount
215+
: totalDonationPerChain[chainId],
209216
spenderAddress: chain.contracts.multiRoundCheckout,
210217
nonce,
211218
chainId,
@@ -302,7 +309,8 @@ export const useCheckoutStore = create<CheckoutState>()(
302309
deadline,
303310
nonce: nonce!,
304311
}
305-
: undefined
312+
: undefined,
313+
isDirectAllocation ? directAllocation : undefined
306314
);
307315

308316
if (receipt.status === "reverted") {

packages/grant-explorer/src/features/common/ConfirmationModal.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ interface ModalProps {
1313
children?: ReactNode;
1414
modalStyle?: "wide" | "normal";
1515
disabled?: boolean;
16+
totalDonationAcrossChainsInUSD?: number;
1617
}
1718

1819
export default function ConfirmationModal({
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { useCallback } from "react";
2+
import { Checkbox } from "@chakra-ui/react";
3+
import { useDonateToGitcoin } from "../DonateToGitcoinContext";
4+
import React from "react";
5+
import { DonateToGitcoinContent } from "./components/DonateToGitcoinContent";
6+
7+
export type DonationDetails = {
8+
chainId: number;
9+
tokenAddress: string;
10+
amount: string;
11+
};
12+
13+
type DonateToGitcoinProps = {
14+
totalAmount: string;
15+
totalDonationsByChain: {
16+
[chainId: number]: number;
17+
};
18+
};
19+
20+
export const DonateToGitcoin = React.memo(
21+
({ totalAmount, totalDonationsByChain }: DonateToGitcoinProps) => {
22+
const { isEnabled, setIsEnabled } = useDonateToGitcoin();
23+
24+
const handleCheckboxChange = useCallback(
25+
(value: React.ChangeEvent<HTMLInputElement>) => {
26+
setIsEnabled(value.target.checked);
27+
},
28+
[setIsEnabled]
29+
);
30+
31+
return (
32+
<div className="flex flex-col items-start gap-[9px] p-[9px] border-[0.75px] border-[#E3E3E3] rounded-[7.5px] bg-[#F5F4FE]">
33+
<div>
34+
<p className="flex items-center">
35+
<Checkbox
36+
className={`mr-2 ${!isEnabled ? "opacity-50" : ""}`}
37+
border={"1px"}
38+
borderRadius={"4px"}
39+
colorScheme="whiteAlpha"
40+
iconColor="black"
41+
size="lg"
42+
isChecked={isEnabled}
43+
onChange={handleCheckboxChange}
44+
/>
45+
<img
46+
className="inline mr-2 w-5 h-5"
47+
alt="Gitcoin"
48+
src="/logos/gitcoin-gist-logo.svg"
49+
/>
50+
<span className="text-[15px] font-medium font-inter text-black">
51+
Donate to Gitcoin
52+
</span>
53+
</p>
54+
</div>
55+
56+
<DonateToGitcoinContent
57+
totalAmount={totalAmount}
58+
totalDonationsByChain={totalDonationsByChain}
59+
/>
60+
</div>
61+
);
62+
},
63+
(prevProps, nextProps) => prevProps.totalAmount === nextProps.totalAmount
64+
);

0 commit comments

Comments
 (0)