Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions migration/1751934185752-CreateSwapTransactionTable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class CreateSwapTransactionTable1751934185752
implements MigrationInterface
{
public async up(queryRunner: QueryRunner): Promise<void> {
// Create the swap_transaction table
await queryRunner.query(`
CREATE TABLE "swap_transaction" (
"id" SERIAL NOT NULL,
"squidRequestId" character varying,
"firstTxHash" character varying NOT NULL,
"secondTxHash" character varying,
"fromChainId" integer NOT NULL,
"toChainId" integer NOT NULL,
"fromTokenAddress" character varying NOT NULL,
"toTokenAddress" character varying NOT NULL,
"fromAmount" double precision NOT NULL,
"toAmount" double precision,
"fromTokenSymbol" character varying NOT NULL,
"toTokenSymbol" character varying NOT NULL,
"status" character varying NOT NULL DEFAULT 'pending',
"metadata" jsonb,
"createdAt" TIMESTAMP NOT NULL DEFAULT now(),
"updatedAt" TIMESTAMP NOT NULL DEFAULT now(),
CONSTRAINT "PK_swap_transaction" PRIMARY KEY ("id")
)
`);

// Add indexes for better performance
await queryRunner.query(`
CREATE INDEX "IDX_swap_transaction_squid_request_id" ON "swap_transaction" ("squidRequestId")
`);

await queryRunner.query(`
CREATE INDEX "IDX_swap_transaction_first_tx_hash" ON "swap_transaction" ("firstTxHash")
`);

await queryRunner.query(`
CREATE INDEX "IDX_swap_transaction_second_tx_hash" ON "swap_transaction" ("secondTxHash")
`);

await queryRunner.query(`
CREATE INDEX "IDX_swap_transaction_status" ON "swap_transaction" ("status")
`);

await queryRunner.query(`
CREATE INDEX "IDX_swap_transaction_from_chain_id" ON "swap_transaction" ("fromChainId")
`);

await queryRunner.query(`
CREATE INDEX "IDX_swap_transaction_to_chain_id" ON "swap_transaction" ("toChainId")
`);

await queryRunner.query(`
CREATE INDEX "IDX_swap_transaction_created_at" ON "swap_transaction" ("createdAt")
`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
// Drop indexes
await queryRunner.query(`DROP INDEX "IDX_swap_transaction_created_at"`);
await queryRunner.query(`DROP INDEX "IDX_swap_transaction_to_chain_id"`);
await queryRunner.query(`DROP INDEX "IDX_swap_transaction_from_chain_id"`);
await queryRunner.query(`DROP INDEX "IDX_swap_transaction_status"`);
await queryRunner.query(`DROP INDEX "IDX_swap_transaction_second_tx_hash"`);
await queryRunner.query(`DROP INDEX "IDX_swap_transaction_first_tx_hash"`);
await queryRunner.query(
`DROP INDEX "IDX_swap_transaction_squid_request_id"`,
);

// Drop the table
await queryRunner.query(`DROP TABLE "swap_transaction"`);
}
}
52 changes: 52 additions & 0 deletions migration/1751934580588-AddSwapDataToDonation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class AddIsSwapToDonation1751934580588 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE "donation"
ADD COLUMN IF NOT EXISTS "swapTransactionId" integer;
`);
await queryRunner.query(`
ALTER TABLE "donation"
ADD CONSTRAINT "FK_donation_swap_transaction"
FOREIGN KEY ("swapTransactionId")
REFERENCES "swap_transaction"("id")
ON DELETE SET NULL;
`);
await queryRunner.query(`
ALTER TABLE "donation"
ADD COLUMN IF NOT EXISTS "isSwap" boolean NOT NULL DEFAULT false;
`);
await queryRunner.query(`
ALTER TABLE "draft_donation"
ADD COLUMN IF NOT EXISTS "fromTokenAmount" double precision;
`);
await queryRunner.query(`
ALTER TABLE "donation"
ADD COLUMN IF NOT EXISTS "fromTokenAmount" double precision;
`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE "donation"
DROP COLUMN IF EXISTS "fromTokenAmount";
`);
await queryRunner.query(`
ALTER TABLE "draft_donation"
DROP COLUMN IF EXISTS "fromTokenAmount";
`);
await queryRunner.query(`
ALTER TABLE "donation"
DROP COLUMN IF EXISTS "isSwap";
`);
await queryRunner.query(`
ALTER TABLE "donation"
DROP CONSTRAINT IF EXISTS "FK_donation_swap_transaction";
`);
await queryRunner.query(`
ALTER TABLE "donation"
DROP COLUMN IF EXISTS "swapTransactionId";
`);
}
}
16 changes: 16 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"google-spreadsheet": "^3.2.0",
"graphql": "16.8.1",
"graphql-fields": "^2.0.3",
"graphql-scalars": "^1.24.2",
"graphql-tag": "^2.12.6",
"graphql-upload": "15.0.2",
"handlebars": "4.7.7",
Expand Down Expand Up @@ -263,4 +264,4 @@
}
},
"license": "ISC"
}
}
21 changes: 21 additions & 0 deletions src/entities/donation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
Entity,
BaseEntity,
ManyToOne,
OneToOne,
JoinColumn,
RelationId,
Index,
} from 'typeorm';
Expand All @@ -13,11 +15,13 @@ import { User } from './user';
import { QfRound } from './qfRound';
import { ChainType } from '../types/network';
import { RecurringDonation } from './recurringDonation';
import { SwapTransaction } from './swapTransaction';

