Skip to content

Commit

Permalink
Remove queue-message, replace it for transactions (#88)
Browse files Browse the repository at this point in the history
* Remove queue-message

* Fix tests

* Fix multiple errors

* Update versions
  • Loading branch information
nacho9900 authored Mar 19, 2024
1 parent faef1ff commit 3aa6dde
Show file tree
Hide file tree
Showing 17 changed files with 238 additions and 175 deletions.
4 changes: 2 additions & 2 deletions examples/poaps/backend/src/methods/mint_async_poap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ import { handleError } from '../utils/handleError';
export const mint_async_poap = async (client: PoapsClient): Promise<void> => {
try {
// Initiate the asynchronous mint process
const queueUid: string = await client.mintAsync({
await client.mintAsync({
mintCode: 'your_mint_code',
address: 'your_address',
});

// Wait for the mint's status to transition from 'IN_PROCESS' or 'PENDING' states
await client.waitMintStatus(queueUid, 'your_mint_code');
await client.waitMintStatus('your_mint_code');

// Wait for the minted POAP to be indexed and fetch the mint code information related to the Mint Code
const getMintCodeResponse = await client.waitPoapIndexed('your_mint_code');
Expand Down
6 changes: 3 additions & 3 deletions packages/drops/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@poap-xyz/drops",
"version": "0.1.6",
"version": "0.1.7",
"description": "Drops module for the poap.js library",
"main": "dist/cjs/index.cjs",
"module": "dist/esm/index.mjs",
Expand Down Expand Up @@ -29,7 +29,7 @@
"node": ">=18"
},
"dependencies": {
"@poap-xyz/providers": "0.1.6",
"@poap-xyz/utils": "0.1.6"
"@poap-xyz/providers": "0.1.7",
"@poap-xyz/utils": "0.1.7"
}
}
6 changes: 3 additions & 3 deletions packages/moments/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@poap-xyz/moments",
"version": "0.1.6",
"version": "0.1.7",
"description": "Moments module for the poap.js library",
"main": "dist/cjs/index.cjs",
"module": "dist/esm/index.mjs",
Expand All @@ -26,8 +26,8 @@
"build": "rollup -c --bundleConfigAsCjs"
},
"dependencies": {
"@poap-xyz/providers": "0.1.6",
"@poap-xyz/utils": "0.1.6",
"@poap-xyz/providers": "0.1.7",
"@poap-xyz/utils": "0.1.7",
"uuid": "^9.0.0"
},
"engines": {
Expand Down
6 changes: 3 additions & 3 deletions packages/poaps/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@poap-xyz/poaps",
"version": "0.1.6",
"version": "0.1.7",
"description": "Poaps module for the poap.js library",
"main": "dist/cjs/index.cjs",
"module": "dist/esm/index.mjs",
Expand All @@ -26,8 +26,8 @@
"build": "rollup -c --bundleConfigAsCjs"
},
"dependencies": {
"@poap-xyz/providers": "0.1.6",
"@poap-xyz/utils": "0.1.6"
"@poap-xyz/providers": "0.1.7",
"@poap-xyz/utils": "0.1.7"
},
"engines": {
"node": ">=18"
Expand Down
106 changes: 53 additions & 53 deletions packages/poaps/src/PoapsClient.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
import { CompassProvider, TokensApiProvider } from '@poap-xyz/providers';
import {
CompassProvider,
TokensApiProvider,
Transaction,
} from '@poap-xyz/providers';
import { POAP } from './domain/Poap';
import { POAPReservation } from './domain/POAPReservation';
import { PaginatedPoapsResponse, PAGINATED_POAPS_QUERY } from './queries';
import { PAGINATED_POAPS_QUERY, PaginatedPoapsResponse } from './queries';
import {
FetchPoapsInput,
EmailReservationInput,
FetchPoapsInput,
PoapMintStatus,
WalletMintInput,
} from './types';
import {
PaginatedResult,
nextCursor,
creatAddressFilter,
createBetweenFilter,
creatEqFilter,
createInFilter,
creatEqFilter,
createUndefinedOrder,
creatAddressFilter,
MintingStatus,
nextCursor,
PaginatedResult,
} from '@poap-xyz/utils';
import { CodeAlreadyMintedError } from './errors/CodeAlreadyMintedError';
import { CodeExpiredError } from './errors/CodeExpiredError';
import { MintChecker } from './utils/MintChecker';
import { PoapIndexed } from './utils/PoapIndexed';
import { PoapMintStatus } from './types/response';

/**
* Represents a client for interacting with POAPs .
Expand Down Expand Up @@ -106,32 +109,11 @@ export class PoapsClient {
);
}

/**
* Retrieves the secret code associated with a POAP code.
* @async
* @param {string} mintCode - The POAP code for which to get the secret.
* @returns {Promise<string>} The associated secret code.
* @throws {CodeAlreadyMintedError} Thrown when the POAP code has already been minted.
* @throws {CodeExpiredError} Thrown when the POAP code is expired.
*/
private async getSecretCode(mintCode: string): Promise<string> {
const getCodeResponse = await this.getMintCode(mintCode);

if (getCodeResponse.minted == true) {
throw new CodeAlreadyMintedError(mintCode);
}
if (getCodeResponse.isActive == false) {
throw new CodeExpiredError(mintCode);
}

return getCodeResponse.secretCode;
}

/**
* Retrieves mint code details for a specific Mint Code.
* @async
* @param {string} mintCode - The Mint Code for which to get the mint code.
* @returns {Promise<GetMintCodeResponse>} The mint code details.
* @returns {Promise<PoapMintStatus>} The Mint status.
*/
async getMintCode(mintCode: string): Promise<PoapMintStatus> {
const getMintCodeRaw = await this.tokensApiProvider.getMintCode(mintCode);
Expand All @@ -144,35 +126,35 @@ export class PoapsClient {
}

/**
* Fetches the current status of a mint based on its unique ID.
* @async
* @param {string} queueUid - The unique ID of the mint.
* @returns {Promise<MintingStatus>} The current status of the mint.
* Gets the Transaction associated with the mint.
* The Transaction could change in case of a bump.
* It returns null if the mint has no transaction associated.
*
* @param {string} qrHash - The qrHash of the mint.
* @returns {Promise<Transaction> | null} The Transaction associated with the mint. Null if no transaction is found.
*/
async getMintStatus(queueUid: string): Promise<MintingStatus> {
const mintStatusResponse =
await this.tokensApiProvider.mintStatus(queueUid);
return mintStatusResponse.status;
public async getMintTransaction(qrHash: string): Promise<Transaction | null> {
return await this.tokensApiProvider.getMintTransaction(qrHash);
}

/**
* Awaits until the mint's status changes from 'IN_PROCESS' or 'PENDING'.
* Awaits until we have a final Transaction status for a specific Mint Code.
* @async
* @param {string} queueUid - The unique ID of the mint.
* @returns {Promise<void>}
* @param mintCode - The Mint Code
*/
async waitMintStatus(queueUid: string, mintCode: string): Promise<void> {
const checker = new MintChecker(queueUid, this.tokensApiProvider, mintCode);
public async waitMintStatus(mintCode: string): Promise<void> {
const checker = new MintChecker(this.tokensApiProvider, mintCode);
await checker.checkMintStatus();
}

/**
* Awaits until a specific POAP, identified by its Mint Code, is indexed on our database.
* @async
* @param {string} mintCode - The Mint Code identifying the POAP to be indexed.
* @returns {Promise<GetMintCodeResponse>} Details of the indexed POAP.
* @returns {Promise<PoapMintStatus>} - The status of the POAP mint.
*/
async waitPoapIndexed(mintCode: string): Promise<PoapMintStatus> {
public async waitPoapIndexed(mintCode: string): Promise<PoapMintStatus> {
const checker = new PoapIndexed(mintCode, this.tokensApiProvider);
return await checker.waitPoapIndexed();
}
Expand All @@ -181,19 +163,16 @@ export class PoapsClient {
* Begins an asynchronous mint process and provides a unique queue ID in return.
* @async
* @param {WalletMintInput} input - Details required for the mint.
* @returns {Promise<string>} A unique queue ID for the initiated mint.
*/
async mintAsync(input: WalletMintInput): Promise<string> {
public async mintAsync(input: WalletMintInput): Promise<void> {
const secretCode = await this.getSecretCode(input.mintCode);

const response = await this.tokensApiProvider.postMintCode({
await this.tokensApiProvider.postMintCode({
address: input.address,
qr_hash: input.mintCode,
secret: secretCode,
sendEmail: false,
});

return response.queue_uid;
}

/**
Expand All @@ -206,9 +185,9 @@ export class PoapsClient {
* @throws {FinishedWithError} If there's an error concluding the mint process.
*/
async mintSync(input: WalletMintInput): Promise<POAP> {
const queueUid = await this.mintAsync(input);
await this.mintAsync(input);

await this.waitMintStatus(queueUid, input.mintCode);
await this.waitMintStatus(input.mintCode);

const getCodeResponse = await this.waitPoapIndexed(input.mintCode);

Expand All @@ -227,7 +206,7 @@ export class PoapsClient {
* @param {EmailReservationInput} input - Information for the reservation.
* @returns {Promise<POAPReservation>} The reservation details of the POAP.
*/
async emailReservation(
public async emailReservation(
input: EmailReservationInput,
): Promise<POAPReservation> {
const secretCode = await this.getSecretCode(input.mintCode);
Expand All @@ -251,4 +230,25 @@ export class PoapsClient {
name: response.event.name,
});
}

/**
* Retrieves the secret code associated with a POAP code.
* @async
* @param {string} mintCode - The POAP code for which to get the secret.
* @returns {Promise<string>} The associated secret code.
* @throws {CodeAlreadyMintedError} Thrown when the POAP code has already been minted.
* @throws {CodeExpiredError} Thrown when the POAP code is expired.
*/
private async getSecretCode(mintCode: string): Promise<string> {
const getCodeResponse = await this.getMintCode(mintCode);

if (getCodeResponse.minted) {
throw new CodeAlreadyMintedError(mintCode);
}
if (!getCodeResponse.isActive) {
throw new CodeExpiredError(mintCode);
}

return getCodeResponse.secretCode;
}
}
89 changes: 44 additions & 45 deletions packages/poaps/src/utils/MintChecker.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { MintingStatus } from '@poap-xyz/utils';
import { TokensApiProvider, MintStatusResponse } from '@poap-xyz/providers';
import {
TokensApiProvider,
Transaction,
TransactionStatus,
} from '@poap-xyz/providers';
import { FinishedWithError } from '../errors/FinishedWithError';
import { RetryableTask } from './RetryableTask';

Expand All @@ -8,80 +11,76 @@ import { RetryableTask } from './RetryableTask';
* If a mint is still pending or in process, it implements a backoff retry mechanism.
*/
export class MintChecker extends RetryableTask {
private queueUid: string;
private mintCode: string;

/**
* Constructs a new instance of the MintChecker class.
*
* @param {string} queueUid - The unique identifier for the token mint.
* @param {string} mintCode - The unique code for the token mint.
* @param {TokensApiProvider} tokensApiProvider - The provider to fetch the mint status.
*/
constructor(
queueUid: string,
tokensApiProvider: TokensApiProvider,
mintCode: string,
) {
constructor(tokensApiProvider: TokensApiProvider, mintCode: string) {
super(tokensApiProvider);
this.queueUid = queueUid;
this.mintCode = mintCode;
}

/**
* Checks the current status of a token mint.
* If the mint is still pending or in process, it will retry the check with an increased delay.
*
* @public
* @returns {Promise<void>} A promise that resolves once the status has been checked.
* @throws {FinishedWithError} Throws an error if the minting process finished with an error.
*/
public async checkMintStatus(): Promise<void> {
try {
const transaction = await this.tokensApiProvider.getMintTransaction(
this.mintCode,
);

if (this.shouldRetry(transaction)) {
await this.backoffAndRetry(() => this.checkMintStatus());
} else {
this.handleErrorStatus(transaction, this.mintCode);
}
} catch (e) {
if (e instanceof FinishedWithError) {
throw e;
}

await this.backoffAndRetry(() => this.checkMintStatus());
}
}

/**
* Determines if a retry should be performed based on the provided minting status.
*
* @private
* @param {MintingStatus} status - The current minting status.
* @returns {boolean} Returns true if a retry should be performed, otherwise false.
* @param transaction - The transaction to check for retry.
*/
private shouldRetry(status: MintingStatus): boolean {
return (
status === MintingStatus.IN_PROCESS || status === MintingStatus.PENDING
);
private shouldRetry(transaction: Transaction | null): boolean {
return !transaction || transaction.status === TransactionStatus.pending;
}

/**
* Handles any error statuses from the mint status response.
* If the minting process finishes with an error, an exception will be thrown.
*
* @private
* @param {MintStatusResponse} mintStatusResponse - The response from the mint status check.
* @param {Transaction} transaction - The transaction to check for errors.
* @param mintCode
* @throws {FinishedWithError} Throws an error if the minting process finished with an error.
*/
private handleErrorStatus(
mintStatusResponse: MintStatusResponse,
transaction: Transaction | null,
mintCode: string,
): void {
if (
mintStatusResponse.status === MintingStatus.FINISH_WITH_ERROR &&
mintStatusResponse.result?.error
) {
throw new FinishedWithError(mintStatusResponse.result?.error, mintCode);
}
}

/**
* Checks the current status of a token mint.
* If the mint is still pending or in process, it will retry the check with an increased delay.
*
* @public
* @returns {Promise<void>} A promise that resolves once the status has been checked.
* @throws {FinishedWithError} Throws an error if the minting process finished with an error.
*/
public async checkMintStatus(): Promise<void> {
try {
const mintStatusResponse = await this.tokensApiProvider.mintStatus(
this.queueUid,
if (transaction?.status === TransactionStatus.failed) {
throw new FinishedWithError(
'The Transaction associated with this mint failed',
mintCode,
);

if (this.shouldRetry(mintStatusResponse.status)) {
await this.backoffAndRetry(() => this.checkMintStatus());
} else {
this.handleErrorStatus(mintStatusResponse, this.mintCode);
}
} catch (e) {
await this.backoffAndRetry(() => this.checkMintStatus());
}
}
}
Loading

0 comments on commit 3aa6dde

Please sign in to comment.