Skip to content
Open
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
1,320 changes: 1 addition & 1,319 deletions abi/BNPLMarketV3.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions data/contractsConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"BNPLContract":{
"address": "0x260C32eB38D1403bd51B83B5b7047812C70B7845"
},

"seaport":{
"address": "0x00000000006c3852cbef3e08e8df289169ede581"
},
Expand Down
40 changes: 20 additions & 20 deletions lib/bnpl-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import { parseFeeMethod, parseHowToCall, parseMetadata, parseSaleKind, WyvernAto


import {BigNumber, Contract, ethers,Signer,Wallet} from 'ethers'

import moment from 'moment'



import { NULL_BLOCK_HASH } from 'opensea-js/lib/constants'

import { OpenseaHelper, SignedOrder, UnhashedOrder } from '../lib/opensea-helper'
import { SubmitBidArgs, ContractsConfig, CraResponse, ExecuteParams, BasicOrderParams } from "./types"
import { SubmitBidArgs, ContractsConfig, CraResponse, ExecuteParams, BasicOrderParams, DomainData } from "./types"
import { axiosPostRequest } from "./axios-helper"
import { craSign } from "./cra-signer"
import { ISignOfferSignerConfig, signOffchainOffer } from "@clarity-credit/anpl-sdk"


require('dotenv').config()
Expand Down Expand Up @@ -71,29 +71,29 @@ export function buildExecuteParams(inputData:CraResponse ): ExecuteParams {

}



export async function generateBNPLOrderSignature(
submitBidArgs:SubmitBidArgs,
basicOrderParams:BasicOrderParams,
domainData: DomainData,
wallet: Wallet,
chainId: number,
implementationContractAddress: string
){

let signatureVersion = 3

let signatureResponse = await craSign(
submitBidArgs,
basicOrderParams,
chainId,
signatureVersion,
implementationContractAddress,
wallet,
true)
const signConfig :ISignOfferSignerConfig = {
submitBidArgs,
basicOrderParams,
domainData,

//@ts-ignore
signer:wallet,

}

if(signatureResponse.success){
return signatureResponse.data
}


return undefined
const signature = await signOffchainOffer(signConfig)

return signature

}
225 changes: 225 additions & 0 deletions lib/reservoir-helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@

import axios from 'axios'
import { BigNumber } from 'ethers'
import { AdditionalRecipient, BasicOrderParams, BasicOrderParamsResponse, ReservoirOrder, SeaportProtocolData, SeaportProtocolParameters } from './types'

require('dotenv').config()

const RESERVOIR_API_KEY = process.env.RESERVOIR_API_KEY!

const BLANK_SIGNATURE =
'0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'


export async function fetchReservoirOrderById(
{orderId}:{orderId:string}
) : Promise<any> {


const apiUrl = new URL('https://api.reservoir.tools/orders/asks/v4')

apiUrl.searchParams.set('ids', `${orderId}`)
apiUrl.searchParams.set('includeRawData', 'true')

const headers = {
'x-api-key': RESERVOIR_API_KEY,
'accept':'*/*',

}

console.log(apiUrl.toString())
const response = await axios.get(apiUrl.toString(), { headers })


const orders = response.data.orders

if(!orders || orders.length == 0) return undefined

return orders[0]

}



export function formatReservoirOrder(order: ReservoirOrder): {
order: ReservoirOrder
basicOrderParams?: BasicOrderParamsResponse
} {


if(!order.rawData.consideration){
console.error("No consideration within raw data")
return {order}
}

const protocolData: SeaportProtocolData = {
parameters: {
consideration: order.rawData.consideration,
offerer: order.rawData.offerer,
zone: order.rawData.zone,
offer: order.rawData.offer,
startTime: order.rawData.startTime,
endTime: order.rawData.endTime,
orderType: order.rawData.orderType,
zoneHash: order.rawData.zoneHash,
salt: order.rawData.salt,
totalOriginalConsiderationItems:
order.rawData.consideration.length.toString(),
conduitKey: order.rawData.conduitKey,

parameterOrderType: order.rawData.orderType, //is this correct ? probably.
},
signature: order.rawData.signature,
}

const generatedOrderParams: BasicOrderParams =
generateBasicOrderParamsFromSeaport(protocolData)

return {
order: order,
basicOrderParams: formatBasicOrderParams(generatedOrderParams),
}
}


export function generateBasicOrderParamsFromSeaport(
orderData: SeaportProtocolData
): BasicOrderParams {
const orderParameters: SeaportProtocolParameters = orderData.parameters

const basicOrderParams: BasicOrderParams = {
considerationToken: orderParameters.consideration[0].token, //payment token
considerationIdentifier: BigNumber.from(
orderParameters.consideration[0].identifierOrCriteria
), // not sure what significance this has
considerationAmount: BigNumber.from(
orderParameters.consideration[0].endAmount
), // using the first element in the consideration array as per Andy's suggestion
offerer: orderParameters.offerer,
zone: orderParameters.zone,
offerToken: orderParameters.offer[0].token, //nft_contract
offerIdentifier: BigNumber.from(
orderParameters.offer[0].identifierOrCriteria
), //token id
offerAmount: orderParameters.offer[0].endAmount, //quantity
basicOrderType: getBasicOrderType(
orderParameters.orderType,
orderParameters.consideration[0].itemType,
orderParameters.offer[0].itemType
),

startTime: BigNumber.from(orderParameters.startTime),
endTime: BigNumber.from(orderParameters.endTime),
zoneHash: orderParameters.zoneHash,
salt: BigNumber.from(orderParameters.salt).toHexString(),
offererConduitKey: orderParameters.conduitKey,
fulfillerConduitKey:
'0x0000000000000000000000000000000000000000000000000000000000000000',
totalOriginalAdditionalRecipients: BigNumber.from(
orderParameters.totalOriginalConsiderationItems
).sub(1),
additionalRecipients: getAdditionalRecipients(orderParameters),
signature: orderData.signature ? orderData.signature : BLANK_SIGNATURE,
}
return basicOrderParams
}



function getAdditionalRecipients(parameters: SeaportProtocolParameters): any[] {
const recipientsArray: object[] = []

for (let i = 1; i < parameters.consideration.length; i++) {
const additionalRecipient = {
amount: BigNumber.from(parameters.consideration[i].endAmount),
recipient: parameters.consideration[i].recipient,
}

recipientsArray.push(additionalRecipient)
}
return recipientsArray
}


export function formatBasicOrderParams(
basicOrderParams: any
): BasicOrderParamsResponse {
return {
considerationToken: basicOrderParams.considerationToken,
considerationIdentifier: BigNumber.from(
basicOrderParams.considerationIdentifier
).toString(),
considerationAmount: BigNumber.from(
basicOrderParams.considerationAmount
).toString(),
offerer: basicOrderParams.offerer,
zone: basicOrderParams.zone,
offerToken: basicOrderParams.offerToken,
offerIdentifier: BigNumber.from(
basicOrderParams.offerIdentifier
).toString(),
offerAmount: BigNumber.from(basicOrderParams.offerAmount).toString(),
basicOrderType: basicOrderParams.basicOrderType,
startTime: BigNumber.from(basicOrderParams.startTime).toString(),
endTime: BigNumber.from(basicOrderParams.endTime).toString(),
zoneHash: basicOrderParams.zoneHash,
salt: basicOrderParams.salt,
offererConduitKey: basicOrderParams.offererConduitKey,
fulfillerConduitKey: basicOrderParams.fulfillerConduitKey,
totalOriginalAdditionalRecipients: BigNumber.from(
basicOrderParams.totalOriginalAdditionalRecipients
).toString(),
additionalRecipients: basicOrderParams.additionalRecipients.map(
(r: AdditionalRecipient) => {
return {
amount: BigNumber.from(r.amount).toString(),
recipient: r.recipient,
}
}
),
signature: basicOrderParams.signature,
}
}


function getBasicOrderType(
orderType: number,
considerationItemType: number,
offerItemType: number
): number {
let basicOrderRouteType = 10
//refer to the above enums to understand if else statements
if (considerationItemType == 0 && offerItemType == 2) {
basicOrderRouteType = 0
} else if (
considerationItemType == 0 &&
(offerItemType == 3 || offerItemType == 5)
) {
basicOrderRouteType = 1
} else if (
considerationItemType == 1 &&
(offerItemType == 2 || offerItemType == 4)
) {
basicOrderRouteType = 2
} else if (
considerationItemType == 1 &&
(offerItemType == 3 || offerItemType == 5)
) {
basicOrderRouteType = 3
} else if (
(considerationItemType == 2 || considerationItemType == 4) &&
offerItemType == 1
) {
basicOrderRouteType = 4
} else if (
(considerationItemType == 3 || considerationItemType == 5) &&
offerItemType == 1
) {
basicOrderRouteType = 5
}


const basicOrderType = orderType + 4 * basicOrderRouteType

return basicOrderType
}
45 changes: 45 additions & 0 deletions lib/teller-v2-lending-helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { BigNumber } from 'ethers'

const FACTOR = 10_000

/*
For ANPL, marketFeePct is 500 (5%) and protocolFeePct is 5 (0.05%)

*/

export function calculatePrincipalRequiredForBorrowerPayout(
expectedBorrowerPayment: BigNumber, //5000 ///amount of wei THE BORROWER must get out of this loan
marketFeePct: BigNumber, //500
protocolFeePct: BigNumber //5
): BigNumber {
const totalFeesPct = marketFeePct.add(protocolFeePct)

const principalRequired = expectedBorrowerPayment
.mul(BigNumber.from(FACTOR))
.div(BigNumber.from(FACTOR).sub(totalFeesPct)) //rounding UP

// ---- If we are off by 1, subtract 1
const calculatedBorrowerPayment = calculateBorrowerPayoutFromLoanPrincipal(
principalRequired,
marketFeePct,
protocolFeePct
)
const offByError = calculatedBorrowerPayment.sub(expectedBorrowerPayment)

return principalRequired.sub(offByError)
}

//this is how it happens in solidity
export function calculateBorrowerPayoutFromLoanPrincipal(
loanPrincipal: BigNumber,
marketFeePct: BigNumber,
protocolFeePct: BigNumber
): BigNumber {
const marketFee = loanPrincipal.mul(marketFeePct).div(FACTOR)

const protocolFee = loanPrincipal.mul(protocolFeePct).div(FACTOR)

const borrowerPayout = loanPrincipal.sub(marketFee).sub(protocolFee)

return borrowerPayout
}
Loading