export const DONATION_STATUS = {
PENDING: 'pending',
VERIFIED: 'verified',
FAILED: 'failed',
SWAP_PENDING: 'swapPending',
};

export const DONATION_ORIGINS = {
Expand Down Expand Up @@ -135,6 +139,10 @@ export class Donation extends BaseEntity {
@Column({ type: 'real' })
amount: number;

@Field({ nullable: true })
@Column({ type: 'real', nullable: true })
fromTokenAmount?: number;

@Field({ nullable: true })
@Column({ type: 'real', nullable: true })
valueEth: number;
Expand Down Expand Up @@ -299,6 +307,19 @@ export class Donation extends BaseEntity {
@Column('decimal', { precision: 5, scale: 2, nullable: true })
donationPercentage?: number;

@Field(_type => SwapTransaction, { nullable: true })
@OneToOne(() => SwapTransaction, swapTransaction => swapTransaction.donation)
@JoinColumn({ name: 'swapTransactionId' })
swapTransaction?: SwapTransaction;

@Field({ nullable: true })
@Column({ nullable: true })
swapTransactionId?: number;

@Field({ nullable: false })
@Column({ default: false })
isSwap: boolean;

static async findXdaiGivDonationsWithoutPrice() {
return this.createQueryBuilder('donation')
.where(`donation.currency = 'GIV' AND donation."valueUsd" IS NULL `)
Expand Down
4 changes: 4 additions & 0 deletions src/entities/draftDonation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ export class DraftDonation extends BaseEntity {
@Column({ type: 'real' })
amount: number;

@Field({ nullable: true })
@Column({ type: 'float', nullable: true })
fromTokenAmount?: number;

@Field()
@Column({ nullable: true })
projectId: number;
Expand Down
2 changes: 2 additions & 0 deletions src/entities/entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import { UserQfRoundModelScore } from './userQfRoundModelScore';
import { ProjectGivbackRankView } from './ProjectGivbackRankView';
import { EstimatedClusterMatching } from './estimatedClusterMatching';
import { SitemapUrl } from './sitemapUrl';
import { SwapTransaction } from './swapTransaction';

export const getEntities = (): DataSourceOptions['entities'] => {
return [
Expand Down Expand Up @@ -126,6 +127,7 @@ export const getEntities = (): DataSourceOptions['entities'] => {
ProjectGivbackRankView,

SitemapUrl,
SwapTransaction,

Cause,
CauseProject,
Expand Down
48 changes: 41 additions & 7 deletions src/entities/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ export enum ProjStatus {

// Always use Enums to prevent sql injection with plain strings
export enum SortingField {
ActiveProjectsCount = 'ActiveProjectsCount',
MostNumberOfProjects = 'MostNumberOfProjects',
LeastNumberOfProjects = 'LeastNumberOfProjects',
MostFunded = 'MostFunded',
MostLiked = 'MostLiked',
Newest = 'Newest',
Expand Down Expand Up @@ -634,22 +635,41 @@ export class Project extends BaseEntity {
@Column('float', { default: 0, nullable: true })
totalDonated?: number;

// Virtual field to get projects directly
@Field(_type => [Project], { nullable: true })
async projects(): Promise<Project[] | null> {
const causeProjects = await CauseProject.createQueryBuilder('causeProject')
.leftJoinAndSelect('causeProject.project', 'project')
.leftJoinAndSelect('project.status', 'status')
.leftJoinAndSelect('project.addresses', 'addresses')
.innerJoinAndSelect(
.leftJoinAndSelect(
'project.socialMedia',
'socialMedia',
'socialMedia.projectId = project.id',
)
.leftJoinAndSelect(
'project.socialProfiles',
'socialProfiles',
'socialProfiles.projectId = project.id',
)
.leftJoinAndSelect('project.anchorContracts', 'anchor_contract_address')
.leftJoinAndSelect('project.projectPower', 'projectPower')
.leftJoinAndSelect('project.projectInstantPower', 'projectInstantPower')
.leftJoinAndSelect(
'project.projectUpdates',
'projectUpdates',
'projectUpdates.projectId = project.id',
)
.leftJoinAndSelect('project.projectFuturePower', 'projectFuturePower')
.leftJoinAndSelect(
'project.categories',
'categories',
'categories.isActive = :isActive',
{ isActive: true },
)
.leftJoinAndSelect('categories.mainCategory', 'mainCategory')
.leftJoinAndSelect('project.organization', 'organization')
.leftJoinAndSelect('project.qfRounds', 'qfRounds')
.leftJoin('project.adminUser', 'user')
.leftJoinAndSelect('project.adminUser', 'adminUser')
.where('causeProject.causeId = :causeId', { causeId: this.id })
.getMany();
return causeProjects.map(cp => cp.project);
Expand All @@ -669,7 +689,7 @@ export class Project extends BaseEntity {
)
.leftJoinAndSelect('project.organization', 'organization')
.leftJoinAndSelect('project.qfRounds', 'qfRounds')
.leftJoin('project.adminUser', 'user')
.leftJoinAndSelect('project.adminUser', 'adminUser')
.where('causeProject.causeId = :causeId', { causeId: this.id })
.getMany();
return causeProjects;
Expand Down Expand Up @@ -879,11 +899,25 @@ export class Cause extends Project {
.leftJoinAndSelect('causeProject.project', 'project')
.leftJoinAndSelect('project.status', 'status')
.leftJoinAndSelect('project.addresses', 'addresses')
.leftJoinAndSelect(
'project.socialProfiles',
'socialProfiles',
'socialProfiles.projectId = project.id',
)
.leftJoinAndSelect(
'project.socialMedia',
'socialMedia',
'socialMedia.projectId = project.id',
)
.leftJoinAndSelect('project.socialMedia', 'socialMedia')
.leftJoinAndSelect('project.anchorContracts', 'anchor_contract_address')
.leftJoinAndSelect('project.projectPower', 'projectPower')
.leftJoinAndSelect('project.projectInstantPower', 'projectInstantPower')
.leftJoinAndSelect('project.projectUpdates', 'projectUpdates')
.leftJoinAndSelect(
'project.projectUpdates',
'projectUpdates',
'projectUpdates.projectId = project.id',
)
.leftJoinAndSelect('project.projectFuturePower', 'projectFuturePower')
.leftJoinAndSelect(
'project.categories',
Expand All @@ -894,7 +928,7 @@ export class Cause extends Project {
.leftJoinAndSelect('categories.mainCategory', 'mainCategory')
.leftJoinAndSelect('project.organization', 'organization')
.leftJoinAndSelect('project.qfRounds', 'qfRounds')
.leftJoin('project.adminUser', 'user')
.leftJoinAndSelect('project.adminUser', 'adminUser')
.where('causeProject.causeId = :causeId', { causeId: this.id })
.getMany();
return causeProjects.map(cp => cp.project);
Expand Down
Loading
Loading