Skip to content

Commit

Permalink
Change donation verification logic for imported and draft donations
Browse files Browse the repository at this point in the history
related to #1821 (comment)
  • Loading branch information
mohammadranjbarz committed Sep 15, 2024
1 parent e643491 commit e6232d0
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 1 deletion.
10 changes: 10 additions & 0 deletions src/repositories/draftDonationRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ export async function countPendingDraftDonations(): Promise<number> {
return parseInt(res[0].count, 10);
}

export async function findDraftDonationByMatchedDonationId(
matchedDonationId: number,
): Promise<DraftDonation | null> {
return DraftDonation.findOne({
where: {
matchedDonationId,
},
});
}

export const updateDraftDonationStatus = async (params: {
donationId: number;
status: string;
Expand Down
42 changes: 42 additions & 0 deletions src/services/chains/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,25 @@ function getTransactionDetailTestCases() {
errorMessages.TRANSACTION_CANT_BE_OLDER_THAN_DONATION,
);
});
it(
'should not return error when transaction time is newer than sent timestamp for HNY token transfer on XDAI,' +
'And donation is imported or relevant to draft donation',
async () => {
// https://blockscout.com/xdai/mainnet/tx/0x99e70642fe1aa03cb2db35c3e3909466e66b233840b7b1e0dd47296c878c16b4
const amount = 0.001;
const txInfo = await getTransactionInfoFromNetwork({
txHash:
'0x99e70642fe1aa03cb2db35c3e3909466e66b233840b7b1e0dd47296c878c16b4',
symbol: 'HNY',
networkId: NETWORK_IDS.XDAI,
fromAddress: '0x826976d7c600d45fb8287ca1d7c76fc8eb732030',
toAddress: '0x5A5a0732c1231D99DB8FFcA38DbEf1c8316fD3E1',
amount,
timestamp: 1617903450 + ONE_DAY,
});
assert.isNotNull(txInfo);
},
);
it('should return transaction_not_found when it has not being mined before an hour', async () => {
const amount = 0.001;
const badFunc = async () => {
Expand Down Expand Up @@ -1019,6 +1038,29 @@ function getTransactionDetailTestCases() {
errorMessages.TRANSACTION_CANT_BE_OLDER_THAN_DONATION,
);
});
it(
'should not return error when transaction time is newer than sent timestamp for spl-token transfer on Solana,' +
'but donation is imported or relevant to draft',
async () => {
// https://explorer.solana.com/tx/2tm14GVsDwXpMzxZzpEWyQnfzcUEv1DZQVQb6VdbsHcV8StoMbBtuQTkW1LJ8RhKKrAL18gbm181NgzuusiQfZ16?cluster=devnet

const amount = 7;
const transactionInfo = await getTransactionInfoFromNetwork({
txHash:
'2tm14GVsDwXpMzxZzpEWyQnfzcUEv1DZQVQb6VdbsHcV8StoMbBtuQTkW1LJ8RhKKrAL18gbm181NgzuusiQfZ16',
symbol: 'TEST-SPL-TOKEN',
chainType: ChainType.SOLANA,
networkId: NETWORK_IDS.SOLANA_DEVNET,
fromAddress: 'BxUK9tDLeMT7AkTR2jBTQQYUxGGw6nuWbQqGtiHHfftn',
toAddress: 'FAMREy7d73N5jPdoKowQ4QFm6DKPWuYxZh6cwjNAbpkY',
timestamp: 1704357745 + ONE_DAY,
amount,
importedFromDraftOrBackupService: true,
});

assert.isOk(transactionInfo);
},
);
}

function closeToTestCases() {
Expand Down
7 changes: 6 additions & 1 deletion src/services/chains/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export interface TransactionDetailInput {
safeTxHash?: string;
nonce?: number;
chainType?: ChainType;
importedFromDraftOrBackupService?: boolean;
}

export const ONE_HOUR = 60 * 60;
Expand Down Expand Up @@ -59,7 +60,11 @@ export function validateTransactionWithInputData(
);
}

