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