Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

setup bulla swap #65

Merged
merged 5 commits into from
Nov 1, 2024
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
501 changes: 501 additions & 0 deletions bulla-contracts/abis/BullaSwap.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion bulla-contracts/config/sepolia.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
"frendLend": { "address": "0x3E058834CE20A54F0755889c008D3fF62D33cE85", "startBlock": 5096555 },
"instantPayment": { "address": "0x1cD1A83C2965CB7aD55d60551877Eb390e9C3d7A", "startBlock": 5096555 },
"bullaFactoring": { "address": "0x0000000000000000000000000000000000000000", "startBlock": 6631476 },
"bullaFactoringv2": { "address": "0xDF0fCe31285dcAB9124bF763AB9E5466723BeF35", "startBlock": 6812207 }
"bullaFactoringv2": { "address": "0xDF0fCe31285dcAB9124bF763AB9E5466723BeF35", "startBlock": 6812207 },
"bullaSwap": { "address": "0xdf30BE5964a7E26b49551a430e85B51148A7b95E", "startBlock": 6982025 }
}
2 changes: 1 addition & 1 deletion bulla-contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"scripts": {
"codegen": "yarn prep:sepolia && graph codegen",
"build": "yarn prep:sepolia && graph codegen && graph build",
"test": "yarn && yarn prep:goerli && graph test -v 0.2.2",
"test": "rm -rf tests/.bin && yarn && yarn prep:goerli && graph test -v 0.2.2",
"coverage": "yarn prep:goerli && graph test -- -c",
"prep:mainnet": "mustache config/mainnet.json template.yaml > subgraph.yaml",
"prep:goerli": "mustache config/goerli.json template.yaml > subgraph.yaml",
Expand Down
37 changes: 37 additions & 0 deletions bulla-contracts/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,42 @@ type InvoiceReconciledEvent implements IEventLog & IPoolTransaction @entity {
claim: Claim!
}

type OrderERC20 @entity {
id: ID! # orderId
orderId: BigInt!
expiry: BigInt!
signerWallet: Bytes! #address
signerToken: Token! #address
signerAmount: BigInt!
senderWallet: Bytes! #address
senderToken: Token! #address
senderAmount: BigInt!
}

type OrderCreatedEvent implements IEventLog @entity {
id: ID!
order: OrderERC20!
sender: Bytes! #address
signerWallet: Bytes! #address
eventName: String!
blockNumber: BigInt!
transactionHash: Bytes!
logIndex: BigInt!
timestamp: BigInt!
}

type OrderExecutedEvent implements IEventLog @entity {
id: ID!
order: OrderERC20!
sender: Bytes! #address
signerWallet: Bytes! #address
eventName: String!
blockNumber: BigInt!
transactionHash: Bytes!
logIndex: BigInt!
timestamp: BigInt!
}

type LoanOfferedEvent implements IEventLog @entity {
id: ID!
loanId: String!
Expand Down Expand Up @@ -448,6 +484,7 @@ type User @entity {
financeEvents: [IEventLog!]!
frendLendEvents: [IEventLog!]!
factoringEvents: [IEventLog!]!
swapEvents: [IEventLog!]!
}

type PoolPnl @entity {
Expand Down
17 changes: 17 additions & 0 deletions bulla-contracts/src/functions/BullaSwap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { BigInt, ethereum } from "@graphprotocol/graph-ts";
import { OrderCreated, OrderExecuted } from "../../generated/BullaSwap/BullaSwap";
import { OrderCreatedEvent, OrderExecutedEvent } from "../../generated/schema";

export const getOrderCreatedEventId = (orderId: BigInt, event: ethereum.Event): string =>
"OrderCreated-" + orderId.toString() + "-" + event.transaction.hash.toHexString() + "-" + event.logIndex.toString();

export const createOrderCreatedEvent = (orderId: BigInt, event: OrderCreated): OrderCreatedEvent => {
return new OrderCreatedEvent(getOrderCreatedEventId(orderId, event));
};

export const getOrderExecutedEventId = (orderId: BigInt, event: ethereum.Event): string =>
"OrderExecuted-" + orderId.toString() + "-" + event.transaction.hash.toHexString() + "-" + event.logIndex.toString();

export const createOrderExecutedEvent = (orderId: BigInt, event: OrderExecuted): OrderExecutedEvent => {
return new OrderExecutedEvent(getOrderExecutedEventId(orderId, event));
};
21 changes: 12 additions & 9 deletions bulla-contracts/src/mappings/BullaFactoring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,18 +255,21 @@ export function handleInvoiceUnfactoredV2(event: InvoiceUnfactored): void {
const targetFees = getTargetFeesAndTaxes(event.address, "v2", ev.invoiceId);
const approvedInvoice = BullaFactoringv2.bind(event.address).approvedInvoices(ev.invoiceId);

const trueProcotolFee = targetFees[1] // targetProcotolFee
.times(ev.interestToCharge)
.div(targetFees[0]); // targetInterest
const trueProcotolFee = targetFees[0].isZero()
? BigInt.fromI32(0)
: targetFees[1] // targetProcotolFee
.times(ev.interestToCharge)
.div(targetFees[0]); // targetInterest

const trueTax = calculateTax(event.address, "v2", ev.interestToCharge);

const actualDays = (event.block.timestamp
.minus(approvedInvoice.getFundedTimestamp()))
.div(BigInt.fromI32(3600 * 24));
const actualDays = event.block.timestamp.minus(approvedInvoice.getFundedTimestamp()).div(BigInt.fromI32(3600 * 24));

const adminFee =
actualDays.times(BigInt.fromI32(approvedInvoice.getAdminFeeBps())).times(approvedInvoice.getTrueFaceValue()).div(BigInt.fromI32(365)).div(BigInt.fromI32(10_000));
const adminFee = actualDays
.times(BigInt.fromI32(approvedInvoice.getAdminFeeBps()))
.times(approvedInvoice.getTrueFaceValue())
.div(BigInt.fromI32(365))
.div(BigInt.fromI32(10_000));

InvoiceUnfactoredEvent.invoiceId = underlyingClaim.id;
InvoiceUnfactoredEvent.originalCreditor = ev.originalCreditor;
Expand Down Expand Up @@ -602,7 +605,7 @@ export function handleActivePaidInvoicesReconciled(event: ActivePaidInvoicesReco
originalCreditor.save();
pnlTotal = pnlTotal.plus(trueNetInterest);
}

const pool_pnl = getOrCreatePoolProfitAndLoss(event, pnlTotal);
const price_per_share = getOrCreatePricePerShare(event, version);
const historical_factoring_statistics = getOrCreateHistoricalFactoringStatistics(event, version);
Expand Down
82 changes: 82 additions & 0 deletions bulla-contracts/src/mappings/BullaSwap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { OrderCreated, OrderExecuted } from "../../generated/BullaSwap/BullaSwap";
import { OrderERC20 } from "../../generated/schema";
import { createOrderCreatedEvent, createOrderExecutedEvent } from "../functions/BullaSwap";
import { getOrCreateToken, getOrCreateUser } from "../functions/common";

export function handleOrderCreated(event: OrderCreated): void {
const ev = event.params;
const orderId = ev.orderId;

// Create the order entity
const order = new OrderERC20(orderId.toString());
order.orderId = orderId;
order.expiry = ev.order.expiry;
order.signerWallet = ev.order.signerWallet;
order.signerToken = getOrCreateToken(ev.order.signerToken).id;
order.signerAmount = ev.order.signerAmount;
order.senderWallet = ev.order.senderWallet;
order.senderToken = getOrCreateToken(ev.order.senderToken).id;
order.senderAmount = ev.order.senderAmount;
order.save();

// Create the event entity
const orderCreatedEvent = createOrderCreatedEvent(orderId, event);
orderCreatedEvent.order = order.id;
orderCreatedEvent.sender = ev.sender;
orderCreatedEvent.signerWallet = ev.order.signerWallet;
orderCreatedEvent.eventName = "OrderCreated";
orderCreatedEvent.blockNumber = event.block.number;
orderCreatedEvent.transactionHash = event.transaction.hash;
orderCreatedEvent.logIndex = event.logIndex;
orderCreatedEvent.timestamp = event.block.timestamp;

// Update user entities
const sender = getOrCreateUser(ev.sender);
sender.swapEvents = sender.swapEvents ? sender.swapEvents.concat([orderCreatedEvent.id]) : [orderCreatedEvent.id];
sender.save();

const signer = getOrCreateUser(ev.signerWallet);
signer.swapEvents = signer.swapEvents ? signer.swapEvents.concat([orderCreatedEvent.id]) : [orderCreatedEvent.id];
signer.save();

orderCreatedEvent.save();
}

export function handleOrderExecuted(event: OrderExecuted): void {
const ev = event.params;
const orderId = ev.orderId;

// Create the order entity
const order = new OrderERC20(orderId.toString());
order.orderId = orderId;
order.expiry = ev.order.expiry;
order.signerWallet = ev.order.signerWallet;
order.signerToken = getOrCreateToken(ev.order.signerToken).id;
order.signerAmount = ev.order.signerAmount;
order.senderWallet = ev.order.senderWallet;
order.senderToken = getOrCreateToken(ev.order.senderToken).id;
order.senderAmount = ev.order.senderAmount;
order.save();

// Create the event entity
const orderExecutedEvent = createOrderExecutedEvent(orderId, event);
orderExecutedEvent.order = order.id;
orderExecutedEvent.sender = ev.sender;
orderExecutedEvent.signerWallet = ev.order.signerWallet;
orderExecutedEvent.eventName = "OrderExecuted";
orderExecutedEvent.blockNumber = event.block.number;
orderExecutedEvent.transactionHash = event.transaction.hash;
orderExecutedEvent.logIndex = event.logIndex;
orderExecutedEvent.timestamp = event.block.timestamp;

// Update user entities
const sender = getOrCreateUser(ev.sender);
sender.swapEvents = sender.swapEvents ? sender.swapEvents.concat([orderExecutedEvent.id]) : [orderExecutedEvent.id];
sender.save();

const recipient = getOrCreateUser(ev.recipient);
recipient.swapEvents = recipient.swapEvents ? recipient.swapEvents.concat([orderExecutedEvent.id]) : [orderExecutedEvent.id];
recipient.save();

orderExecutedEvent.save();
}
24 changes: 23 additions & 1 deletion bulla-contracts/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -310,4 +310,26 @@ dataSources:
handler: handleSharesRedeemedWithAttachmentV2
- event: InvoiceImpaired(indexed uint256,uint256,uint256)
handler: handleInvoiceImpairedV2
file: ./src/mappings/BullaFactoring.ts
file: ./src/mappings/BullaFactoring.ts
- kind: ethereum/contract
name: BullaSwap
network: {{ network }}
source:
address: "{{ bullaSwap.address }}"
startBlock: {{ bullaSwap.startBlock }}
abi: BullaSwap
mapping:
kind: ethereum/events
apiVersion: {{ apiVersion }}
language: wasm/assemblyscript
entities:
- BullaSwap
abis:
- name: BullaSwap
file: ./abis/BullaSwap.json
eventHandlers:
- event: OrderCreated(indexed uint256,indexed address,indexed address,(uint256,uint256,address,address,uint256,address,address,uint256))
handler: handleOrderCreated
- event: OrderExecuted(indexed uint256,indexed address,indexed address,(uint256,uint256,address,address,uint256,address,address,uint256))
handler: handleOrderExecuted
file: ./src/mappings/BullaSwap.ts
87 changes: 87 additions & 0 deletions bulla-contracts/tests/BullaSwap.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { BigInt, log } from "@graphprotocol/graph-ts";
import { assert, test } from "matchstick-as/assembly/index";

import { handleOrderCreated, handleOrderExecuted } from "../src/mappings/BullaSwap";
import { ADDRESS_1, ADDRESS_2, ADDRESS_3, ADDRESS_4, afterEach, setupContracts } from "./helpers";
import { newOrderCreatedEvent, newOrderExecutedEvent } from "./functions/BullaSwap.testtools";
import { User } from "../generated/schema";
import { getOrderCreatedEventId, getOrderExecutedEventId } from "../src/functions/BullaSwap";

test("it handles OrderCreated event", () => {
const orderId = BigInt.fromI32(3);
const expiry = BigInt.fromI32(100);
const signerWallet = ADDRESS_1;
const signerToken = ADDRESS_2;
const signerAmount = BigInt.fromI32(10000);
const senderWallet = ADDRESS_3;
const senderToken = ADDRESS_4;
const senderAmount = BigInt.fromI32(10000);

setupContracts();
const signerUser = new User(signerWallet.toHexString());
signerUser.swapEvents = [];
signerUser.save();

const senderUser = new User(senderWallet.toHexString());
senderUser.swapEvents = [];
senderUser.save();

const timestamp = BigInt.fromI32(100);
const blockNum = BigInt.fromI32(100);

const orderCreatedEvent = newOrderCreatedEvent(orderId, signerWallet, signerToken, signerAmount, senderWallet, senderToken, senderAmount, expiry);
orderCreatedEvent.block.timestamp = timestamp;
orderCreatedEvent.block.number = blockNum;

handleOrderCreated(orderCreatedEvent);

const orderCreatedEventId = getOrderCreatedEventId(orderId, orderCreatedEvent);
assert.fieldEquals("OrderCreatedEvent", orderCreatedEventId, "signerWallet", signerWallet.toHexString());
assert.fieldEquals("OrderCreatedEvent", orderCreatedEventId, "sender", senderWallet.toHexString());
assert.fieldEquals("OrderERC20", orderId.toString(), "orderId", orderId.toString());

log.info("✅ should create a OrderCreated event", []);

afterEach();
});

test("it handles OrderExecuted event", () => {
const orderId = BigInt.fromI32(3);
const expiry = BigInt.fromI32(100);
const signerWallet = ADDRESS_1;
const signerToken = ADDRESS_2;
const signerAmount = BigInt.fromI32(10000);
const senderWallet = ADDRESS_3;
const senderToken = ADDRESS_4;
const senderAmount = BigInt.fromI32(10000);

setupContracts();
const signerUser = new User(signerWallet.toHexString());
signerUser.swapEvents = [];
signerUser.save();

const senderUser = new User(senderWallet.toHexString());
senderUser.swapEvents = [];
senderUser.save();

const timestamp = BigInt.fromI32(100);
const blockNum = BigInt.fromI32(100);

const orderExecutedEvent = newOrderExecutedEvent(orderId, signerWallet, signerToken, signerAmount, senderWallet, senderToken, senderAmount, expiry);
orderExecutedEvent.block.timestamp = timestamp;
orderExecutedEvent.block.number = blockNum;

handleOrderExecuted(orderExecutedEvent);

const orderExecutedEventId = getOrderExecutedEventId(orderId, orderExecutedEvent);
assert.fieldEquals("OrderExecutedEvent", orderExecutedEventId, "signerWallet", signerWallet.toHexString());
assert.fieldEquals("OrderExecutedEvent", orderExecutedEventId, "sender", senderWallet.toHexString());
assert.fieldEquals("OrderERC20", orderId.toString(), "orderId", orderId.toString());

log.info("✅ should create a OrderExecuted event", []);

afterEach();
});

// exporting for test coverage
export { handleOrderCreated, handleOrderExecuted };
Loading
Loading