Skip to content

Commit fa36acf

Browse files
more tests
1 parent 53c1607 commit fa36acf

1 file changed

Lines changed: 170 additions & 0 deletions

File tree

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import axios from 'axios';
2+
import fetch from 'node-fetch';
3+
import { config } from '../config/env.config';
4+
import { SendTransactionArgs, fundAddress, sendTransaction } from '../utils/chain.simulator.operations';
5+
6+
const sleep = (ms: number) => new Promise((res) => setTimeout(res, ms));
7+
8+
async function getJson(url: string): Promise<any | undefined> {
9+
for (let i = 0; i < 45; i++) {
10+
try {
11+
const resp = await fetch(url);
12+
if (resp.ok) {
13+
return await resp.json();
14+
}
15+
} catch {
16+
// ignore and retry
17+
}
18+
await sleep(1000);
19+
}
20+
return undefined;
21+
}
22+
23+
function pickBalance(payload: any): string | undefined {
24+
if (!payload || typeof payload !== 'object') return undefined;
25+
if (typeof payload.balance === 'string') return payload.balance;
26+
if (typeof payload.balance === 'number') return String(payload.balance);
27+
if (payload.data) {
28+
if (typeof payload.data.balance === 'string') return payload.data.balance;
29+
if (typeof payload.data.balance === 'number') return String(payload.data.balance);
30+
if (payload.data.account && payload.data.account.balance) {
31+
const b = payload.data.account.balance;
32+
if (typeof b === 'string') return b;
33+
if (typeof b === 'number') return String(b);
34+
}
35+
}
36+
return undefined;
37+
}
38+
39+
async function fetchApiBalance(baseUrl: string, address: string): Promise<bigint> {
40+
const url = `${baseUrl}/accounts/${address}`;
41+
const payload = await getJson(url);
42+
if (!payload) throw new Error(`No payload from ${url}`);
43+
const bal = pickBalance(payload);
44+
if (!bal) throw new Error(`No balance field in response from ${url}`);
45+
return BigInt(bal);
46+
}
47+
48+
async function fetchTxFeeFromSimulator(simUrl: string, txHash: string): Promise<bigint> {
49+
// Prefer explicit fee, fallback to gasUsed * gasPrice if needed
50+
for (let i = 0; i < 30; i++) {
51+
const resp = await axios.get(`${simUrl}/transaction/${txHash}?withResults=true`).catch(() => undefined);
52+
const tx = resp?.data?.data?.transaction;
53+
if (tx) {
54+
if (tx.fee) return BigInt(String(tx.fee));
55+
if (tx.gasUsed && (tx.gasPrice || tx.initialPaidFee)) {
56+
// gasPrice might be missing; initialPaidFee may be present. Use what we have.
57+
const gasUsed = BigInt(String(tx.gasUsed));
58+
if (tx.gasPrice) return gasUsed * BigInt(String(tx.gasPrice));
59+
if (tx.initialPaidFee) return BigInt(String(tx.initialPaidFee));
60+
}
61+
}
62+
await sleep(1000);
63+
}
64+
throw new Error(`Could not fetch fee for tx ${txHash}`);
65+
}
66+
67+
describe('State changes: native EGLD transfers reflect in balances', () => {
68+
const sim = config.chainSimulatorUrl;
69+
const api = config.apiServiceUrl;
70+
const alice = config.aliceAddress;
71+
const bob = config.bobAddress;
72+
73+
it('Alice -> Bob single transfer updates balances with exact fee accounting', async () => {
74+
// Ensure both parties have funds to simplify expectations
75+
await fundAddress(sim, alice);
76+
await fundAddress(sim, bob);
77+
78+
const beforeAlice = await fetchApiBalance(api, alice);
79+
const beforeBob = await fetchApiBalance(api, bob);
80+
81+
const amount = BigInt('1000000000000000000'); // 1 EGLD
82+
const txHash = await sendTransaction(new SendTransactionArgs({
83+
chainSimulatorUrl: sim,
84+
sender: alice,
85+
receiver: bob,
86+
value: amount.toString(),
87+
dataField: '',
88+
}));
89+
90+
const fee = await fetchTxFeeFromSimulator(sim, txHash);
91+
92+
const afterAlice = await fetchApiBalance(api, alice);
93+
const afterBob = await fetchApiBalance(api, bob);
94+
95+
expect(afterAlice).toBe(beforeAlice - amount - fee);
96+
expect(afterBob).toBe(beforeBob + amount);
97+
});
98+
99+
it('Round-trip transfers: Alice->Bob then Bob->Alice yields expected finals', async () => {
100+
await fundAddress(sim, alice);
101+
await fundAddress(sim, bob);
102+
103+
const startAlice = await fetchApiBalance(api, alice);
104+
const startBob = await fetchApiBalance(api, bob);
105+
106+
const amount1 = BigInt('2500000000000000000'); // 2.5 EGLD
107+
const hash1 = await sendTransaction(new SendTransactionArgs({
108+
chainSimulatorUrl: sim,
109+
sender: alice,
110+
receiver: bob,
111+
value: amount1.toString(),
112+
dataField: '',
113+
}));
114+
const fee1 = await fetchTxFeeFromSimulator(sim, hash1);
115+
116+
const amount2 = BigInt('1700000000000000000'); // 1.7 EGLD
117+
const hash2 = await sendTransaction(new SendTransactionArgs({
118+
chainSimulatorUrl: sim,
119+
sender: bob,
120+
receiver: alice,
121+
value: amount2.toString(),
122+
dataField: '',
123+
}));
124+
const fee2 = await fetchTxFeeFromSimulator(sim, hash2);
125+
126+
const endAlice = await fetchApiBalance(api, alice);
127+
const endBob = await fetchApiBalance(api, bob);
128+
129+
// Alice: -amount1 - fee1 + amount2
130+
expect(endAlice).toBe(startAlice - amount1 - fee1 + amount2);
131+
// Bob: +amount1 - fee2 - amount2
132+
expect(endBob).toBe(startBob + amount1 - fee2 - amount2);
133+
});
134+
135+
it('Multiple sequential transfers accumulate correctly (Alice->Bob x3)', async () => {
136+
await fundAddress(sim, alice);
137+
await fundAddress(sim, bob);
138+
139+
const startAlice = await fetchApiBalance(api, alice);
140+
const startBob = await fetchApiBalance(api, bob);
141+
142+
const amounts = [
143+
BigInt('100000000000000000'), // 0.1 EGLD
144+
BigInt('200000000000000000'), // 0.2 EGLD
145+
BigInt('300000000000000000'), // 0.3 EGLD
146+
];
147+
148+
let totalSent = BigInt(0);
149+
let totalFees = BigInt(0);
150+
for (const amt of amounts) {
151+
const hash = await sendTransaction(new SendTransactionArgs({
152+
chainSimulatorUrl: sim,
153+
sender: alice,
154+
receiver: bob,
155+
value: amt.toString(),
156+
dataField: '',
157+
}));
158+
const fee = await fetchTxFeeFromSimulator(sim, hash);
159+
totalSent += amt;
160+
totalFees += fee;
161+
}
162+
163+
const endAlice = await fetchApiBalance(api, alice);
164+
const endBob = await fetchApiBalance(api, bob);
165+
166+
expect(endAlice).toBe(startAlice - totalSent - totalFees);
167+
expect(endBob).toBe(startBob + totalSent);
168+
});
169+
});
170+

0 commit comments

Comments
 (0)