diff --git a/.gitignore b/.gitignore
index 8301e83..93d68b6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,4 +22,5 @@ node_modules
# cli
dist
.vercel
+*.zip
*.gz
diff --git a/donations/build/DonationContract/DonationContract.wasm b/donations/build/DonationContract/DonationContract.wasm
new file mode 100644
index 0000000..a7c9181
Binary files /dev/null and b/donations/build/DonationContract/DonationContract.wasm differ
diff --git a/donations/build/DonationContract/abis/DonationContract.json b/donations/build/DonationContract/abis/DonationContract.json
new file mode 100644
index 0000000..1154ea7
--- /dev/null
+++ b/donations/build/DonationContract/abis/DonationContract.json
@@ -0,0 +1,350 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_batchSwapContract",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "_swapRouter",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "campaignId",
+ "type": "uint256"
+ }
+ ],
+ "name": "CampaignClosed",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "campaignId",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "campaignOwner",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "string",
+ "name": "campaignName",
+ "type": "string"
+ }
+ ],
+ "name": "CampaignCreated",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "campaignId",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "donor",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "address[]",
+ "name": "tokenAddresses",
+ "type": "address[]"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256[]",
+ "name": "tokenAmounts",
+ "type": "uint256[]"
+ }
+ ],
+ "name": "DonationReceived",
+ "type": "event"
+ },
+ {
+ "inputs": [],
+ "name": "MAX_PRICE_LIMIT",
+ "outputs": [
+ {
+ "internalType": "uint160",
+ "name": "",
+ "type": "uint160"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "MIN_PRICE_LIMIT",
+ "outputs": [
+ {
+ "internalType": "uint160",
+ "name": "",
+ "type": "uint160"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "batchSwapRouter",
+ "outputs": [
+ {
+ "internalType": "contract PoolBatchSwapTest",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "campaigns",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "campaignOwner",
+ "type": "address"
+ },
+ {
+ "internalType": "bool",
+ "name": "isLive",
+ "type": "bool"
+ },
+ {
+ "internalType": "string",
+ "name": "campaignName",
+ "type": "string"
+ },
+ {
+ "internalType": "uint256",
+ "name": "goalAmount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "address",
+ "name": "goalToken",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_campaignId",
+ "type": "uint256"
+ }
+ ],
+ "name": "closeCampaign",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "_campaignName",
+ "type": "string"
+ },
+ {
+ "internalType": "address",
+ "name": "goalToken",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "goalAmount",
+ "type": "uint256"
+ }
+ ],
+ "name": "createCampaign",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address[]",
+ "name": "_tokenAddresses",
+ "type": "address[]"
+ },
+ {
+ "internalType": "uint256[]",
+ "name": "_tokenAmounts",
+ "type": "uint256[]"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_campaignId",
+ "type": "uint256"
+ }
+ ],
+ "name": "donate",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ {
+ "internalType": "Currency",
+ "name": "currency0",
+ "type": "address"
+ },
+ {
+ "internalType": "Currency",
+ "name": "currency1",
+ "type": "address"
+ },
+ {
+ "internalType": "uint24",
+ "name": "fee",
+ "type": "uint24"
+ },
+ {
+ "internalType": "int24",
+ "name": "tickSpacing",
+ "type": "int24"
+ },
+ {
+ "internalType": "contract IHooks",
+ "name": "hooks",
+ "type": "address"
+ }
+ ],
+ "internalType": "struct PoolKey[]",
+ "name": "keys",
+ "type": "tuple[]"
+ },
+ {
+ "internalType": "int256[]",
+ "name": "amountsSpecified",
+ "type": "int256[]"
+ },
+ {
+ "internalType": "bool[]",
+ "name": "zeroForOnes",
+ "type": "bool[]"
+ }
+ ],
+ "name": "makeBatchSwap",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ {
+ "internalType": "Currency",
+ "name": "currency0",
+ "type": "address"
+ },
+ {
+ "internalType": "Currency",
+ "name": "currency1",
+ "type": "address"
+ },
+ {
+ "internalType": "uint24",
+ "name": "fee",
+ "type": "uint24"
+ },
+ {
+ "internalType": "int24",
+ "name": "tickSpacing",
+ "type": "int24"
+ },
+ {
+ "internalType": "contract IHooks",
+ "name": "hooks",
+ "type": "address"
+ }
+ ],
+ "internalType": "struct PoolKey",
+ "name": "key",
+ "type": "tuple"
+ },
+ {
+ "internalType": "int256",
+ "name": "amountSpecified",
+ "type": "int256"
+ },
+ {
+ "internalType": "bool",
+ "name": "zeroForOne",
+ "type": "bool"
+ }
+ ],
+ "name": "makeSwap",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "nextCampaignId",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "swapRouter",
+ "outputs": [
+ {
+ "internalType": "contract PoolSwapTest",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ }
+]
\ No newline at end of file
diff --git a/donations/build/schema.graphql b/donations/build/schema.graphql
new file mode 100644
index 0000000..1defba6
--- /dev/null
+++ b/donations/build/schema.graphql
@@ -0,0 +1,28 @@
+type CampaignClosed @entity(immutable: true) {
+ id: Bytes!
+ campaignId: BigInt! # uint256
+ blockNumber: BigInt!
+ blockTimestamp: BigInt!
+ transactionHash: Bytes!
+}
+
+type CampaignCreated @entity(immutable: true) {
+ id: Bytes!
+ campaignId: BigInt! # uint256
+ campaignOwner: Bytes! # address
+ campaignName: String! # string
+ blockNumber: BigInt!
+ blockTimestamp: BigInt!
+ transactionHash: Bytes!
+}
+
+type DonationReceived @entity(immutable: true) {
+ id: Bytes!
+ campaignId: BigInt! # uint256
+ donor: Bytes! # address
+ # tokenAddresses: [Bytes!]! # address[]
+ tokenAmounts: [BigInt!]! # uint256[]
+ blockNumber: BigInt!
+ blockTimestamp: BigInt!
+ transactionHash: Bytes!
+}
diff --git a/donations/build/subgraph.yaml b/donations/build/subgraph.yaml
new file mode 100644
index 0000000..15660a0
--- /dev/null
+++ b/donations/build/subgraph.yaml
@@ -0,0 +1,32 @@
+specVersion: 1.0.0
+indexerHints:
+ prune: auto
+schema:
+ file: schema.graphql
+dataSources:
+ - kind: ethereum
+ name: DonationContract
+ network: sepolia
+ source:
+ address: "0x015c05c99467aca9eb8313bFe836c75067C01ce8"
+ abi: DonationContract
+ startBlock: 6019786
+ mapping:
+ kind: ethereum/events
+ apiVersion: 0.0.7
+ language: wasm/assemblyscript
+ entities:
+ - CampaignClosed
+ - CampaignCreated
+ - DonationReceived
+ abis:
+ - name: DonationContract
+ file: DonationContract\abis\DonationContract.json
+ eventHandlers:
+ - event: CampaignClosed(uint256)
+ handler: handleCampaignClosed
+ - event: CampaignCreated(uint256,address,string)
+ handler: handleCampaignCreated
+ - event: DonationReceived(uint256,address,address[],uint256[])
+ handler: handleDonationReceived
+ file: DonationContract\DonationContract.wasm
diff --git a/donations/generated/DonationContract/DonationContract.ts b/donations/generated/DonationContract/DonationContract.ts
new file mode 100644
index 0000000..efc04d9
--- /dev/null
+++ b/donations/generated/DonationContract/DonationContract.ts
@@ -0,0 +1,547 @@
+// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+
+import {
+ ethereum,
+ JSONValue,
+ TypedMap,
+ Entity,
+ Bytes,
+ Address,
+ BigInt,
+} from "@graphprotocol/graph-ts";
+
+export class CampaignClosed extends ethereum.Event {
+ get params(): CampaignClosed__Params {
+ return new CampaignClosed__Params(this);
+ }
+}
+
+export class CampaignClosed__Params {
+ _event: CampaignClosed;
+
+ constructor(event: CampaignClosed) {
+ this._event = event;
+ }
+
+ get campaignId(): BigInt {
+ return this._event.parameters[0].value.toBigInt();
+ }
+}
+
+export class CampaignCreated extends ethereum.Event {
+ get params(): CampaignCreated__Params {
+ return new CampaignCreated__Params(this);
+ }
+}
+
+export class CampaignCreated__Params {
+ _event: CampaignCreated;
+
+ constructor(event: CampaignCreated) {
+ this._event = event;
+ }
+
+ get campaignId(): BigInt {
+ return this._event.parameters[0].value.toBigInt();
+ }
+
+ get campaignOwner(): Address {
+ return this._event.parameters[1].value.toAddress();
+ }
+
+ get campaignName(): string {
+ return this._event.parameters[2].value.toString();
+ }
+}
+
+export class DonationReceived extends ethereum.Event {
+ get params(): DonationReceived__Params {
+ return new DonationReceived__Params(this);
+ }
+}
+
+export class DonationReceived__Params {
+ _event: DonationReceived;
+
+ constructor(event: DonationReceived) {
+ this._event = event;
+ }
+
+ get campaignId(): BigInt {
+ return this._event.parameters[0].value.toBigInt();
+ }
+
+ get donor(): Address {
+ return this._event.parameters[1].value.toAddress();
+ }
+
+ get tokenAddresses(): Array
{
+ return this._event.parameters[2].value.toAddressArray();
+ }
+
+ get tokenAmounts(): Array {
+ return this._event.parameters[3].value.toBigIntArray();
+ }
+}
+
+export class DonationContract__campaignsResult {
+ value0: Address;
+ value1: boolean;
+ value2: string;
+ value3: BigInt;
+ value4: Address;
+
+ constructor(
+ value0: Address,
+ value1: boolean,
+ value2: string,
+ value3: BigInt,
+ value4: Address,
+ ) {
+ this.value0 = value0;
+ this.value1 = value1;
+ this.value2 = value2;
+ this.value3 = value3;
+ this.value4 = value4;
+ }
+
+ toMap(): TypedMap {
+ let map = new TypedMap();
+ map.set("value0", ethereum.Value.fromAddress(this.value0));
+ map.set("value1", ethereum.Value.fromBoolean(this.value1));
+ map.set("value2", ethereum.Value.fromString(this.value2));
+ map.set("value3", ethereum.Value.fromUnsignedBigInt(this.value3));
+ map.set("value4", ethereum.Value.fromAddress(this.value4));
+ return map;
+ }
+
+ getCampaignOwner(): Address {
+ return this.value0;
+ }
+
+ getIsLive(): boolean {
+ return this.value1;
+ }
+
+ getCampaignName(): string {
+ return this.value2;
+ }
+
+ getGoalAmount(): BigInt {
+ return this.value3;
+ }
+
+ getGoalToken(): Address {
+ return this.value4;
+ }
+}
+
+export class DonationContract extends ethereum.SmartContract {
+ static bind(address: Address): DonationContract {
+ return new DonationContract("DonationContract", address);
+ }
+
+ MAX_PRICE_LIMIT(): BigInt {
+ let result = super.call(
+ "MAX_PRICE_LIMIT",
+ "MAX_PRICE_LIMIT():(uint160)",
+ [],
+ );
+
+ return result[0].toBigInt();
+ }
+
+ try_MAX_PRICE_LIMIT(): ethereum.CallResult {
+ let result = super.tryCall(
+ "MAX_PRICE_LIMIT",
+ "MAX_PRICE_LIMIT():(uint160)",
+ [],
+ );
+ if (result.reverted) {
+ return new ethereum.CallResult();
+ }
+ let value = result.value;
+ return ethereum.CallResult.fromValue(value[0].toBigInt());
+ }
+
+ MIN_PRICE_LIMIT(): BigInt {
+ let result = super.call(
+ "MIN_PRICE_LIMIT",
+ "MIN_PRICE_LIMIT():(uint160)",
+ [],
+ );
+
+ return result[0].toBigInt();
+ }
+
+ try_MIN_PRICE_LIMIT(): ethereum.CallResult {
+ let result = super.tryCall(
+ "MIN_PRICE_LIMIT",
+ "MIN_PRICE_LIMIT():(uint160)",
+ [],
+ );
+ if (result.reverted) {
+ return new ethereum.CallResult();
+ }
+ let value = result.value;
+ return ethereum.CallResult.fromValue(value[0].toBigInt());
+ }
+
+ batchSwapRouter(): Address {
+ let result = super.call(
+ "batchSwapRouter",
+ "batchSwapRouter():(address)",
+ [],
+ );
+
+ return result[0].toAddress();
+ }
+
+ try_batchSwapRouter(): ethereum.CallResult {
+ let result = super.tryCall(
+ "batchSwapRouter",
+ "batchSwapRouter():(address)",
+ [],
+ );
+ if (result.reverted) {
+ return new ethereum.CallResult();
+ }
+ let value = result.value;
+ return ethereum.CallResult.fromValue(value[0].toAddress());
+ }
+
+ campaigns(param0: BigInt): DonationContract__campaignsResult {
+ let result = super.call(
+ "campaigns",
+ "campaigns(uint256):(address,bool,string,uint256,address)",
+ [ethereum.Value.fromUnsignedBigInt(param0)],
+ );
+
+ return new DonationContract__campaignsResult(
+ result[0].toAddress(),
+ result[1].toBoolean(),
+ result[2].toString(),
+ result[3].toBigInt(),
+ result[4].toAddress(),
+ );
+ }
+
+ try_campaigns(
+ param0: BigInt,
+ ): ethereum.CallResult {
+ let result = super.tryCall(
+ "campaigns",
+ "campaigns(uint256):(address,bool,string,uint256,address)",
+ [ethereum.Value.fromUnsignedBigInt(param0)],
+ );
+ if (result.reverted) {
+ return new ethereum.CallResult();
+ }
+ let value = result.value;
+ return ethereum.CallResult.fromValue(
+ new DonationContract__campaignsResult(
+ value[0].toAddress(),
+ value[1].toBoolean(),
+ value[2].toString(),
+ value[3].toBigInt(),
+ value[4].toAddress(),
+ ),
+ );
+ }
+
+ nextCampaignId(): BigInt {
+ let result = super.call("nextCampaignId", "nextCampaignId():(uint256)", []);
+
+ return result[0].toBigInt();
+ }
+
+ try_nextCampaignId(): ethereum.CallResult {
+ let result = super.tryCall(
+ "nextCampaignId",
+ "nextCampaignId():(uint256)",
+ [],
+ );
+ if (result.reverted) {
+ return new ethereum.CallResult();
+ }
+ let value = result.value;
+ return ethereum.CallResult.fromValue(value[0].toBigInt());
+ }
+
+ swapRouter(): Address {
+ let result = super.call("swapRouter", "swapRouter():(address)", []);
+
+ return result[0].toAddress();
+ }
+
+ try_swapRouter(): ethereum.CallResult {
+ let result = super.tryCall("swapRouter", "swapRouter():(address)", []);
+ if (result.reverted) {
+ return new ethereum.CallResult();
+ }
+ let value = result.value;
+ return ethereum.CallResult.fromValue(value[0].toAddress());
+ }
+}
+
+export class ConstructorCall extends ethereum.Call {
+ get inputs(): ConstructorCall__Inputs {
+ return new ConstructorCall__Inputs(this);
+ }
+
+ get outputs(): ConstructorCall__Outputs {
+ return new ConstructorCall__Outputs(this);
+ }
+}
+
+export class ConstructorCall__Inputs {
+ _call: ConstructorCall;
+
+ constructor(call: ConstructorCall) {
+ this._call = call;
+ }
+
+ get _batchSwapContract(): Address {
+ return this._call.inputValues[0].value.toAddress();
+ }
+
+ get _swapRouter(): Address {
+ return this._call.inputValues[1].value.toAddress();
+ }
+}
+
+export class ConstructorCall__Outputs {
+ _call: ConstructorCall;
+
+ constructor(call: ConstructorCall) {
+ this._call = call;
+ }
+}
+
+export class CloseCampaignCall extends ethereum.Call {
+ get inputs(): CloseCampaignCall__Inputs {
+ return new CloseCampaignCall__Inputs(this);
+ }
+
+ get outputs(): CloseCampaignCall__Outputs {
+ return new CloseCampaignCall__Outputs(this);
+ }
+}
+
+export class CloseCampaignCall__Inputs {
+ _call: CloseCampaignCall;
+
+ constructor(call: CloseCampaignCall) {
+ this._call = call;
+ }
+
+ get _campaignId(): BigInt {
+ return this._call.inputValues[0].value.toBigInt();
+ }
+}
+
+export class CloseCampaignCall__Outputs {
+ _call: CloseCampaignCall;
+
+ constructor(call: CloseCampaignCall) {
+ this._call = call;
+ }
+}
+
+export class CreateCampaignCall extends ethereum.Call {
+ get inputs(): CreateCampaignCall__Inputs {
+ return new CreateCampaignCall__Inputs(this);
+ }
+
+ get outputs(): CreateCampaignCall__Outputs {
+ return new CreateCampaignCall__Outputs(this);
+ }
+}
+
+export class CreateCampaignCall__Inputs {
+ _call: CreateCampaignCall;
+
+ constructor(call: CreateCampaignCall) {
+ this._call = call;
+ }
+
+ get _campaignName(): string {
+ return this._call.inputValues[0].value.toString();
+ }
+
+ get goalToken(): Address {
+ return this._call.inputValues[1].value.toAddress();
+ }
+
+ get goalAmount(): BigInt {
+ return this._call.inputValues[2].value.toBigInt();
+ }
+}
+
+export class CreateCampaignCall__Outputs {
+ _call: CreateCampaignCall;
+
+ constructor(call: CreateCampaignCall) {
+ this._call = call;
+ }
+}
+
+export class DonateCall extends ethereum.Call {
+ get inputs(): DonateCall__Inputs {
+ return new DonateCall__Inputs(this);
+ }
+
+ get outputs(): DonateCall__Outputs {
+ return new DonateCall__Outputs(this);
+ }
+}
+
+export class DonateCall__Inputs {
+ _call: DonateCall;
+
+ constructor(call: DonateCall) {
+ this._call = call;
+ }
+
+ get _tokenAddresses(): Array {
+ return this._call.inputValues[0].value.toAddressArray();
+ }
+
+ get _tokenAmounts(): Array {
+ return this._call.inputValues[1].value.toBigIntArray();
+ }
+
+ get _campaignId(): BigInt {
+ return this._call.inputValues[2].value.toBigInt();
+ }
+}
+
+export class DonateCall__Outputs {
+ _call: DonateCall;
+
+ constructor(call: DonateCall) {
+ this._call = call;
+ }
+}
+
+export class MakeBatchSwapCall extends ethereum.Call {
+ get inputs(): MakeBatchSwapCall__Inputs {
+ return new MakeBatchSwapCall__Inputs(this);
+ }
+
+ get outputs(): MakeBatchSwapCall__Outputs {
+ return new MakeBatchSwapCall__Outputs(this);
+ }
+}
+
+export class MakeBatchSwapCall__Inputs {
+ _call: MakeBatchSwapCall;
+
+ constructor(call: MakeBatchSwapCall) {
+ this._call = call;
+ }
+
+ get keys(): Array {
+ return this._call.inputValues[0].value.toTupleArray();
+ }
+
+ get amountsSpecified(): Array {
+ return this._call.inputValues[1].value.toBigIntArray();
+ }
+
+ get zeroForOnes(): Array {
+ return this._call.inputValues[2].value.toBooleanArray();
+ }
+}
+
+export class MakeBatchSwapCall__Outputs {
+ _call: MakeBatchSwapCall;
+
+ constructor(call: MakeBatchSwapCall) {
+ this._call = call;
+ }
+}
+
+export class MakeBatchSwapCallKeysStruct extends ethereum.Tuple {
+ get currency0(): Address {
+ return this[0].toAddress();
+ }
+
+ get currency1(): Address {
+ return this[1].toAddress();
+ }
+
+ get fee(): i32 {
+ return this[2].toI32();
+ }
+
+ get tickSpacing(): i32 {
+ return this[3].toI32();
+ }
+
+ get hooks(): Address {
+ return this[4].toAddress();
+ }
+}
+
+export class MakeSwapCall extends ethereum.Call {
+ get inputs(): MakeSwapCall__Inputs {
+ return new MakeSwapCall__Inputs(this);
+ }
+
+ get outputs(): MakeSwapCall__Outputs {
+ return new MakeSwapCall__Outputs(this);
+ }
+}
+
+export class MakeSwapCall__Inputs {
+ _call: MakeSwapCall;
+
+ constructor(call: MakeSwapCall) {
+ this._call = call;
+ }
+
+ get key(): MakeSwapCallKeyStruct {
+ return changetype(
+ this._call.inputValues[0].value.toTuple(),
+ );
+ }
+
+ get amountSpecified(): BigInt {
+ return this._call.inputValues[1].value.toBigInt();
+ }
+
+ get zeroForOne(): boolean {
+ return this._call.inputValues[2].value.toBoolean();
+ }
+}
+
+export class MakeSwapCall__Outputs {
+ _call: MakeSwapCall;
+
+ constructor(call: MakeSwapCall) {
+ this._call = call;
+ }
+}
+
+export class MakeSwapCallKeyStruct extends ethereum.Tuple {
+ get currency0(): Address {
+ return this[0].toAddress();
+ }
+
+ get currency1(): Address {
+ return this[1].toAddress();
+ }
+
+ get fee(): i32 {
+ return this[2].toI32();
+ }
+
+ get tickSpacing(): i32 {
+ return this[3].toI32();
+ }
+
+ get hooks(): Address {
+ return this[4].toAddress();
+ }
+}
diff --git a/donations/generated/schema.ts b/donations/generated/schema.ts
new file mode 100644
index 0000000..765c51e
--- /dev/null
+++ b/donations/generated/schema.ts
@@ -0,0 +1,352 @@
+// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+
+import {
+ TypedMap,
+ Entity,
+ Value,
+ ValueKind,
+ store,
+ Bytes,
+ BigInt,
+ BigDecimal,
+} from "@graphprotocol/graph-ts";
+
+export class CampaignClosed extends Entity {
+ constructor(id: Bytes) {
+ super();
+ this.set("id", Value.fromBytes(id));
+ }
+
+ save(): void {
+ let id = this.get("id");
+ assert(id != null, "Cannot save CampaignClosed entity without an ID");
+ if (id) {
+ assert(
+ id.kind == ValueKind.BYTES,
+ `Entities of type CampaignClosed must have an ID of type Bytes but the id '${id.displayData()}' is of type ${id.displayKind()}`,
+ );
+ store.set("CampaignClosed", id.toBytes().toHexString(), this);
+ }
+ }
+
+ static loadInBlock(id: Bytes): CampaignClosed | null {
+ return changetype(
+ store.get_in_block("CampaignClosed", id.toHexString()),
+ );
+ }
+
+ static load(id: Bytes): CampaignClosed | null {
+ return changetype(
+ store.get("CampaignClosed", id.toHexString()),
+ );
+ }
+
+ get id(): Bytes {
+ let value = this.get("id");
+ if (!value || value.kind == ValueKind.NULL) {
+ throw new Error("Cannot return null for a required field.");
+ } else {
+ return value.toBytes();
+ }
+ }
+
+ set id(value: Bytes) {
+ this.set("id", Value.fromBytes(value));
+ }
+
+ get campaignId(): BigInt {
+ let value = this.get("campaignId");
+ if (!value || value.kind == ValueKind.NULL) {
+ throw new Error("Cannot return null for a required field.");
+ } else {
+ return value.toBigInt();
+ }
+ }
+
+ set campaignId(value: BigInt) {
+ this.set("campaignId", Value.fromBigInt(value));
+ }
+
+ get blockNumber(): BigInt {
+ let value = this.get("blockNumber");
+ if (!value || value.kind == ValueKind.NULL) {
+ throw new Error("Cannot return null for a required field.");
+ } else {
+ return value.toBigInt();
+ }
+ }
+
+ set blockNumber(value: BigInt) {
+ this.set("blockNumber", Value.fromBigInt(value));
+ }
+
+ get blockTimestamp(): BigInt {
+ let value = this.get("blockTimestamp");
+ if (!value || value.kind == ValueKind.NULL) {
+ throw new Error("Cannot return null for a required field.");
+ } else {
+ return value.toBigInt();
+ }
+ }
+
+ set blockTimestamp(value: BigInt) {
+ this.set("blockTimestamp", Value.fromBigInt(value));
+ }
+
+ get transactionHash(): Bytes {
+ let value = this.get("transactionHash");
+ if (!value || value.kind == ValueKind.NULL) {
+ throw new Error("Cannot return null for a required field.");
+ } else {
+ return value.toBytes();
+ }
+ }
+
+ set transactionHash(value: Bytes) {
+ this.set("transactionHash", Value.fromBytes(value));
+ }
+}
+
+export class CampaignCreated extends Entity {
+ constructor(id: Bytes) {
+ super();
+ this.set("id", Value.fromBytes(id));
+ }
+
+ save(): void {
+ let id = this.get("id");
+ assert(id != null, "Cannot save CampaignCreated entity without an ID");
+ if (id) {
+ assert(
+ id.kind == ValueKind.BYTES,
+ `Entities of type CampaignCreated must have an ID of type Bytes but the id '${id.displayData()}' is of type ${id.displayKind()}`,
+ );
+ store.set("CampaignCreated", id.toBytes().toHexString(), this);
+ }
+ }
+
+ static loadInBlock(id: Bytes): CampaignCreated | null {
+ return changetype(
+ store.get_in_block("CampaignCreated", id.toHexString()),
+ );
+ }
+
+ static load(id: Bytes): CampaignCreated | null {
+ return changetype(
+ store.get("CampaignCreated", id.toHexString()),
+ );
+ }
+
+ get id(): Bytes {
+ let value = this.get("id");
+ if (!value || value.kind == ValueKind.NULL) {
+ throw new Error("Cannot return null for a required field.");
+ } else {
+ return value.toBytes();
+ }
+ }
+
+ set id(value: Bytes) {
+ this.set("id", Value.fromBytes(value));
+ }
+
+ get campaignId(): BigInt {
+ let value = this.get("campaignId");
+ if (!value || value.kind == ValueKind.NULL) {
+ throw new Error("Cannot return null for a required field.");
+ } else {
+ return value.toBigInt();
+ }
+ }
+
+ set campaignId(value: BigInt) {
+ this.set("campaignId", Value.fromBigInt(value));
+ }
+
+ get campaignOwner(): Bytes {
+ let value = this.get("campaignOwner");
+ if (!value || value.kind == ValueKind.NULL) {
+ throw new Error("Cannot return null for a required field.");
+ } else {
+ return value.toBytes();
+ }
+ }
+
+ set campaignOwner(value: Bytes) {
+ this.set("campaignOwner", Value.fromBytes(value));
+ }
+
+ get campaignName(): string {
+ let value = this.get("campaignName");
+ if (!value || value.kind == ValueKind.NULL) {
+ throw new Error("Cannot return null for a required field.");
+ } else {
+ return value.toString();
+ }
+ }
+
+ set campaignName(value: string) {
+ this.set("campaignName", Value.fromString(value));
+ }
+
+ get blockNumber(): BigInt {
+ let value = this.get("blockNumber");
+ if (!value || value.kind == ValueKind.NULL) {
+ throw new Error("Cannot return null for a required field.");
+ } else {
+ return value.toBigInt();
+ }
+ }
+
+ set blockNumber(value: BigInt) {
+ this.set("blockNumber", Value.fromBigInt(value));
+ }
+
+ get blockTimestamp(): BigInt {
+ let value = this.get("blockTimestamp");
+ if (!value || value.kind == ValueKind.NULL) {
+ throw new Error("Cannot return null for a required field.");
+ } else {
+ return value.toBigInt();
+ }
+ }
+
+ set blockTimestamp(value: BigInt) {
+ this.set("blockTimestamp", Value.fromBigInt(value));
+ }
+
+ get transactionHash(): Bytes {
+ let value = this.get("transactionHash");
+ if (!value || value.kind == ValueKind.NULL) {
+ throw new Error("Cannot return null for a required field.");
+ } else {
+ return value.toBytes();
+ }
+ }
+
+ set transactionHash(value: Bytes) {
+ this.set("transactionHash", Value.fromBytes(value));
+ }
+}
+
+export class DonationReceived extends Entity {
+ constructor(id: Bytes) {
+ super();
+ this.set("id", Value.fromBytes(id));
+ }
+
+ save(): void {
+ let id = this.get("id");
+ assert(id != null, "Cannot save DonationReceived entity without an ID");
+ if (id) {
+ assert(
+ id.kind == ValueKind.BYTES,
+ `Entities of type DonationReceived must have an ID of type Bytes but the id '${id.displayData()}' is of type ${id.displayKind()}`,
+ );
+ store.set("DonationReceived", id.toBytes().toHexString(), this);
+ }
+ }
+
+ static loadInBlock(id: Bytes): DonationReceived | null {
+ return changetype(
+ store.get_in_block("DonationReceived", id.toHexString()),
+ );
+ }
+
+ static load(id: Bytes): DonationReceived | null {
+ return changetype(
+ store.get("DonationReceived", id.toHexString()),
+ );
+ }
+
+ get id(): Bytes {
+ let value = this.get("id");
+ if (!value || value.kind == ValueKind.NULL) {
+ throw new Error("Cannot return null for a required field.");
+ } else {
+ return value.toBytes();
+ }
+ }
+
+ set id(value: Bytes) {
+ this.set("id", Value.fromBytes(value));
+ }
+
+ get campaignId(): BigInt {
+ let value = this.get("campaignId");
+ if (!value || value.kind == ValueKind.NULL) {
+ throw new Error("Cannot return null for a required field.");
+ } else {
+ return value.toBigInt();
+ }
+ }
+
+ set campaignId(value: BigInt) {
+ this.set("campaignId", Value.fromBigInt(value));
+ }
+
+ get donor(): Bytes {
+ let value = this.get("donor");
+ if (!value || value.kind == ValueKind.NULL) {
+ throw new Error("Cannot return null for a required field.");
+ } else {
+ return value.toBytes();
+ }
+ }
+
+ set donor(value: Bytes) {
+ this.set("donor", Value.fromBytes(value));
+ }
+
+ get tokenAmounts(): Array {
+ let value = this.get("tokenAmounts");
+ if (!value || value.kind == ValueKind.NULL) {
+ throw new Error("Cannot return null for a required field.");
+ } else {
+ return value.toBigIntArray();
+ }
+ }
+
+ set tokenAmounts(value: Array) {
+ this.set("tokenAmounts", Value.fromBigIntArray(value));
+ }
+
+ get blockNumber(): BigInt {
+ let value = this.get("blockNumber");
+ if (!value || value.kind == ValueKind.NULL) {
+ throw new Error("Cannot return null for a required field.");
+ } else {
+ return value.toBigInt();
+ }
+ }
+
+ set blockNumber(value: BigInt) {
+ this.set("blockNumber", Value.fromBigInt(value));
+ }
+
+ get blockTimestamp(): BigInt {
+ let value = this.get("blockTimestamp");
+ if (!value || value.kind == ValueKind.NULL) {
+ throw new Error("Cannot return null for a required field.");
+ } else {
+ return value.toBigInt();
+ }
+ }
+
+ set blockTimestamp(value: BigInt) {
+ this.set("blockTimestamp", Value.fromBigInt(value));
+ }
+
+ get transactionHash(): Bytes {
+ let value = this.get("transactionHash");
+ if (!value || value.kind == ValueKind.NULL) {
+ throw new Error("Cannot return null for a required field.");
+ } else {
+ return value.toBytes();
+ }
+ }
+
+ set transactionHash(value: Bytes) {
+ this.set("transactionHash", Value.fromBytes(value));
+ }
+}
diff --git a/packages/nextjs/app/campaign/[id]/page.tsx b/packages/nextjs/app/campaign/[id]/page.tsx
index 83da4bb..b725274 100644
--- a/packages/nextjs/app/campaign/[id]/page.tsx
+++ b/packages/nextjs/app/campaign/[id]/page.tsx
@@ -11,7 +11,7 @@ const CampaignPage = ({ params }: { params: { id: string } }) => {
return (
<>
-
+
diff --git a/packages/nextjs/components/Campaigns.tsx b/packages/nextjs/components/Campaigns.tsx
index 0030a8d..4bfee7a 100644
--- a/packages/nextjs/components/Campaigns.tsx
+++ b/packages/nextjs/components/Campaigns.tsx
@@ -51,7 +51,7 @@ useEffect(() => {
return (
-
+
{campaigns.map((campaign) => (
40%
-
{donationGoal} USDC
+
{donationGoal} USDC
diff --git a/packages/nextjs/components/Header.tsx b/packages/nextjs/components/Header.tsx
index 9549367..d6055e5 100644
--- a/packages/nextjs/components/Header.tsx
+++ b/packages/nextjs/components/Header.tsx
@@ -96,12 +96,14 @@ export const Header = () => {
)}
-
-
-
-
-
Scaffold-ETH
-
Ethereum dev stack
+
+
diff --git a/packages/nextjs/components/Info.tsx b/packages/nextjs/components/Info.tsx
new file mode 100644
index 0000000..6234b9e
--- /dev/null
+++ b/packages/nextjs/components/Info.tsx
@@ -0,0 +1,145 @@
+"use client";
+
+import React from "react";
+
+/**
+ * Site header
+ */
+export const Info = () => {
+ return (
+
+
+ Unlike other donation dApp, this one accepts all kids of ERC20 tokens! All the memecoins, barely-worth-it
+ airdrops and random legacy coins usually just lie in out wallets. With Donation Appreciation, we can put them
+ all in one pile and have them do some good in the world.
+
+
How it works?
+
+
+
+ Onchain fundraisers can easily be created through our website.
+
+
+
+ Donors can see all the ERC20s in their wallet and donate multiple ones at once.
+
+
+
+
+ Once the pile of the donated tokens reaches the target value, either by price appreciation or donations, it
+ all gets converted to USDC and sent to the donation address.
+
+
+
+
+
What are the advantages
+
+
+
+ Enables donations in almost any ERC20 token
+
+
+
+ Small donation today could turn into a big one later
+
+
+
+ Fully permission-less onchain donations
+
+
+
+ Can solve tax implications of airdrops for the donors
+
+
+
+
Under the hood
+
+
+
+
+ The Graph subgraph was built to monitor the contracts of the fundraising campaigns
+
+
+
+
+
+ We have built a custom EigenLayer AVS to verify the target is reached before swapping all ERC20
+ tokens to $USDC
+
+
+
+
+
+ UniSwap hooks are used to swap all tokens for USDC, before transferring the USDC to the donation
+ recipient address
+
+
+
+
+ {/* Tech Used */}
+
+
Tech Used
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Built by at at */}
+
+
+
+
+
+
Source Code
+
+
+
+
+
+
+
+
+
Team
+
+
Built at
+
+ );
+};
diff --git a/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx b/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx
index 05273c2..0306232 100644
--- a/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx
+++ b/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx
@@ -8,6 +8,7 @@ import { Toaster } from "react-hot-toast";
import { WagmiProvider } from "wagmi";
import { Footer } from "~~/components/Footer";
import { Header } from "~~/components/Header";
+import { Info } from "~~/components/Info";
import { BlockieAvatar } from "~~/components/scaffold-eth";
import { ProgressBar } from "~~/components/scaffold-eth/ProgressBar";
import { useNativeCurrencyPrice } from "~~/hooks/scaffold-eth";
@@ -28,7 +29,8 @@ const ScaffoldEthApp = ({ children }: { children: React.ReactNode }) => {
<>
- {children}
+ {children}
+
diff --git a/packages/nextjs/public/DA-logo.png b/packages/nextjs/public/DA-logo.png
new file mode 100644
index 0000000..ab4dfed
Binary files /dev/null and b/packages/nextjs/public/DA-logo.png differ
diff --git a/packages/nextjs/public/eigen.jpg b/packages/nextjs/public/eigen.jpg
new file mode 100644
index 0000000..5f96f20
Binary files /dev/null and b/packages/nextjs/public/eigen.jpg differ
diff --git a/packages/nextjs/public/ethprague.jpeg b/packages/nextjs/public/ethprague.jpeg
new file mode 100644
index 0000000..043afd9
Binary files /dev/null and b/packages/nextjs/public/ethprague.jpeg differ
diff --git a/packages/nextjs/public/favicon.png b/packages/nextjs/public/favicon.png
index 4bef7f2..1dd4a38 100644
Binary files a/packages/nextjs/public/favicon.png and b/packages/nextjs/public/favicon.png differ
diff --git a/packages/nextjs/public/github.png b/packages/nextjs/public/github.png
new file mode 100644
index 0000000..3cad90e
Binary files /dev/null and b/packages/nextjs/public/github.png differ
diff --git a/packages/nextjs/public/the-graph.jpeg b/packages/nextjs/public/the-graph.jpeg
new file mode 100644
index 0000000..6b4c9ec
Binary files /dev/null and b/packages/nextjs/public/the-graph.jpeg differ
diff --git a/packages/nextjs/public/uniswap.jpeg b/packages/nextjs/public/uniswap.jpeg
new file mode 100644
index 0000000..d3b2db3
Binary files /dev/null and b/packages/nextjs/public/uniswap.jpeg differ
diff --git a/packages/nextjs/public/uniswap.png b/packages/nextjs/public/uniswap.png
new file mode 100644
index 0000000..81d00fa
Binary files /dev/null and b/packages/nextjs/public/uniswap.png differ
diff --git a/packages/nextjs/tailwind.config.js b/packages/nextjs/tailwind.config.js
index 9099dc5..04a8695 100644
--- a/packages/nextjs/tailwind.config.js
+++ b/packages/nextjs/tailwind.config.js
@@ -3,25 +3,26 @@ module.exports = {
content: ["./app/**/*.{js,ts,jsx,tsx}", "./components/**/*.{js,ts,jsx,tsx}", "./utils/**/*.{js,ts,jsx,tsx}"],
plugins: [require("daisyui")],
darkTheme: "dark",
+ // lightTheme: "lemonade",
darkMode: ["selector", "[data-theme='dark']"],
// DaisyUI theme colors
daisyui: {
themes: [
{
light: {
- primary: "#93BBFB",
+ primary: "#2DCD62",
"primary-content": "#212638",
- secondary: "#DAE8FF",
+ secondary: "#EAFBEF",
"secondary-content": "#212638",
- accent: "#93BBFB",
+ accent: "#2DCD62",
"accent-content": "#212638",
neutral: "#212638",
"neutral-content": "#ffffff",
"base-100": "#ffffff",
"base-200": "#f4f8ff",
- "base-300": "#DAE8FF",
+ "base-300": "#EAFBEF",
"base-content": "#212638",
- info: "#93BBFB",
+ info: "#2DCD62",
success: "#34EEB6",
warning: "#FFCF72",
error: "#FF8863",