forked from cerc-io/snowballtools-base
Implement functionality to release funds after deployment (#7)
Part of [Service provider auctions for web deployments](https://www.notion.so/Service-provider-auctions-for-web-deployments-104a6b22d47280dbad51d28aa3a91d75) - Implement functionality to release funds after first successful deployment Co-authored-by: IshaVenikar <ishavenikar7@gmail.com> Reviewed-on: cerc-io/snowballtools-base#7
This commit is contained in:
@@ -3,7 +3,9 @@ import {
|
||||
DeepPartial,
|
||||
FindManyOptions,
|
||||
FindOneOptions,
|
||||
FindOptionsWhere
|
||||
FindOptionsWhere,
|
||||
IsNull,
|
||||
Not
|
||||
} from 'typeorm';
|
||||
import path from 'path';
|
||||
import debug from 'debug';
|
||||
@@ -151,14 +153,19 @@ export class Database {
|
||||
}
|
||||
|
||||
async allProjectsWithoutDeployments(): Promise<Project[]> {
|
||||
const projectRepository = this.dataSource.getRepository(Project);
|
||||
const allProjects = await this.getProjects({
|
||||
where: {
|
||||
auctionId: Not(IsNull()),
|
||||
},
|
||||
relations: ['deployments'],
|
||||
withDeleted: true,
|
||||
});
|
||||
|
||||
const projects = await projectRepository
|
||||
.createQueryBuilder('project')
|
||||
.leftJoinAndSelect('project.deployments', 'deployment', 'deployment.deletedAt IS NULL') // Join only non-soft-deleted deployments
|
||||
.where('deployment.id IS NULL') // Get projects where no deployments are present
|
||||
.andWhere('project.auctionId IS NOT NULL') // Ensure auctionId is not null
|
||||
.getMany();
|
||||
const projects = allProjects.filter(project => {
|
||||
if (project.deletedAt !== null) return false;
|
||||
|
||||
return project.deployments.length === 0;
|
||||
});
|
||||
|
||||
return projects;
|
||||
}
|
||||
|
||||
@@ -52,6 +52,9 @@ export class Project {
|
||||
@Column({ type: 'simple-array', nullable: true })
|
||||
deployerLrns!: string[] | null;
|
||||
|
||||
@Column('boolean', { default: false, nullable: true })
|
||||
fundsReleased!: boolean;
|
||||
|
||||
// TODO: Compute template & framework in import repository
|
||||
@Column('varchar', { nullable: true })
|
||||
template!: string | null;
|
||||
|
||||
@@ -319,6 +319,21 @@ export class Registry {
|
||||
return deployerLrns;
|
||||
}
|
||||
|
||||
async releaseDeployerFunds(
|
||||
auctionId: string
|
||||
): Promise<any> {
|
||||
const fee = parseGasAndFees(this.registryConfig.fee.gas, this.registryConfig.fee.fees);
|
||||
const auction = await this.registry.releaseFunds(
|
||||
{
|
||||
auctionId
|
||||
},
|
||||
this.registryConfig.privateKey,
|
||||
fee
|
||||
);
|
||||
|
||||
return auction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch ApplicationDeploymentRecords for deployments
|
||||
*/
|
||||
@@ -417,6 +432,10 @@ export class Registry {
|
||||
}
|
||||
|
||||
async getCompletedAuctionIds(auctionIds: string[]): Promise<string[]> {
|
||||
if (auctionIds.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const auctions = await this.registry.getAuctionsByIds(auctionIds);
|
||||
|
||||
const completedAuctions = auctions
|
||||
|
||||
@@ -74,6 +74,7 @@ type Project {
|
||||
description: String
|
||||
deployerLrns: [String]
|
||||
auctionId: String
|
||||
fundsReleased: Boolean
|
||||
template: String
|
||||
framework: String
|
||||
webhooks: [String!]
|
||||
|
||||
@@ -173,6 +173,9 @@ export class Service {
|
||||
where: records.map((record) => ({
|
||||
applicationDeploymentRequestId: record.attributes.request,
|
||||
})),
|
||||
relations: {
|
||||
project: true,
|
||||
},
|
||||
order: {
|
||||
createdAt: 'DESC',
|
||||
},
|
||||
@@ -189,8 +192,6 @@ export class Service {
|
||||
// Update deployment data for ApplicationDeploymentRecords
|
||||
const deploymentUpdatePromises = records.map(async (record) => {
|
||||
const deployment = recordToDeploymentsMap[record.attributes.request];
|
||||
const project = await this.getProjectById(deployment.projectId)
|
||||
assert(project)
|
||||
|
||||
const parts = record.attributes.url.replace('https://', '').split('.');
|
||||
const baseDomain = parts.slice(1).join('.');
|
||||
@@ -204,15 +205,21 @@ export class Service {
|
||||
|
||||
await this.db.updateDeploymentById(deployment.id, deployment);
|
||||
|
||||
const baseDomains = project.baseDomains || [];
|
||||
const baseDomains = deployment.project.baseDomains || [];
|
||||
|
||||
if (!baseDomains.includes(baseDomain)) {
|
||||
baseDomains.push(baseDomain);
|
||||
}
|
||||
|
||||
await this.db.updateProjectById(project.id, {
|
||||
baseDomains
|
||||
})
|
||||
// Release deployer funds on successful deployment
|
||||
if (!deployment.project.fundsReleased) {
|
||||
const fundsReleased = await this.releaseDeployerFundsByProjectId(deployment.projectId);
|
||||
|
||||
await this.db.updateProjectById(deployment.projectId, {
|
||||
baseDomains,
|
||||
fundsReleased,
|
||||
});
|
||||
}
|
||||
|
||||
log(
|
||||
`Updated deployment ${deployment.id} with URL ${record.attributes.url}`,
|
||||
@@ -292,7 +299,7 @@ export class Service {
|
||||
async checkAuctionStatus(): Promise<void> {
|
||||
const projects = await this.db.allProjectsWithoutDeployments();
|
||||
|
||||
const validAuctionIds = projects.map((project) => project.auctionId!)
|
||||
const validAuctionIds = projects.map((project) => project.auctionId)
|
||||
.filter((id): id is string => Boolean(id));
|
||||
const completedAuctionIds = await this.laconicRegistry.getCompletedAuctionIds(validAuctionIds);
|
||||
|
||||
@@ -301,7 +308,7 @@ export class Service {
|
||||
);
|
||||
|
||||
for (const project of projectsToBedeployed) {
|
||||
const deployerLrns = await this.laconicRegistry.getAuctionWinningDeployers(project!.auctionId!);
|
||||
const deployerLrns = await this.laconicRegistry.getAuctionWinningDeployers(project.auctionId!);
|
||||
|
||||
if (!deployerLrns) {
|
||||
log(`No winning deployer for auction ${project!.auctionId}`);
|
||||
@@ -1261,4 +1268,27 @@ export class Service {
|
||||
const auctions = await this.laconicRegistry.getAuctionData(auctionId);
|
||||
return auctions[0];
|
||||
}
|
||||
|
||||
async releaseDeployerFundsByProjectId(projectId: string): Promise<boolean> {
|
||||
const project = await this.db.getProjectById(projectId);
|
||||
|
||||
if (!project || !project.auctionId) {
|
||||
log(`Project ${projectId} ${!project ? 'not found' : 'does not have an auction'}`);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const auction = await this.laconicRegistry.releaseDeployerFunds(project.auctionId);
|
||||
|
||||
if (auction.auction.fundsReleased) {
|
||||
log(`Funds released for auction ${project.auctionId}`);
|
||||
await this.db.updateProjectById(projectId, { fundsReleased: true });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
log(`Error releasing funds for auction ${project.auctionId}`);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user