Welcome, aspiring hacker!
On the right, you see the source code for a server that implements a simple bank. It has a subtle problem. Your job is not to fix it, but to exploit it to grow the total balance across the accounts from $3,000 to exactly $3,000,000,000 using no more than 60 transfers.
On the left, you have the bank client. You can use the buttons to transfer money manually, then write JS code. You may use functions transfer(accFrom, accTo, amount)
and getBalance(acc)
. Good luck!
xxxxxxxxxx
// You may use transfer(accFrom, accTo, amount) and getBalance(acc).
await transfer('A', 'B', 200);
await transfer('B', 'C', 200);
console.log("A=", await getBalance('A'),
"B=", await getBalance('B'),
"C=", await getBalance('C'));
xxxxxxxxxx
export type AccountId = string;
// This simple bank maintains account balances in this map.
const bankBalances: Map<AccountId, number> = new Map();
// Initialize the bankBalances to 3 accounts, each starting out
// with an initial balankce of $1000.
export async function initialize() {
bankBalances.clear();
bankBalances.set("A", 1000);
bankBalances.set("B", 1000);
bankBalances.set("C", 1000);
}
// Method to retrieve the balance for an account.
export async function getBalance(accountId: AccountId) {
const balance = bankBalances.get(accountId);
if (typeof balance !== 'number') {
throw new Error(`Invalid accountID ${accountId}`);
}
return balance;
}
// Transfer a given amount from one account to another. The amount
// must be positive, and must not exceed the balance in accFrom.
export async function transfer(
accFrom: AccountId, accTo: AccountId, amount: number
) {
if (accFrom === accTo) {
throw new Error(`Transfer accounts must be different`);
}
const balanceFrom = await getBalance(accFrom);
const balanceTo = await getBalance(accTo);
if (typeof amount !== 'number' || !(amount > 0)) {
throw new Error(`Invalid amount ${amount}`);
}
if (amount > balanceFrom) {
throw new Error(`Insufficient balance`);
}
await moneyLaunderingCheck(amount);
bankBalances.set(accFrom, balanceFrom - amount);
bankBalances.set(accTo, balanceTo + amount);
}
// Pretend to run some extra checks. These are quite fast, taking
// around 100ms (plus or minus), and happen to always pass.
export async function moneyLaunderingCheck(amount: number) {
return new Promise(resolve => setTimeout(resolve, 50 + Math.random() * 100));
}