Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -90,42 +90,12 @@ describe('RealUnitBlockchainService', () => {
});

describe('getBrokerbotSellPrice', () => {
it('should query BrokerBot contract and apply default 0.5% slippage', async () => {
it('should query BrokerBot contract and return exact amount', async () => {
// BrokerBot returns 1000 ZCHF (in Wei) for 10 shares
mockReadContract.mockResolvedValue(BigInt('1000000000000000000000'));

const result = await service.getBrokerbotSellPrice(MOCK_BROKERBOT_ADDRESS, 10);

// 1000 ZCHF * (1 - 0.005) = 995 ZCHF
expect(result.zchfAmountWei).toBe(BigInt('995000000000000000000'));
});

it('should calculate correctly for 1 share', async () => {
// BrokerBot returns 100 ZCHF for 1 share
mockReadContract.mockResolvedValue(BigInt('100000000000000000000'));

const result = await service.getBrokerbotSellPrice(MOCK_BROKERBOT_ADDRESS, 1);

// 100 * 0.995 = 99.5 ZCHF
expect(result.zchfAmountWei).toBe(BigInt('99500000000000000000'));
});

it('should accept custom slippage in basis points', async () => {
// BrokerBot returns 1000 ZCHF for 10 shares
mockReadContract.mockResolvedValue(BigInt('1000000000000000000000'));

const result = await service.getBrokerbotSellPrice(MOCK_BROKERBOT_ADDRESS, 10, 100); // 1% slippage

// 1000 * (1 - 0.01) = 990 ZCHF
expect(result.zchfAmountWei).toBe(BigInt('990000000000000000000'));
});

it('should handle zero slippage', async () => {
mockReadContract.mockResolvedValue(BigInt('1000000000000000000000'));

const result = await service.getBrokerbotSellPrice(MOCK_BROKERBOT_ADDRESS, 10, 0);

// Full amount with no slippage
expect(result.zchfAmountWei).toBe(BigInt('1000000000000000000000'));
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,7 @@ export class RealUnitBlockchainService {
};
}

async getBrokerbotSellPrice(
brokerbotAddress: string,
shares: number,
slippageBps = 50,
): Promise<{ zchfAmountWei: bigint }> {
async getBrokerbotSellPrice(brokerbotAddress: string, shares: number): Promise<{ zchfAmountWei: bigint }> {
const blockchain = [Environment.DEV, Environment.LOC].includes(GetConfig().environment)
? Blockchain.SEPOLIA
: Blockchain.ETHEREUM;
Expand All @@ -150,21 +146,17 @@ export class RealUnitBlockchainService {
});

// Call getSellPrice on the BrokerBot contract
const sellPriceWei = (await publicClient.readContract({
const zchfAmountWei = (await publicClient.readContract({
address: brokerbotAddress as `0x${string}`,
abi: BROKERBOT_ABI,
functionName: 'getSellPrice',
args: [BigInt(shares)],
} as any)) as bigint;

if (sellPriceWei === 0n) {
if (zchfAmountWei === 0n) {
throw new Error('BrokerBot returned zero sell price');
}

// Apply slippage buffer (reduce expected amount to account for price movement)
const slippageFactor = BigInt(10000 - slippageBps);
const zchfAmountWei = (sellPriceWei * slippageFactor) / BigInt(10000);

return { zchfAmountWei };
}
}
3 changes: 2 additions & 1 deletion src/subdomains/supporting/realunit/realunit.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -980,7 +980,8 @@ export class RealUnitService {
throw new BadRequestException('Delegation delegator does not match user address');
}

// Calculate expected ZCHF amount from BrokerBot (with slippage buffer)
// Calculate expected ZCHF amount from BrokerBot
// If price drops between quote and execution, transaction reverts safely and user can retry
const [{ zchfAmountWei }, zchfAsset] = await Promise.all([
this.blockchainService.getBrokerbotSellPrice(this.getBrokerbotAddress(), Math.floor(request.amount)),
this.getZchfAsset(),
Expand Down
Loading