@provable-games/budokan-sdk 0.1.24 → 0.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +610 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +307 -3
- package/dist/index.d.ts +307 -3
- package/dist/index.js +588 -5
- package/dist/index.js.map +1 -1
- package/dist/{player-C2GE9Lop.d.cts → player-CbAYHoW8.d.cts} +49 -7
- package/dist/{player-C2GE9Lop.d.ts → player-CbAYHoW8.d.ts} +49 -7
- package/dist/react.cjs +163 -4
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +163 -4
- package/dist/react.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -209,11 +209,37 @@ function camelToSnake(obj) {
|
|
|
209
209
|
return obj;
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
+
// src/phase/index.ts
|
|
213
|
+
function tournamentPhase(t, nowSeconds) {
|
|
214
|
+
const createdAt = Number(t.createdAtOnchain ?? NaN);
|
|
215
|
+
if (!Number.isFinite(createdAt)) return null;
|
|
216
|
+
const regStartDelay = Number(t.registrationStartDelay ?? t.schedule?.registrationStartDelay ?? 0);
|
|
217
|
+
const regEndDelay = Number(t.registrationEndDelay ?? t.schedule?.registrationEndDelay ?? 0);
|
|
218
|
+
const gameStartDelay = Number(t.gameStartDelay ?? t.schedule?.gameStartDelay ?? 0);
|
|
219
|
+
const gameEndDelay = Number(t.gameEndDelay ?? t.schedule?.gameEndDelay ?? 0);
|
|
220
|
+
const submissionDuration = Number(t.submissionDuration ?? t.schedule?.submissionDuration ?? 0);
|
|
221
|
+
const now = nowSeconds ?? Math.floor(Date.now() / 1e3);
|
|
222
|
+
const hasReg = regStartDelay > 0 || regEndDelay > 0;
|
|
223
|
+
const regStart = createdAt + regStartDelay;
|
|
224
|
+
const regEnd = regStart + regEndDelay;
|
|
225
|
+
const gameStart = createdAt + gameStartDelay;
|
|
226
|
+
const gameEnd = gameStart + gameEndDelay;
|
|
227
|
+
const subEnd = gameEnd + submissionDuration;
|
|
228
|
+
if (hasReg && now < regStart) return "scheduled";
|
|
229
|
+
if (hasReg && now < regEnd) return "registration";
|
|
230
|
+
if (now < gameStart) return "staging";
|
|
231
|
+
if (now < gameEnd) return "live";
|
|
232
|
+
if (now < subEnd) return "submission";
|
|
233
|
+
return "finalized";
|
|
234
|
+
}
|
|
235
|
+
|
|
212
236
|
// src/api/tournaments.ts
|
|
213
237
|
function normalizeTournament(raw) {
|
|
214
238
|
const t = snakeToCamel(raw);
|
|
215
239
|
const id = t.id ?? t.tournamentId;
|
|
216
|
-
|
|
240
|
+
const protocolFeeShare = t.protocolFeeShare ?? t.entryFee?.protocolFeeShare ?? null;
|
|
241
|
+
const phase = t.phase ?? tournamentPhase(t);
|
|
242
|
+
return { ...t, id, tournamentId: id, protocolFeeShare, phase };
|
|
217
243
|
}
|
|
218
244
|
function fetchOpts(ctx) {
|
|
219
245
|
return {
|
|
@@ -538,7 +564,7 @@ var WSManager = class {
|
|
|
538
564
|
// src/chains/constants.ts
|
|
539
565
|
var CHAINS = {
|
|
540
566
|
mainnet: {
|
|
541
|
-
rpcUrl: "https://
|
|
567
|
+
rpcUrl: "https://rpc.provable.games/rpc",
|
|
542
568
|
apiBaseUrl: "https://budokan-api-production.up.railway.app",
|
|
543
569
|
wsUrl: "wss://budokan-api-production.up.railway.app/ws",
|
|
544
570
|
budokanAddress: "0x0596ced030e74ebc37f33607f07ecd5a62eff22cdc4ae31fe2d724040c1bdc0b",
|
|
@@ -830,7 +856,7 @@ function phaseToRpcArg(phase) {
|
|
|
830
856
|
}
|
|
831
857
|
return new CairoCustomEnum(variants);
|
|
832
858
|
}
|
|
833
|
-
function parseTournament(raw, entryCount) {
|
|
859
|
+
function parseTournament(raw, entryCount, protocolFeeShare = null) {
|
|
834
860
|
const obj = raw;
|
|
835
861
|
const id = String(obj.id ?? "0");
|
|
836
862
|
const createdAt = Number(obj.created_at ?? 0);
|
|
@@ -928,6 +954,8 @@ function parseTournament(raw, entryCount) {
|
|
|
928
954
|
leaderboardGameMustBeOver: gameMustBeOver,
|
|
929
955
|
entryFeeToken,
|
|
930
956
|
entryFeeAmount,
|
|
957
|
+
// Protocol-fee bps snapshot, surfaced by the viewer's TournamentFullState.
|
|
958
|
+
protocolFeeShare,
|
|
931
959
|
hasEntryRequirement,
|
|
932
960
|
schedule: {
|
|
933
961
|
registrationStartDelay,
|
|
@@ -949,6 +977,14 @@ function parseTournament(raw, entryCount) {
|
|
|
949
977
|
entryFeeExtension,
|
|
950
978
|
entryRequirement,
|
|
951
979
|
leaderboardConfig: { ascending, gameMustBeOver },
|
|
980
|
+
phase: tournamentPhase({
|
|
981
|
+
createdAtOnchain: createdAtStr,
|
|
982
|
+
registrationStartDelay,
|
|
983
|
+
registrationEndDelay,
|
|
984
|
+
gameStartDelay,
|
|
985
|
+
gameEndDelay,
|
|
986
|
+
submissionDuration
|
|
987
|
+
}),
|
|
952
988
|
entryCount,
|
|
953
989
|
prizeCount: 0,
|
|
954
990
|
// Not available from viewer
|
|
@@ -1094,7 +1130,8 @@ function parseFilterResult(raw) {
|
|
|
1094
1130
|
function parseTournamentFullState(raw) {
|
|
1095
1131
|
const obj = raw;
|
|
1096
1132
|
const entryCount = Number(obj.entry_count ?? 0);
|
|
1097
|
-
|
|
1133
|
+
const protocolFeeShare = obj.protocol_fee_bps != null ? Number(obj.protocol_fee_bps) : null;
|
|
1134
|
+
return parseTournament(obj.tournament, entryCount, protocolFeeShare);
|
|
1098
1135
|
}
|
|
1099
1136
|
async function viewerTournaments(contract, offset, limit) {
|
|
1100
1137
|
return wrapRpcCall(async () => {
|
|
@@ -1270,6 +1307,9 @@ function translateCairoRewardType(rewardType) {
|
|
|
1270
1307
|
if (subVariant === "GameCreator" || subBag?.GameCreator !== void 0) {
|
|
1271
1308
|
return rewardClaim({ claimKind: "entry_fee_game_creator" });
|
|
1272
1309
|
}
|
|
1310
|
+
if (subVariant === "ProtocolFee" || subBag?.ProtocolFee !== void 0) {
|
|
1311
|
+
return rewardClaim({ claimKind: "entry_fee_protocol_fee" });
|
|
1312
|
+
}
|
|
1273
1313
|
if (subVariant === "Refund" || subBag?.Refund !== void 0) {
|
|
1274
1314
|
return rewardClaim({
|
|
1275
1315
|
claimKind: "entry_fee_refund",
|
|
@@ -1742,6 +1782,10 @@ var budokanViewer_default = [
|
|
|
1742
1782
|
{
|
|
1743
1783
|
name: "phase",
|
|
1744
1784
|
type: "budokan_interfaces::budokan::Phase"
|
|
1785
|
+
},
|
|
1786
|
+
{
|
|
1787
|
+
name: "protocol_fee_bps",
|
|
1788
|
+
type: "core::integer::u16"
|
|
1745
1789
|
}
|
|
1746
1790
|
]
|
|
1747
1791
|
},
|
|
@@ -2012,6 +2056,10 @@ var budokanViewer_default = [
|
|
|
2012
2056
|
{
|
|
2013
2057
|
name: "Refund",
|
|
2014
2058
|
type: "core::felt252"
|
|
2059
|
+
},
|
|
2060
|
+
{
|
|
2061
|
+
name: "ProtocolFee",
|
|
2062
|
+
type: "()"
|
|
2015
2063
|
}
|
|
2016
2064
|
]
|
|
2017
2065
|
},
|
|
@@ -3390,6 +3438,10 @@ var budokan_default = [
|
|
|
3390
3438
|
{
|
|
3391
3439
|
name: "Refund",
|
|
3392
3440
|
type: "core::felt252"
|
|
3441
|
+
},
|
|
3442
|
+
{
|
|
3443
|
+
name: "ProtocolFee",
|
|
3444
|
+
type: "()"
|
|
3393
3445
|
}
|
|
3394
3446
|
]
|
|
3395
3447
|
},
|
|
@@ -4678,6 +4730,11 @@ var budokan_default = [
|
|
|
4678
4730
|
name: "entry_requirement",
|
|
4679
4731
|
type: "core::option::Option::<game_components_interfaces::entry_requirement::EntryRequirement>",
|
|
4680
4732
|
kind: "data"
|
|
4733
|
+
},
|
|
4734
|
+
{
|
|
4735
|
+
name: "protocol_fee_bps",
|
|
4736
|
+
type: "core::integer::u16",
|
|
4737
|
+
kind: "data"
|
|
4681
4738
|
}
|
|
4682
4739
|
]
|
|
4683
4740
|
},
|
|
@@ -4900,6 +4957,108 @@ var budokan_default = [
|
|
|
4900
4957
|
name: "QualificationEntriesUpdated",
|
|
4901
4958
|
type: "budokan::events::QualificationEntriesUpdated",
|
|
4902
4959
|
kind: "nested"
|
|
4960
|
+
},
|
|
4961
|
+
{
|
|
4962
|
+
name: "ProtocolFeeBpsUpdated",
|
|
4963
|
+
type: "budokan::events::ProtocolFeeBpsUpdated",
|
|
4964
|
+
kind: "nested"
|
|
4965
|
+
},
|
|
4966
|
+
{
|
|
4967
|
+
name: "ProtocolFeeRecipientUpdated",
|
|
4968
|
+
type: "budokan::events::ProtocolFeeRecipientUpdated",
|
|
4969
|
+
kind: "nested"
|
|
4970
|
+
}
|
|
4971
|
+
]
|
|
4972
|
+
},
|
|
4973
|
+
{
|
|
4974
|
+
type: "interface",
|
|
4975
|
+
name: "budokan::budokan::Budokan::IBudokanProtocolFeeAdmin",
|
|
4976
|
+
items: [
|
|
4977
|
+
{
|
|
4978
|
+
type: "function",
|
|
4979
|
+
name: "set_protocol_fee_bps",
|
|
4980
|
+
inputs: [
|
|
4981
|
+
{
|
|
4982
|
+
name: "bps",
|
|
4983
|
+
type: "core::integer::u16"
|
|
4984
|
+
}
|
|
4985
|
+
],
|
|
4986
|
+
outputs: [],
|
|
4987
|
+
state_mutability: "external"
|
|
4988
|
+
},
|
|
4989
|
+
{
|
|
4990
|
+
type: "function",
|
|
4991
|
+
name: "set_protocol_fee_recipient",
|
|
4992
|
+
inputs: [
|
|
4993
|
+
{
|
|
4994
|
+
name: "recipient",
|
|
4995
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
4996
|
+
}
|
|
4997
|
+
],
|
|
4998
|
+
outputs: [],
|
|
4999
|
+
state_mutability: "external"
|
|
5000
|
+
},
|
|
5001
|
+
{
|
|
5002
|
+
type: "function",
|
|
5003
|
+
name: "protocol_fee_bps",
|
|
5004
|
+
inputs: [],
|
|
5005
|
+
outputs: [
|
|
5006
|
+
{
|
|
5007
|
+
type: "core::integer::u16"
|
|
5008
|
+
}
|
|
5009
|
+
],
|
|
5010
|
+
state_mutability: "view"
|
|
5011
|
+
},
|
|
5012
|
+
{
|
|
5013
|
+
type: "function",
|
|
5014
|
+
name: "protocol_fee_recipient",
|
|
5015
|
+
inputs: [],
|
|
5016
|
+
outputs: [
|
|
5017
|
+
{
|
|
5018
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
5019
|
+
}
|
|
5020
|
+
],
|
|
5021
|
+
state_mutability: "view"
|
|
5022
|
+
},
|
|
5023
|
+
{
|
|
5024
|
+
type: "function",
|
|
5025
|
+
name: "tournament_protocol_fee_bps",
|
|
5026
|
+
inputs: [
|
|
5027
|
+
{
|
|
5028
|
+
name: "tournament_id",
|
|
5029
|
+
type: "core::integer::u64"
|
|
5030
|
+
}
|
|
5031
|
+
],
|
|
5032
|
+
outputs: [
|
|
5033
|
+
{
|
|
5034
|
+
type: "core::integer::u16"
|
|
5035
|
+
}
|
|
5036
|
+
],
|
|
5037
|
+
state_mutability: "view"
|
|
5038
|
+
}
|
|
5039
|
+
]
|
|
5040
|
+
},
|
|
5041
|
+
{
|
|
5042
|
+
type: "event",
|
|
5043
|
+
name: "budokan::events::ProtocolFeeBpsUpdated",
|
|
5044
|
+
kind: "struct",
|
|
5045
|
+
members: [
|
|
5046
|
+
{
|
|
5047
|
+
name: "bps",
|
|
5048
|
+
type: "core::integer::u16",
|
|
5049
|
+
kind: "data"
|
|
5050
|
+
}
|
|
5051
|
+
]
|
|
5052
|
+
},
|
|
5053
|
+
{
|
|
5054
|
+
type: "event",
|
|
5055
|
+
name: "budokan::events::ProtocolFeeRecipientUpdated",
|
|
5056
|
+
kind: "struct",
|
|
5057
|
+
members: [
|
|
5058
|
+
{
|
|
5059
|
+
name: "recipient",
|
|
5060
|
+
type: "core::starknet::contract_address::ContractAddress",
|
|
5061
|
+
kind: "key"
|
|
4903
5062
|
}
|
|
4904
5063
|
]
|
|
4905
5064
|
}
|
|
@@ -5367,6 +5526,185 @@ function createBudokanClient(config) {
|
|
|
5367
5526
|
return new BudokanClient(config);
|
|
5368
5527
|
}
|
|
5369
5528
|
|
|
5529
|
+
// src/utils/prizes.ts
|
|
5530
|
+
function isNonEmptyString(value) {
|
|
5531
|
+
return typeof value === "string" && value.length > 0;
|
|
5532
|
+
}
|
|
5533
|
+
function isNonNegativeIntegerString(value) {
|
|
5534
|
+
if (!isNonEmptyString(value) || value.trim() !== value) return false;
|
|
5535
|
+
if (!/^\d+$/.test(value)) return false;
|
|
5536
|
+
try {
|
|
5537
|
+
return BigInt(value) >= 0n;
|
|
5538
|
+
} catch {
|
|
5539
|
+
return false;
|
|
5540
|
+
}
|
|
5541
|
+
}
|
|
5542
|
+
function isNonNegativeIntegerNumber(value) {
|
|
5543
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0;
|
|
5544
|
+
}
|
|
5545
|
+
function isPositiveIntegerNumber(value) {
|
|
5546
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
5547
|
+
}
|
|
5548
|
+
function isDistributionType(value) {
|
|
5549
|
+
return value === "linear" || value === "exponential" || value === "uniform" || value === "custom";
|
|
5550
|
+
}
|
|
5551
|
+
function hasNoDistributionFields(prize) {
|
|
5552
|
+
return prize.distributionType === null && prize.distributionWeight === null && prize.distributionShares === null && prize.distributionCount === null;
|
|
5553
|
+
}
|
|
5554
|
+
function hasValidDistributionFields(prize) {
|
|
5555
|
+
if (prize.distributionType === null) return hasNoDistributionFields(prize);
|
|
5556
|
+
if (!isDistributionType(prize.distributionType)) return false;
|
|
5557
|
+
if (!isPositiveIntegerNumber(prize.distributionCount)) return false;
|
|
5558
|
+
if (prize.distributionType === "custom") {
|
|
5559
|
+
return prize.distributionWeight === null && Array.isArray(prize.distributionShares) && prize.distributionShares.length === prize.distributionCount && prize.distributionShares.every(isNonNegativeIntegerNumber) && prize.distributionShares.reduce((sum, share) => sum + share, 0) === 1e4;
|
|
5560
|
+
}
|
|
5561
|
+
if (prize.distributionType === "uniform") {
|
|
5562
|
+
return prize.distributionWeight === null && prize.distributionShares === null;
|
|
5563
|
+
}
|
|
5564
|
+
return isNonNegativeIntegerNumber(prize.distributionWeight) && prize.distributionShares === null;
|
|
5565
|
+
}
|
|
5566
|
+
function hasBasePrizeFields(prize) {
|
|
5567
|
+
return isNonNegativeIntegerString(prize.prizeId) && isNonNegativeIntegerString(prize.tournamentId) && Number.isInteger(prize.payoutPosition) && prize.payoutPosition >= 0 && isNonEmptyString(prize.sponsorAddress);
|
|
5568
|
+
}
|
|
5569
|
+
function hasExtensionConfig(value) {
|
|
5570
|
+
return value === null || Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
5571
|
+
}
|
|
5572
|
+
function describePrize(prize) {
|
|
5573
|
+
const prizeId = isNonEmptyString(prize.prizeId) ? prize.prizeId : "<invalid>";
|
|
5574
|
+
return `prizeId=${prizeId}, tokenType=${prize.tokenType}`;
|
|
5575
|
+
}
|
|
5576
|
+
function malformedTokenPrizeError(action, prize) {
|
|
5577
|
+
return new TypeError(
|
|
5578
|
+
`Cannot ${action} malformed Budokan token prize (${describePrize(prize)})`
|
|
5579
|
+
);
|
|
5580
|
+
}
|
|
5581
|
+
function malformedExtensionPrizeError(action, prize) {
|
|
5582
|
+
return new TypeError(
|
|
5583
|
+
`Cannot ${action} malformed Budokan extension prize (${describePrize(prize)})`
|
|
5584
|
+
);
|
|
5585
|
+
}
|
|
5586
|
+
function assertMetagameTokenPosition(prize) {
|
|
5587
|
+
if (Number.isInteger(prize.payoutPosition) && prize.payoutPosition > 0) {
|
|
5588
|
+
return;
|
|
5589
|
+
}
|
|
5590
|
+
if (prize.payoutPosition !== 0) {
|
|
5591
|
+
throw new TypeError(
|
|
5592
|
+
`Cannot adapt Budokan token prize with invalid payout position (${describePrize(prize)})`
|
|
5593
|
+
);
|
|
5594
|
+
}
|
|
5595
|
+
throw new TypeError(
|
|
5596
|
+
`Cannot adapt Budokan token prize with unhydrated payout position (${describePrize(prize)})`
|
|
5597
|
+
);
|
|
5598
|
+
}
|
|
5599
|
+
function assertMetagameExtensionPosition(prize) {
|
|
5600
|
+
if (Number.isInteger(prize.payoutPosition) && prize.payoutPosition > 0) {
|
|
5601
|
+
return;
|
|
5602
|
+
}
|
|
5603
|
+
if (prize.payoutPosition !== 0) {
|
|
5604
|
+
throw new TypeError(
|
|
5605
|
+
`Cannot adapt Budokan extension prize with invalid payout position (${describePrize(prize)})`
|
|
5606
|
+
);
|
|
5607
|
+
}
|
|
5608
|
+
throw new TypeError(
|
|
5609
|
+
`Cannot adapt Budokan extension prize with unhydrated payout position (${describePrize(prize)})`
|
|
5610
|
+
);
|
|
5611
|
+
}
|
|
5612
|
+
function hasHydratedPayoutPosition(prize) {
|
|
5613
|
+
return prize.payoutPosition > 0;
|
|
5614
|
+
}
|
|
5615
|
+
function isRawTokenPrize(prize) {
|
|
5616
|
+
if (!hasBasePrizeFields(prize) || !isNonEmptyString(prize.tokenAddress)) {
|
|
5617
|
+
return false;
|
|
5618
|
+
}
|
|
5619
|
+
return prize.tokenType === "erc20" ? isNonNegativeIntegerString(prize.amount) && prize.tokenId === null && prize.extensionAddress === null && prize.extensionConfig === null && hasValidDistributionFields(prize) : prize.tokenType === "erc721" && prize.amount === null && isNonNegativeIntegerString(prize.tokenId) && prize.extensionAddress === null && prize.extensionConfig === null && hasNoDistributionFields(prize);
|
|
5620
|
+
}
|
|
5621
|
+
function isRawExtensionPrize(prize) {
|
|
5622
|
+
return hasBasePrizeFields(prize) && prize.tokenType === "extension" && prize.tokenAddress === null && prize.amount === null && prize.tokenId === null && hasNoDistributionFields(prize) && isNonEmptyString(prize.extensionAddress) && hasExtensionConfig(prize.extensionConfig);
|
|
5623
|
+
}
|
|
5624
|
+
function isTokenPrize(prize) {
|
|
5625
|
+
return isRawTokenPrize(prize) && hasHydratedPayoutPosition(prize);
|
|
5626
|
+
}
|
|
5627
|
+
function isExtensionPrize(prize) {
|
|
5628
|
+
return isRawExtensionPrize(prize) && hasHydratedPayoutPosition(prize);
|
|
5629
|
+
}
|
|
5630
|
+
function isMetagameAdaptablePrize(prize) {
|
|
5631
|
+
return isTokenPrize(prize) || isExtensionPrize(prize);
|
|
5632
|
+
}
|
|
5633
|
+
function getRawTokenPrizes(prizes) {
|
|
5634
|
+
return prizes.flatMap((prize) => {
|
|
5635
|
+
if (isRawTokenPrize(prize)) return [prize];
|
|
5636
|
+
if (prize.tokenType === "extension") return [];
|
|
5637
|
+
throw malformedTokenPrizeError("read", prize);
|
|
5638
|
+
});
|
|
5639
|
+
}
|
|
5640
|
+
function getTokenPrizes(prizes) {
|
|
5641
|
+
return prizes.flatMap((prize) => {
|
|
5642
|
+
if (isTokenPrize(prize)) return [prize];
|
|
5643
|
+
if (isRawTokenPrize(prize) || prize.tokenType === "extension") return [];
|
|
5644
|
+
throw malformedTokenPrizeError("read", prize);
|
|
5645
|
+
});
|
|
5646
|
+
}
|
|
5647
|
+
function toMetagameTokenPrize(prize) {
|
|
5648
|
+
assertMetagameTokenPosition(prize);
|
|
5649
|
+
if (!isRawTokenPrize(prize)) {
|
|
5650
|
+
throw malformedTokenPrizeError("adapt", prize);
|
|
5651
|
+
}
|
|
5652
|
+
const adapted = {
|
|
5653
|
+
id: prize.prizeId,
|
|
5654
|
+
position: prize.payoutPosition,
|
|
5655
|
+
tokenAddress: prize.tokenAddress,
|
|
5656
|
+
tokenType: prize.tokenType,
|
|
5657
|
+
// Metagame token prizes use `amount` as the token id for ERC721 entries.
|
|
5658
|
+
amount: prize.tokenType === "erc20" ? prize.amount : prize.tokenId,
|
|
5659
|
+
sponsorAddress: prize.sponsorAddress
|
|
5660
|
+
};
|
|
5661
|
+
return adapted;
|
|
5662
|
+
}
|
|
5663
|
+
function toMetagameExtensionPrize(prize) {
|
|
5664
|
+
assertMetagameExtensionPosition(prize);
|
|
5665
|
+
if (!isRawExtensionPrize(prize)) {
|
|
5666
|
+
throw malformedExtensionPrizeError("adapt", prize);
|
|
5667
|
+
}
|
|
5668
|
+
const adapted = {
|
|
5669
|
+
id: prize.prizeId,
|
|
5670
|
+
position: prize.payoutPosition,
|
|
5671
|
+
tokenAddress: null,
|
|
5672
|
+
tokenType: "extension",
|
|
5673
|
+
amount: null,
|
|
5674
|
+
sponsorAddress: prize.sponsorAddress,
|
|
5675
|
+
extensionAddress: prize.extensionAddress,
|
|
5676
|
+
extensionConfig: prize.extensionConfig
|
|
5677
|
+
};
|
|
5678
|
+
return adapted;
|
|
5679
|
+
}
|
|
5680
|
+
function toMetagamePrize(prize) {
|
|
5681
|
+
if (isRawTokenPrize(prize)) return toMetagameTokenPrize(prize);
|
|
5682
|
+
if (isRawExtensionPrize(prize)) return toMetagameExtensionPrize(prize);
|
|
5683
|
+
throw new TypeError(
|
|
5684
|
+
`Cannot adapt malformed Budokan prize (${describePrize(prize)})`
|
|
5685
|
+
);
|
|
5686
|
+
}
|
|
5687
|
+
function tryToMetagamePrize(prize) {
|
|
5688
|
+
if (!isMetagameAdaptablePrize(prize)) return null;
|
|
5689
|
+
return prize.tokenType === "extension" ? toMetagameExtensionPrize(prize) : toMetagameTokenPrize(prize);
|
|
5690
|
+
}
|
|
5691
|
+
function toMetagamePrizes(prizes) {
|
|
5692
|
+
return prizes.map(toMetagamePrize);
|
|
5693
|
+
}
|
|
5694
|
+
function tryToMetagamePrizes(prizes) {
|
|
5695
|
+
return prizes.flatMap((prize) => {
|
|
5696
|
+
const adapted = tryToMetagamePrize(prize);
|
|
5697
|
+
return adapted ? [adapted] : [];
|
|
5698
|
+
});
|
|
5699
|
+
}
|
|
5700
|
+
function toMetagameTokenPrizes(prizes) {
|
|
5701
|
+
return prizes.flatMap((prize) => {
|
|
5702
|
+
if (isRawTokenPrize(prize)) return [toMetagameTokenPrize(prize)];
|
|
5703
|
+
if (prize.tokenType === "extension") return [];
|
|
5704
|
+
throw malformedTokenPrizeError("adapt", prize);
|
|
5705
|
+
});
|
|
5706
|
+
}
|
|
5707
|
+
|
|
5370
5708
|
// src/games/whitelist.ts
|
|
5371
5709
|
var STRK = "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d";
|
|
5372
5710
|
var MAINNET_GAMES_RAW = [
|
|
@@ -5753,6 +6091,9 @@ function pushRewardTypeFelts(out, reward) {
|
|
|
5753
6091
|
case "entry_fee_refund":
|
|
5754
6092
|
out.push("0x1", "0x0", "0x3", num.toHex(reward.tokenId));
|
|
5755
6093
|
return;
|
|
6094
|
+
case "entry_fee_protocol_fee":
|
|
6095
|
+
out.push("0x1", "0x0", "0x4");
|
|
6096
|
+
return;
|
|
5756
6097
|
case "entry_fee_extension": {
|
|
5757
6098
|
out.push("0x1", "0x1");
|
|
5758
6099
|
if (reward.tokenId !== void 0) {
|
|
@@ -5794,6 +6135,248 @@ function felt252FromShortString(s) {
|
|
|
5794
6135
|
}
|
|
5795
6136
|
return "0x" + value.toString(16);
|
|
5796
6137
|
}
|
|
6138
|
+
|
|
6139
|
+
// src/distribution/index.ts
|
|
6140
|
+
var BASIS_POINTS = 10000n;
|
|
6141
|
+
function calculateDistribution(positions, weight, distributionType) {
|
|
6142
|
+
if (positions <= 0) return [];
|
|
6143
|
+
let raw;
|
|
6144
|
+
if (distributionType === "uniform") {
|
|
6145
|
+
raw = Array(positions).fill(1);
|
|
6146
|
+
} else if (distributionType === "linear") {
|
|
6147
|
+
raw = [];
|
|
6148
|
+
for (let i = 0; i < positions; i++) {
|
|
6149
|
+
const positionValue = positions - i;
|
|
6150
|
+
raw.push(1 + (positionValue - 1) * (weight / 10));
|
|
6151
|
+
}
|
|
6152
|
+
} else {
|
|
6153
|
+
raw = [];
|
|
6154
|
+
for (let i = 0; i < positions; i++) {
|
|
6155
|
+
raw.push(Math.pow(1 - i / positions, weight));
|
|
6156
|
+
}
|
|
6157
|
+
}
|
|
6158
|
+
const total = raw.reduce((a, b) => a + b, 0);
|
|
6159
|
+
if (total === 0) return Array(positions).fill(0);
|
|
6160
|
+
const bpShares = raw.map((d) => Math.floor(d / total * 1e4));
|
|
6161
|
+
const remaining = 1e4 - bpShares.reduce((a, b) => a + b, 0);
|
|
6162
|
+
if (remaining !== 0) bpShares[0] = bpShares[0] + remaining;
|
|
6163
|
+
return bpShares.map((bp) => bp / 100);
|
|
6164
|
+
}
|
|
6165
|
+
var KNOWN_KEYS = {
|
|
6166
|
+
linear: "linear",
|
|
6167
|
+
exponential: "exponential",
|
|
6168
|
+
uniform: "uniform",
|
|
6169
|
+
custom: "custom"
|
|
6170
|
+
};
|
|
6171
|
+
function parseDistribution(dist) {
|
|
6172
|
+
if (!dist || typeof dist !== "object") {
|
|
6173
|
+
return { type: "unknown", weight: 0 };
|
|
6174
|
+
}
|
|
6175
|
+
const explicit = dist;
|
|
6176
|
+
if (typeof explicit.type === "string") {
|
|
6177
|
+
const kind = KNOWN_KEYS[explicit.type.toLowerCase()] ?? "unknown";
|
|
6178
|
+
return { type: kind, weight: Number(explicit.weight ?? 0) };
|
|
6179
|
+
}
|
|
6180
|
+
const bag = dist.variant ?? dist;
|
|
6181
|
+
for (const [rawKey, value] of Object.entries(bag)) {
|
|
6182
|
+
if (value === void 0 || value === null) continue;
|
|
6183
|
+
const kind = KNOWN_KEYS[rawKey.toLowerCase()];
|
|
6184
|
+
if (!kind) continue;
|
|
6185
|
+
if (kind === "uniform") return { type: "uniform", weight: 0 };
|
|
6186
|
+
if (kind === "custom") {
|
|
6187
|
+
const arr = Array.isArray(value) ? value.map((v) => Number(v)) : [];
|
|
6188
|
+
return { type: "custom", weight: 0, customWeights: arr };
|
|
6189
|
+
}
|
|
6190
|
+
if (typeof value === "number" || typeof value === "string" || typeof value === "bigint") {
|
|
6191
|
+
return { type: kind, weight: Number(value) };
|
|
6192
|
+
}
|
|
6193
|
+
if (typeof value === "object" && value !== null && "Some" in value) {
|
|
6194
|
+
return { type: kind, weight: Number(value.Some) };
|
|
6195
|
+
}
|
|
6196
|
+
return { type: kind, weight: 0 };
|
|
6197
|
+
}
|
|
6198
|
+
return { type: "unknown", weight: 0 };
|
|
6199
|
+
}
|
|
6200
|
+
function prizeDistribution(prize) {
|
|
6201
|
+
const type = KNOWN_KEYS[String(prize.distributionType ?? "uniform").toLowerCase()] ?? "uniform";
|
|
6202
|
+
if (type === "custom") {
|
|
6203
|
+
return { type, weight: 0, customWeights: prize.distributionShares ?? [] };
|
|
6204
|
+
}
|
|
6205
|
+
return { type, weight: prize.distributionWeight ?? 10 };
|
|
6206
|
+
}
|
|
6207
|
+
function distributionPercentages(dist, count) {
|
|
6208
|
+
if (count <= 0) return [];
|
|
6209
|
+
if (dist.type === "custom") {
|
|
6210
|
+
const cw = dist.customWeights ?? [];
|
|
6211
|
+
if (cw.length === count) return cw.map((bp) => bp / 100);
|
|
6212
|
+
return calculateDistribution(count, 1, "uniform");
|
|
6213
|
+
}
|
|
6214
|
+
const distType = dist.type === "linear" || dist.type === "exponential" || dist.type === "uniform" ? dist.type : "uniform";
|
|
6215
|
+
return calculateDistribution(count, dist.weight / 10, distType);
|
|
6216
|
+
}
|
|
6217
|
+
function bps(total, share) {
|
|
6218
|
+
const b = Number(share ?? 0);
|
|
6219
|
+
if (b <= 0) return 0n;
|
|
6220
|
+
return total * BigInt(b) / BASIS_POINTS;
|
|
6221
|
+
}
|
|
6222
|
+
function entryFeeSplit(input) {
|
|
6223
|
+
const total = BigInt(input.amount ?? 0) * BigInt(input.entryCount ?? 0);
|
|
6224
|
+
const creator = Number(input.tournamentCreatorShare ?? 0);
|
|
6225
|
+
const game = Number(input.gameCreatorShare ?? 0);
|
|
6226
|
+
const refund = Number(input.refundShare ?? 0);
|
|
6227
|
+
const protocol = Number(input.protocolFeeShare ?? 0);
|
|
6228
|
+
const availableShareBps = Math.max(0, 1e4 - creator - game - refund - protocol);
|
|
6229
|
+
return {
|
|
6230
|
+
total,
|
|
6231
|
+
positionPool: total * BigInt(availableShareBps) / BASIS_POINTS,
|
|
6232
|
+
tournamentCreator: bps(total, creator),
|
|
6233
|
+
gameCreator: bps(total, game),
|
|
6234
|
+
refund: bps(total, refund),
|
|
6235
|
+
protocolFee: bps(total, protocol),
|
|
6236
|
+
availableShareBps
|
|
6237
|
+
};
|
|
6238
|
+
}
|
|
6239
|
+
function entryFeePositionPayout(input, position) {
|
|
6240
|
+
const distCount = Number(input.distributionCount ?? 0);
|
|
6241
|
+
if (distCount <= 0 || position < 1 || position > distCount) return 0n;
|
|
6242
|
+
const split = entryFeeSplit(input);
|
|
6243
|
+
if (split.positionPool <= 0n) return 0n;
|
|
6244
|
+
const pcts = distributionPercentages(parseDistribution(input.distribution), distCount);
|
|
6245
|
+
const pct = pcts[position - 1] ?? 0;
|
|
6246
|
+
if (pct <= 0) return 0n;
|
|
6247
|
+
return split.positionPool * BigInt(Math.floor(pct * 1e4)) / 1000000n;
|
|
6248
|
+
}
|
|
6249
|
+
function sponsorPrizePayout(prize, position) {
|
|
6250
|
+
if (prize.tokenType !== "erc20") return 0n;
|
|
6251
|
+
const distCount = Number(prize.distributionCount ?? 0);
|
|
6252
|
+
if (distCount <= 0 || position < 1 || position > distCount) return 0n;
|
|
6253
|
+
const pcts = distributionPercentages(prizeDistribution(prize), distCount);
|
|
6254
|
+
const pct = pcts[position - 1] ?? 0;
|
|
6255
|
+
if (pct <= 0) return 0n;
|
|
6256
|
+
return BigInt(prize.amount ?? "0") * BigInt(Math.floor(pct * 1e4)) / 1000000n;
|
|
6257
|
+
}
|
|
6258
|
+
|
|
6259
|
+
// src/rewards/index.ts
|
|
6260
|
+
function getClaimableRewards(input) {
|
|
6261
|
+
const tournamentsById = /* @__PURE__ */ new Map();
|
|
6262
|
+
for (const t of input.tournaments) tournamentsById.set(t.id, t);
|
|
6263
|
+
const prizesByTournament = /* @__PURE__ */ new Map();
|
|
6264
|
+
for (const p of input.prizes) {
|
|
6265
|
+
let list = prizesByTournament.get(p.tournamentId);
|
|
6266
|
+
if (!list) prizesByTournament.set(p.tournamentId, list = []);
|
|
6267
|
+
list.push(p);
|
|
6268
|
+
}
|
|
6269
|
+
const claimedKeys = /* @__PURE__ */ new Set();
|
|
6270
|
+
for (const c of input.existingClaims) {
|
|
6271
|
+
if (!c.claimed) continue;
|
|
6272
|
+
const key = rewardClaimKey(c);
|
|
6273
|
+
if (key) claimedKeys.add(`${c.tournamentId}:${key}`);
|
|
6274
|
+
}
|
|
6275
|
+
const out = [];
|
|
6276
|
+
for (const placement of input.placements) {
|
|
6277
|
+
const tournament = tournamentsById.get(placement.tournamentId);
|
|
6278
|
+
if (!tournament) continue;
|
|
6279
|
+
const tournamentName = tournament.name || `#${tournament.id}`;
|
|
6280
|
+
const pos = placement.position;
|
|
6281
|
+
const ef = tournament.entryFee;
|
|
6282
|
+
const efDistCount = Number(ef?.distributionCount ?? 0);
|
|
6283
|
+
if (ef && ef.tokenAddress && efDistCount >= pos) {
|
|
6284
|
+
const claimKey = `${placement.tournamentId}:EntryFee.Position.${pos}`;
|
|
6285
|
+
if (!claimedKeys.has(claimKey)) {
|
|
6286
|
+
const amount = entryFeePositionPayout(
|
|
6287
|
+
{
|
|
6288
|
+
amount: ef.amount ?? "0",
|
|
6289
|
+
entryCount: tournament.entryCount ?? 0,
|
|
6290
|
+
tournamentCreatorShare: ef.tournamentCreatorShare,
|
|
6291
|
+
gameCreatorShare: ef.gameCreatorShare,
|
|
6292
|
+
refundShare: ef.refundShare,
|
|
6293
|
+
protocolFeeShare: tournament.protocolFeeShare,
|
|
6294
|
+
distribution: ef.distribution,
|
|
6295
|
+
distributionCount: efDistCount
|
|
6296
|
+
},
|
|
6297
|
+
pos
|
|
6298
|
+
);
|
|
6299
|
+
if (amount > 0n) {
|
|
6300
|
+
out.push({
|
|
6301
|
+
tournamentId: placement.tournamentId,
|
|
6302
|
+
tournamentName,
|
|
6303
|
+
source: "entry_fee_position",
|
|
6304
|
+
position: pos,
|
|
6305
|
+
tokenAddress: ef.tokenAddress,
|
|
6306
|
+
tokenType: "erc20",
|
|
6307
|
+
amount,
|
|
6308
|
+
reward: { kind: "entry_fee_position", position: pos }
|
|
6309
|
+
});
|
|
6310
|
+
}
|
|
6311
|
+
}
|
|
6312
|
+
}
|
|
6313
|
+
for (const prize of prizesByTournament.get(placement.tournamentId) ?? []) {
|
|
6314
|
+
if (!isRawTokenPrize(prize)) continue;
|
|
6315
|
+
const dc = prize.distributionCount ?? 0;
|
|
6316
|
+
const pp = prize.payoutPosition ?? 0;
|
|
6317
|
+
const isSingle = pp === pos && dc === 0;
|
|
6318
|
+
const isDistributed = dc >= pos && pp === 0;
|
|
6319
|
+
if (!isSingle && !isDistributed) continue;
|
|
6320
|
+
const tokenType = prize.tokenType === "erc721" ? "erc721" : "erc20";
|
|
6321
|
+
if (isSingle) {
|
|
6322
|
+
const claimKey2 = `${placement.tournamentId}:Prize.Single.${prize.prizeId}`;
|
|
6323
|
+
if (claimedKeys.has(claimKey2)) continue;
|
|
6324
|
+
out.push({
|
|
6325
|
+
tournamentId: placement.tournamentId,
|
|
6326
|
+
tournamentName,
|
|
6327
|
+
source: "sponsor_single",
|
|
6328
|
+
position: pos,
|
|
6329
|
+
tokenAddress: prize.tokenAddress,
|
|
6330
|
+
tokenType,
|
|
6331
|
+
amount: tokenType === "erc20" ? BigInt(prize.amount ?? "0") : void 0,
|
|
6332
|
+
tokenId: prize.tokenId,
|
|
6333
|
+
reward: { kind: "prize_single", prizeId: prize.prizeId }
|
|
6334
|
+
});
|
|
6335
|
+
continue;
|
|
6336
|
+
}
|
|
6337
|
+
const payoutIndex = pos - 1;
|
|
6338
|
+
const claimKey = `${placement.tournamentId}:Prize.Distributed.${prize.prizeId}.${payoutIndex}`;
|
|
6339
|
+
if (claimedKeys.has(claimKey)) continue;
|
|
6340
|
+
const amount = sponsorPrizePayout(prize, pos);
|
|
6341
|
+
if (amount <= 0n) continue;
|
|
6342
|
+
out.push({
|
|
6343
|
+
tournamentId: placement.tournamentId,
|
|
6344
|
+
tournamentName,
|
|
6345
|
+
source: "sponsor_distributed",
|
|
6346
|
+
position: pos,
|
|
6347
|
+
tokenAddress: prize.tokenAddress,
|
|
6348
|
+
tokenType: "erc20",
|
|
6349
|
+
amount,
|
|
6350
|
+
reward: {
|
|
6351
|
+
kind: "prize_distributed",
|
|
6352
|
+
prizeId: prize.prizeId,
|
|
6353
|
+
payoutPosition: payoutIndex
|
|
6354
|
+
}
|
|
6355
|
+
});
|
|
6356
|
+
}
|
|
6357
|
+
}
|
|
6358
|
+
return out;
|
|
6359
|
+
}
|
|
6360
|
+
function buildClaimCalls(rewards, budokanAddress) {
|
|
6361
|
+
return rewards.map(
|
|
6362
|
+
(r) => buildClaimRewardCall(budokanAddress, {
|
|
6363
|
+
tournamentId: r.tournamentId,
|
|
6364
|
+
reward: r.reward
|
|
6365
|
+
})
|
|
6366
|
+
);
|
|
6367
|
+
}
|
|
6368
|
+
function rewardClaimKey(c) {
|
|
6369
|
+
switch (c.claimKind) {
|
|
6370
|
+
case "prize_single":
|
|
6371
|
+
return c.prizeId ? `Prize.Single.${c.prizeId}` : null;
|
|
6372
|
+
case "prize_distributed":
|
|
6373
|
+
return c.prizeId != null && c.payoutIndex != null ? `Prize.Distributed.${c.prizeId}.${c.payoutIndex}` : null;
|
|
6374
|
+
case "entry_fee_position":
|
|
6375
|
+
return c.position != null ? `EntryFee.Position.${c.position}` : null;
|
|
6376
|
+
default:
|
|
6377
|
+
return null;
|
|
6378
|
+
}
|
|
6379
|
+
}
|
|
5797
6380
|
function sdkChainId(chain) {
|
|
5798
6381
|
return chain === "mainnet" ? "SN_MAIN" : "SN_SEPOLIA";
|
|
5799
6382
|
}
|
|
@@ -5862,6 +6445,6 @@ function buildTournamentValidatorConfig(cfg) {
|
|
|
5862
6445
|
return [qualifierType, qualifyingMode, topPositions, ...cfg.tournamentIds];
|
|
5863
6446
|
}
|
|
5864
6447
|
|
|
5865
|
-
export { BudokanApiError, BudokanClient, BudokanConnectionError, BudokanError, BudokanTimeoutError, CHAINS, ConnectionStatus, DataSourceError, RpcError, TournamentNotFoundError, WSManager, buildAddPrizeCall, buildClaimRewardCall, buildCreateTournamentCall, buildEnterTournamentCall, buildErc20ApproveCall, buildErc20BalanceConfig, buildMerkleConfig, buildOpusTrovesConfig, buildSubmitScoreCall, buildTournamentValidatorConfig, camelToSnake, createBudokanClient, explorerAddressUrl, explorerBaseUrl, explorerTxUrl, extensionAddressFor, findWhitelistedGame, getActivityStats, getChainConfig, getGameDefaults, getGameStats, getGameTournaments, getPrizeStats, getTournament, getTournamentPrizeAggregation, getTournamentPrizes, getTournamentQualifications, getTournamentRegistrations, getTournamentRewardClaims, getTournamentRewardClaimsSummary, getTournaments, getWhitelistedGames, isGameWhitelisted, normalizeAddress, parseTournamentIdFromReceipt, snakeToCamel, tournamentPageUrl, u256ToLowHigh, withRetry };
|
|
6448
|
+
export { BudokanApiError, BudokanClient, BudokanConnectionError, BudokanError, BudokanTimeoutError, CHAINS, ConnectionStatus, DataSourceError, RpcError, TournamentNotFoundError, WSManager, buildAddPrizeCall, buildClaimCalls, buildClaimRewardCall, buildCreateTournamentCall, buildEnterTournamentCall, buildErc20ApproveCall, buildErc20BalanceConfig, buildMerkleConfig, buildOpusTrovesConfig, buildSubmitScoreCall, buildTournamentValidatorConfig, camelToSnake, createBudokanClient, distributionPercentages, entryFeePositionPayout, entryFeeSplit, explorerAddressUrl, explorerBaseUrl, explorerTxUrl, extensionAddressFor, findWhitelistedGame, getActivityStats, getChainConfig, getClaimableRewards, getGameDefaults, getGameStats, getGameTournaments, getPrizeStats, getRawTokenPrizes, getTokenPrizes, getTournament, getTournamentPrizeAggregation, getTournamentPrizes, getTournamentQualifications, getTournamentRegistrations, getTournamentRewardClaims, getTournamentRewardClaimsSummary, getTournaments, getWhitelistedGames, isExtensionPrize, isGameWhitelisted, isMetagameAdaptablePrize, isRawExtensionPrize, isRawTokenPrize, isTokenPrize, normalizeAddress, parseDistribution, parseTournamentIdFromReceipt, prizeDistribution, snakeToCamel, sponsorPrizePayout, toMetagameExtensionPrize, toMetagamePrize, toMetagamePrizes, toMetagameTokenPrize, toMetagameTokenPrizes, tournamentPageUrl, tournamentPhase, tryToMetagamePrize, tryToMetagamePrizes, u256ToLowHigh, withRetry };
|
|
5866
6449
|
//# sourceMappingURL=index.js.map
|
|
5867
6450
|
//# sourceMappingURL=index.js.map
|