Skip to content

Commit

Permalink
Merge pull request #767 from BoltzExchange/configurable-refs
Browse files Browse the repository at this point in the history
feat: configurable referral values
  • Loading branch information
michael1011 authored Jan 7, 2025
2 parents e04f3c0 + 964bf25 commit 2a77462
Show file tree
Hide file tree
Showing 31 changed files with 2,210 additions and 269 deletions.
43 changes: 43 additions & 0 deletions lib/cli/commands/GetReferral.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Arguments } from 'yargs';
import { GetReferralsRequest } from '../../proto/boltzrpc_pb';
import { ApiType, BuilderTypes } from '../BuilderComponents';
import { callback, loadBoltzClient } from '../Command';

export const command = 'getreferrals [id]';

export const describe = 'gets referrals from the database';

export const builder = {
id: {
type: 'string',
describe: 'optional ID of a referral to query for',
},
};

export const handler = (
argv: Arguments<BuilderTypes<typeof builder> & ApiType>,
): void => {
const req = new GetReferralsRequest();

if (argv.id) {
req.setId(argv.id);
}

loadBoltzClient(argv).getReferrals(
req,
callback((res) => {
const toPrint: Record<string, any> = {};

for (const entry of res.getReferralList()) {
toPrint[entry.getId()] = {
id: entry.getId(),
config: entry.hasConfig()
? JSON.parse(entry.getConfig()!)
: undefined,
};
}

return toPrint;
}),
);
};
70 changes: 70 additions & 0 deletions lib/cli/commands/SetReferral.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Arguments } from 'yargs';
import { deepMerge } from '../../Utils';
import {
GetReferralsRequest,
GetReferralsResponse,
SetReferralRequest,
} from '../../proto/boltzrpc_pb';
import { ApiType, BuilderTypes } from '../BuilderComponents';
import { callback, loadBoltzClient } from '../Command';

export const command = 'setreferral <id> [config] [amend]';

export const describe = 'updates the config of a referral';

export const builder = {
id: {
type: 'string',
describe: 'optional ID of the referral',
},
config: {
type: 'object',
describe: 'config changes to be applied',
},
amend: {
type: 'bool',
describe: 'amends the existing config instead of overwriting it',
},
};