if (input.timestamp - transaction.timestamp > ONE_HOUR) {
if (
// We bypass checking tx and donation time for imported donations from backup service or draft donation
!input.importedFromDraftOrBackupService &&
input.timestamp - transaction.timestamp > ONE_HOUR
) {
// because we first create donation, then transaction will be mined, the transaction always should be greater than
// donation created time, but we set one hour because maybe our server time is different with blockchain time server
logger.debug(
Expand Down
45 changes: 45 additions & 0 deletions src/services/donationService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,51 @@ function syncDonationStatusWithBlockchainNetworkTestCases() {
errorMessages.TRANSACTION_CANT_BE_OLDER_THAN_DONATION,
);
});
it(
'should change status to verified when donation is very newer than transaction' +
' but tx is imported or relevant to draft donation',
async () => {
// https://blockscout.com/xdai/mainnet/tx/0x00aef89fc40cea0cc0cb7ae5ac18c0e586dccb200b230a9caabca0e08ff7a36b
const transactionInfo = {
txHash:
'0x00aef89fc40cea0cc0cb7ae5ac18c0e586dccb200b230a9caabca0e08ff7a36b',
currency: 'USDC',
networkId: NETWORK_IDS.XDAI,
fromAddress: '0x826976d7c600d45fb8287ca1d7c76fc8eb732030',
toAddress: '0x87f1c862c166b0ceb79da7ad8d0864d53468d076',
amount: 1,
};
const user = await saveUserDirectlyToDb(transactionInfo.fromAddress);
const project = await saveProjectDirectlyToDb({
...createProjectData(),
walletAddress: transactionInfo.toAddress,
});
const donation = await saveDonationDirectlyToDb(
{
amount: transactionInfo.amount,
transactionNetworkId: transactionInfo.networkId,
transactionId: transactionInfo.txHash,
currency: transactionInfo.currency,
fromWalletAddress: transactionInfo.fromAddress,
toWalletAddress: transactionInfo.toAddress,
valueUsd: 100,
anonymous: false,
createdAt: new Date(),
status: DONATION_STATUS.PENDING,
},
user.id,
project.id,
);
donation.importDate = new Date();
await donation.save();
const updateDonation = await syncDonationStatusWithBlockchainNetwork({
donationId: donation.id,
});
assert.isOk(updateDonation);
assert.equal(updateDonation.id, donation.id);
assert.equal(updateDonation.status, DONATION_STATUS.VERIFIED);
},
);
}

function isProjectAcceptTokenTestCases() {
Expand Down
6 changes: 6 additions & 0 deletions src/services/donationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { getEvmTransactionTimestamp } from './chains/evm/transactionService';
import { getOrttoPersonAttributes } from '../adapters/notifications/NotificationCenterAdapter';
import { CustomToken, getTokenPrice } from './priceService';
import { updateProjectStatistics } from './projectService';
import { findDraftDonationByMatchedDonationId } from '../repositories/draftDonationRepository';

export const TRANSAK_COMPLETED_STATUS = 'COMPLETED';

Expand Down Expand Up @@ -228,6 +229,8 @@ export const syncDonationStatusWithBlockchainNetwork = async (params: {
if (!donation) {
throw new Error(i18n.__(translationErrorMessagesKeys.DONATION_NOT_FOUND));
}
const relevantDraftDonation =
await findDraftDonationByMatchedDonationId(donationId);

// fetch the transactionId from the safeTransaction Approval
if (!donation.transactionId && donation.safeTransactionId) {
Expand Down Expand Up @@ -261,6 +264,9 @@ export const syncDonationStatusWithBlockchainNetwork = async (params: {
chainType: donation.chainType,
safeTxHash: donation.safeTransactionId,
timestamp: donation.createdAt.getTime() / 1000,
importedFromDraftOrBackupService: Boolean(
donation.importDate || relevantDraftDonation,
),
});
donation.status = DONATION_STATUS.VERIFIED;
if (transaction.hash !== donation.transactionId) {
Expand Down

0 comments on commit e6232d0

Please sign in to comment.