Skip to content

Commit

Permalink
feat: refund ncg when amount of ncg to transfer after refunded is low…
Browse files Browse the repository at this point in the history
…er than minimum
  • Loading branch information
shkangr committed Feb 22, 2024
1 parent f1ffacb commit 17e2e48
Show file tree
Hide file tree
Showing 3 changed files with 296 additions and 0 deletions.
35 changes: 35 additions & 0 deletions bridge/src/observers/nine-chronicles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,41 @@ export class NCGTransferredEventObserver
`${sender} tried to exchange ${amountString} and already exchanged ${transferredAmountInLast24Hours} and users can exchange until ${this._limitationPolicy.maximum} in 24 hours so refund NCG as ${refundAmount}. The transaction's id is`,
refundTxId
);

if (limitedAmount.lessThan(this._limitationPolicy.minimum)) {
console.log('Amount Ncg to transfer after refunded is lower than minimum', limitedAmount.toString())
const smallAmountRefundTxId = await this._ncgTransfer.transfer(
sender,
limitedAmount.toString(),
`I'm bridge and you should transfer more NCG than ${this._limitationPolicy.minimum}.`
);
await this._slackMessageSender.sendMessage(
new RefundEvent(
this._explorerUrl,
this._ncscanUrl,
this._useNcscan,
sender,
txId,
limitedAmount,
smallAmountRefundTxId,
limitedAmount,
`Overflowed Amount ${limitedAmount.toString()} is lower than minimum NCG. Refund NCG.`
)
);
this._opensearchClient.to_opensearch("error", {
content: "NCG -> wNCG request failure",
cause: `Overflowed Amount ${limitedAmount.toString()} is lower than minimum NCG. Refund NCG.`,
libplanetTxId: txId,
sender: sender,
recipient: recipient,
amount: amount.toNumber(),
});
console.log(
`Overflowed Amount after refund ${limitedAmount.toString()} is lower than minimum NCG. Refund NCG. The transaction's id is`,
smallAmountRefundTxId
);
continue;
}
}

let fee = this._exchangeFeeRatioPolicy.getFee(limitedAmount);
Expand Down
160 changes: 160 additions & 0 deletions bridge/test/observers/__snapshots__/nine-chronicles.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,165 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`NCGTransferredEventObserver notify If overflowed amount is lower than minimum, then refund check 1`] = `
Array [
Array [
"info",
Object {
"amount": 48651.5,
"content": "NCG -> wNCG request success",
"ethereumTxId": "TRANSACTION-HASH",
"fee": 1298.5,
"libplanetTxId": "TX-A",
"recipient": "0x4029bC50b4747A037d38CF2197bCD335e22Ca301",
"sender": "0x2734048eC2892d111b4fbAB224400847544FC872",
},
],
Array [
"error",
Object {
"amount": 150,
"cause": "24 hr transfer maximum 50000 reached. User transferred 49950 NCGs in 24 hrs.",
"content": "NCG -> wNCG request failure",
"libplanetTxId": "TX-SHOULD-REFUND",
"recipient": "0x4029bC50b4747A037d38CF2197bCD335e22Ca301",
"refundAmount": 100,
"refundTxId": "TX-ID",
"sender": "0x2734048eC2892d111b4fbAB224400847544FC872",
},
],
Array [
"error",
Object {
"amount": 150,
"cause": "Overflowed Amount 50 is lower than minimum NCG. Refund NCG.",
"content": "NCG -> wNCG request failure",
"libplanetTxId": "TX-SHOULD-REFUND",
"recipient": "0x4029bC50b4747A037d38CF2197bCD335e22Ca301",
"sender": "0x2734048eC2892d111b4fbAB224400847544FC872",
},
],
]
`;