export const handler = async (
argv: Arguments<BuilderTypes<typeof builder> & ApiType>,
): Promise<void> => {
const req = new SetReferralRequest();

if (argv.id) {
req.setId(argv.id);
}

const client = loadBoltzClient(argv);

if (argv.amend) {
const getReq = new GetReferralsRequest();
getReq.setId(argv.id);

const existing = (
await new Promise<GetReferralsResponse>((resolve, reject) =>
client.getReferrals(getReq, (error, response) => {
if (error) {
reject(error);
} else {
resolve(response);
}
}),
)
).getReferralList()[0];

if (existing.hasConfig()) {
const merged = JSON.parse(existing.getConfig()!);
deepMerge(merged, JSON.parse(argv.config));

req.setConfig(JSON.stringify(merged));
} else {
req.setConfig(argv.config);
}
} else {
req.setConfig(argv.config);
}

client.setReferral(req, callback());
};
65 changes: 61 additions & 4 deletions lib/db/Migration.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Transaction } from 'bitcoinjs-lib';
import bolt11, { RoutingInfo } from 'bolt11';
import { detectSwap } from 'boltz-core';
import { DataTypes, Op, Sequelize } from 'sequelize';
import { DataTypes, Op, QueryTypes, Sequelize } from 'sequelize';
import Logger from '../Logger';
import {
createApiCredential,
Expand All @@ -12,7 +12,7 @@ import {
getLightningCurrency,
splitPairId,
} from '../Utils';
import { SwapVersion, swapTypeToPrettyString } from '../consts/Enums';
import { SwapType, SwapVersion, swapTypeToPrettyString } from '../consts/Enums';
import { Currency } from '../wallet/WalletManager';
import ChainSwap from './models/ChainSwap';
import ChannelCreation from './models/ChannelCreation';
Expand All @@ -21,7 +21,7 @@ import LightningPayment, {
LightningPaymentStatus,
} from './models/LightningPayment';
import PendingLockupTransaction from './models/PendingLockupTransaction';
import Referral from './models/Referral';
import Referral, { ReferralConfig } from './models/Referral';
import ReverseSwap, { NodeType } from './models/ReverseSwap';
import Swap from './models/Swap';
import DatabaseVersionRepository from './repositories/DatabaseVersionRepository';
Expand Down Expand Up @@ -93,7 +93,7 @@ const decodeInvoice = (

// TODO: integration tests for actual migrations
class Migration {
private static latestSchemaVersion = 13;
private static latestSchemaVersion = 14;

private toBackFill: number[] = [];

Expand Down Expand Up @@ -600,6 +600,63 @@ class Migration {
break;
}

case 13: {
await this.sequelize
.getQueryInterface()
.addColumn(Referral.tableName, 'config', {
type: new DataTypes.JSON(),
allowNull: true,
});

const refs: {
id: string;
submarinePremium: number;
reversePremium: number;
chainPremium: number;
}[] = await this.sequelize.query(
'SELECT id, "submarinePremium", "reversePremium", "chainPremium" FROM referrals',
{
type: QueryTypes.SELECT,
},
);

await this.sequelize.transaction(async (transaction) => {
for (const ref of refs) {
await Referral.update(
{
config: {
premiums: {
[SwapType.Submarine]: ref.submarinePremium || undefined,
[SwapType.ReverseSubmarine]:
ref.reversePremium || undefined,
[SwapType.Chain]: ref.chainPremium || undefined,
},
} as ReferralConfig,
},
{
transaction,
where: {
id: ref.id,
},
},
);
}
});

await this.sequelize.query(
'ALTER TABLE referrals DROP COLUMN "submarinePremium"',
);
await this.sequelize.query(
'ALTER TABLE referrals DROP COLUMN "reversePremium"',
);
await this.sequelize.query(
'ALTER TABLE referrals DROP COLUMN "chainPremium"',
);

await this.finishMigration(versionRow.version, currencies);
break;
}

default:
throw `found unexpected database version ${versionRow.version}`;
}
Expand Down
86 changes: 68 additions & 18 deletions lib/db/models/Referral.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,28 @@
import { DataTypes, Model, Sequelize } from 'sequelize';
import { SwapType } from '../../consts/Enums';

type Limits = {
minimal?: number;
maximal?: number;
};

// TODO: direction of chain swaps
type Premiums = Partial<Record<SwapType, number>>;

type LimitsPerType = Partial<Record<SwapType, Limits>>;

type ReferralPairConfig = {
maxRoutingFee?: number;

limits?: LimitsPerType;
premiums?: Premiums;
};

type ReferralConfig = ReferralPairConfig & {
// Pair configs beat the ones of the type
pairs?: Record<string, ReferralPairConfig>;
};

type ReferralType = {
id: string;

Expand All @@ -10,9 +32,7 @@ type ReferralType = {
feeShare: number;
routingNode?: string;

submarinePremium?: number;
reversePremium?: number;
chainPremium?: number;
config?: ReferralConfig | null;
};

class Referral extends Model implements ReferralType {
Expand All @@ -24,9 +44,7 @@ class Referral extends Model implements ReferralType {
public feeShare!: number;
public routingNode?: string;

public submarinePremium?: number;
public reversePremium?: number;
public chainPremium?: number;
public config!: ReferralConfig | null;

public static load = (sequelize: Sequelize): void => {
Referral.init(
Expand All @@ -52,9 +70,7 @@ class Referral extends Model implements ReferralType {
allowNull: true,
unique: true,
},
submarinePremium: { type: new DataTypes.INTEGER(), allowNull: true },
reversePremium: { type: new DataTypes.INTEGER(), allowNull: true },
chainPremium: { type: new DataTypes.INTEGER(), allowNull: true },
config: { type: new DataTypes.JSON(), allowNull: true },
},
{
sequelize,
Expand All @@ -73,19 +89,53 @@ class Referral extends Model implements ReferralType {
);
};

public premiumForType = (type: SwapType) => {
switch (type) {
case SwapType.Submarine:
return this.submarinePremium;
public maxRoutingFeeRatio = (pair: string): number | undefined => {
return (
this.config?.pairs?.[pair]?.maxRoutingFee || this.config?.maxRoutingFee
);
};

case SwapType.ReverseSubmarine:
return this.reversePremium;
public limits = (pair: string, type: SwapType): Limits | undefined => {
return (
this.config?.pairs?.[pair]?.limits?.[type] || this.config?.limits?.[type]
);
};

public limitsForPairs = (
pairs: string[],
type: SwapType,
): Limits | undefined => {
for (const pair of pairs) {
const limits = this.config?.pairs?.[pair]?.limits?.[type];
if (limits !== undefined) {
return limits;
}
}

return this.config?.limits?.[type];
};

case SwapType.Chain:
return this.chainPremium;
public premium = (pair: string, type: SwapType): number | undefined => {
return (
this.config?.pairs?.[pair]?.premiums?.[type] ||
this.config?.premiums?.[type]
);
};

public premiumForPairs = (
pairs: string[],
type: SwapType,
): number | undefined => {
for (const pair of pairs) {
const premium = this.config?.pairs?.[pair]?.premiums?.[type];
if (premium !== undefined) {
return premium;
}
}

return this.config?.premiums?.[type];
};
}

export default Referral;
export { ReferralType };
export { ReferralType, ReferralConfig };
Loading

0 comments on commit 2a77462

Please sign in to comment.