exports[`NCGTransferredEventObserver notify If overflowed amount is lower than minimum, then refund check 2`] = `
Array [
Array [
Object {
"attachments": Array [
Object {
"author_name": "Bridge Event",
"color": "#42f5aa",
"fallback": "NCG 0x2734048eC2892d111b4fbAB224400847544FC872 → wNCG 0x4029bC50b4747A037d38CF2197bCD335e22Ca301",
"fields": Array [
Object {
"title": "9c network transaction",
"value": "https://explorer.libplanet.io/9c-internal/transaction?TX-A",
},
Object {
"title": "Ethereum network transaction",
"value": "https://ropsten.etherscan.io/tx/TRANSACTION-HASH",
},
Object {
"title": "sender (NineChronicles)",
"value": "0x2734048eC2892d111b4fbAB224400847544FC872",
},
Object {
"title": "recipient (Ethereum)",
"value": "0x4029bC50b4747A037d38CF2197bCD335e22Ca301",
},
Object {
"title": "amount",
"value": "48651.5",
},
Object {
"title": "fee",
"value": "1298.5",
},
],
},
],
"text": "NCG → wNCG event occurred.",
},
],
Array [
Object {
"attachments": Array [
Object {
"author_name": "Bridge Event",
"color": "#42f5aa",
"fallback": "Refund NCG 100 in 150 to 0x2734048eC2892d111b4fbAB224400847544FC872",
"fields": Array [
Object {
"title": "Reason",
"value": "0x2734048eC2892d111b4fbAB224400847544FC872 tried to exchange 150 and already exchanged 49950 and users can exchange until 50000 in 24 hours so refund NCG as 100",
},
Object {
"title": "Address",
"value": "0x2734048eC2892d111b4fbAB224400847544FC872",
},
Object {
"title": "Request transaction",
"value": "https://explorer.libplanet.io/9c-internal/transaction?TX-SHOULD-REFUND",
},
Object {
"title": "Request Amount",
"value": "150",
},
Object {
"title": "Refund transaction",
"value": "https://explorer.libplanet.io/9c-internal/transaction?TX-ID",
},
Object {
"title": "Refund Amount",
"value": "100",
},
],
},
],
"text": "NCG refund event occurred.",
},
],
Array [
Object {
"attachments": Array [
Object {
"author_name": "Bridge Event",
"color": "#42f5aa",
"fallback": "Refund NCG 50 in 50 to 0x2734048eC2892d111b4fbAB224400847544FC872",
"fields": Array [
Object {
"title": "Reason",
"value": "Overflowed Amount 50 is lower than minimum NCG. Refund NCG.",
},
Object {
"title": "Address",
"value": "0x2734048eC2892d111b4fbAB224400847544FC872",
},
Object {
"title": "Request transaction",
"value": "https://explorer.libplanet.io/9c-internal/transaction?TX-SHOULD-REFUND",
},
Object {
"title": "Request Amount",
"value": "50",
},
Object {
"title": "Refund transaction",
"value": "https://explorer.libplanet.io/9c-internal/transaction?TX-ID",
},
Object {
"title": "Refund Amount",
"value": "50",
},
],
},
],
"text": "NCG refund event occurred.",
},
],
]
`;

exports[`NCGTransferredEventObserver notify pagerduty ethereum transfer error message - snapshot 1`] = `
Array [
Array [
Expand Down
101 changes: 101 additions & 0 deletions bridge/test/observers/nine-chronicles.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,107 @@ describe(NCGTransferredEventObserver.name, () => {
]);
});

it("If overflowed amount is lower than minimum, then refund check", async () => {
const amounts = new Map<string, number>();
mockExchangeHistoryStore.put.mockImplementation(
({ sender, amount }) => {
if (!amounts.has(sender)) {
amounts.set(sender, amount);
} else {
console.log(
"mockImpl",
sender,
amounts.get(sender)!,
amount
);
amounts.set(sender, amounts.get(sender)! + amount);
}

return Promise.resolve();
}
);

mockExchangeHistoryStore.transferredAmountInLast24Hours.mockImplementation(
(_, sender) => {
return Promise.resolve(amounts.get(sender) || 0);
}
);

const sender = "0x2734048eC2892d111b4fbAB224400847544FC872";
const wrappedNcgRecipient =
"0x4029bC50b4747A037d38CF2197bCD335e22Ca301";
function makeEvent(
wrappedNcgRecipient: string,
amount: string,
txId: TxId
) {
return {
amount: amount,
memo: wrappedNcgRecipient,
blockHash: "BLOCK-HASH",
txId: txId,
recipient: "0x6d29f9923C86294363e59BAaA46FcBc37Ee5aE2e",
sender: sender,
};
}

const events = [
makeEvent(wrappedNcgRecipient, "49950", "TX-A"),
makeEvent(wrappedNcgRecipient, "150", "TX-SHOULD-REFUND"),
];

await observer.notify({
blockHash: "BLOCK-HASH",
events,
});

expect(mockMonitorStateStore.store).toHaveBeenNthCalledWith(
1,
"nineChronicles",
{
blockHash: "BLOCK-HASH",
txId: "TX-A",
}
);

expect(mockMonitorStateStore.store).toHaveBeenNthCalledWith(
2,
"nineChronicles",
{
blockHash: "BLOCK-HASH",
txId: "TX-SHOULD-REFUND",
}
);

expect(mockExchangeHistoryStore.put).toHaveBeenNthCalledWith(1, {
amount: 49950,
network: "nineChronicles",
recipient: wrappedNcgRecipient,
sender: sender,
timestamp: expect.any(String),
tx_id: "TX-A",
});

expect(mockExchangeHistoryStore.put).toHaveBeenNthCalledWith(2, {
amount: 50,
network: "nineChronicles",
recipient: wrappedNcgRecipient,
sender: sender,
timestamp: expect.any(String),
tx_id: "TX-SHOULD-REFUND",
});

// applied fixed fee ( 10 NCG for transfer under 1000 NCG )
expect(mockWrappedNcgMinter.mint.mock.calls).toEqual([
[wrappedNcgRecipient, new Decimal(48651500000000000000000)],
]);

expect(
mockOpenSearchClient.to_opensearch.mock.calls
).toMatchSnapshot();
expect(mockSlackChannel.sendMessage.mock.calls).toMatchSnapshot();
});

for (const invalidMemo of [
"0x",
"",
Expand Down

0 comments on commit 17e2e48

Please sign in to comment.