@zga/client 0.0.0-stage → 0.1.1
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/LICENSE +21 -0
- package/dist/addresses.d.ts +29 -0
- package/dist/addresses.js +43 -0
- package/dist/billing.d.ts +41 -0
- package/dist/billing.js +141 -0
- package/dist/bin/crank.d.ts +2 -0
- package/dist/bin/crank.js +34 -0
- package/dist/bin/relayer.d.ts +2 -0
- package/dist/bin/relayer.js +37 -0
- package/dist/chain.d.ts +14 -0
- package/dist/chain.js +48 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.js +61 -0
- package/dist/crank/gate.d.ts +2 -0
- package/dist/crank/gate.js +26 -0
- package/dist/crank/lending.d.ts +16 -0
- package/dist/crank/lending.js +144 -0
- package/dist/crank/prices.d.ts +11 -0
- package/dist/crank/prices.js +177 -0
- package/dist/crank/runner.d.ts +15 -0
- package/dist/crank/runner.js +30 -0
- package/dist/crank/shieldFees.d.ts +15 -0
- package/dist/crank/shieldFees.js +161 -0
- package/dist/epoch-root.d.ts +23 -0
- package/dist/epoch-root.js +98 -0
- package/dist/explorer.d.ts +41 -0
- package/dist/explorer.js +222 -0
- package/dist/gossip.d.ts +4 -0
- package/dist/gossip.js +77 -0
- package/dist/idl.d.ts +2 -0
- package/dist/idl.js +52 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +47 -0
- package/dist/lending.d.ts +82 -0
- package/dist/lending.js +164 -0
- package/dist/log.d.ts +27 -0
- package/dist/log.js +173 -0
- package/dist/lookupTable.d.ts +2 -0
- package/dist/lookupTable.js +47 -0
- package/dist/observer.d.ts +59 -0
- package/dist/observer.js +255 -0
- package/dist/receipt.d.ts +30 -0
- package/dist/receipt.js +27 -0
- package/dist/relayer/chain.d.ts +35 -0
- package/dist/relayer/chain.js +171 -0
- package/dist/relayer/errors.d.ts +8 -0
- package/dist/relayer/errors.js +29 -0
- package/dist/relayer/limits.d.ts +15 -0
- package/dist/relayer/limits.js +47 -0
- package/dist/relayer/relayer.d.ts +25 -0
- package/dist/relayer/relayer.js +54 -0
- package/dist/relayer/server.d.ts +8 -0
- package/dist/relayer/server.js +101 -0
- package/dist/relayer/settings.d.ts +23 -0
- package/dist/relayer/settings.js +69 -0
- package/dist/replay.d.ts +13 -0
- package/dist/replay.js +118 -0
- package/dist/session.d.ts +29 -0
- package/dist/session.js +31 -0
- package/dist/settlement.d.ts +17 -0
- package/dist/settlement.js +96 -0
- package/dist/sha256.d.ts +3 -0
- package/dist/sha256.js +83 -0
- package/dist/shieldLimits.d.ts +15 -0
- package/dist/shieldLimits.js +24 -0
- package/dist/signer.d.ts +5 -0
- package/dist/signer.js +43 -0
- package/dist/token.d.ts +6 -0
- package/dist/token.js +33 -0
- package/package.json +36 -4
- package/README.md +0 -3
package/dist/lending.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.lendingFeeAddress = exports.lendingLoanAddress = exports.lendingLenderAddress = exports.LENDING_PAY_ALL = void 0;
|
|
4
|
+
exports.lendingVaultAddresses = lendingVaultAddresses;
|
|
5
|
+
exports.ensureAssociatedAccountInstruction = ensureAssociatedAccountInstruction;
|
|
6
|
+
exports.createLendingVault = createLendingVault;
|
|
7
|
+
exports.depositLendingLiquidity = depositLendingLiquidity;
|
|
8
|
+
exports.withdrawLendingLiquidity = withdrawLendingLiquidity;
|
|
9
|
+
exports.openLendingLoan = openLendingLoan;
|
|
10
|
+
exports.repayLendingLoan = repayLendingLoan;
|
|
11
|
+
exports.addLendingCollateral = addLendingCollateral;
|
|
12
|
+
exports.extendLendingLoan = extendLendingLoan;
|
|
13
|
+
exports.liquidateLendingLoan = liquidateLendingLoan;
|
|
14
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
15
|
+
const chain_1 = require("./chain");
|
|
16
|
+
const token_1 = require("./token");
|
|
17
|
+
const ASSOCIATED_TOKEN_PROGRAM = new web3_js_1.PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL');
|
|
18
|
+
const text = (s) => Buffer.from(s);
|
|
19
|
+
const le8 = (n) => {
|
|
20
|
+
const b = Buffer.alloc(8);
|
|
21
|
+
b.writeBigUInt64LE(BigInt(n));
|
|
22
|
+
return b;
|
|
23
|
+
};
|
|
24
|
+
exports.LENDING_PAY_ALL = 18446744073709551615n;
|
|
25
|
+
function lendingVaultAddresses(pid, creator, nonce) {
|
|
26
|
+
const vault = (0, chain_1.pda)(pid, text('znl_vault'), creator.toBuffer(), le8(nonce));
|
|
27
|
+
return {
|
|
28
|
+
vault,
|
|
29
|
+
cash: (0, chain_1.pda)(pid, text('znl_cash'), vault.toBuffer()),
|
|
30
|
+
collateral: (0, chain_1.pda)(pid, text('znl_collateral'), vault.toBuffer()),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const lendingLenderAddress = (pid, vault, lender) => (0, chain_1.pda)(pid, text('znl_lender'), vault.toBuffer(), lender.toBuffer());
|
|
34
|
+
exports.lendingLenderAddress = lendingLenderAddress;
|
|
35
|
+
const lendingLoanAddress = (pid, vault, borrower, nonce) => (0, chain_1.pda)(pid, text('znl_loan'), vault.toBuffer(), borrower.toBuffer(), le8(nonce));
|
|
36
|
+
exports.lendingLoanAddress = lendingLoanAddress;
|
|
37
|
+
const lendingFeeAddress = (pid) => (0, chain_1.pda)(pid, text('znl_fee_zgap'));
|
|
38
|
+
exports.lendingFeeAddress = lendingFeeAddress;
|
|
39
|
+
function common(pid) {
|
|
40
|
+
return {
|
|
41
|
+
registry: (0, chain_1.pda)(pid, text('asset_registry')),
|
|
42
|
+
config: (0, chain_1.pda)(pid, text('config')),
|
|
43
|
+
zgapAuthority: (0, chain_1.pda)(pid, text('zgap_authority')),
|
|
44
|
+
zgapMint: (0, chain_1.pda)(pid, text('zgap_mint')),
|
|
45
|
+
stakingVault: (0, chain_1.pda)(pid, text('staking_vault')),
|
|
46
|
+
stakingPool: (0, chain_1.pda)(pid, text('staking_pool')),
|
|
47
|
+
fee: (0, exports.lendingFeeAddress)(pid),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function ensureAssociatedAccountInstruction(payer, owner, mint) {
|
|
51
|
+
return new web3_js_1.TransactionInstruction({
|
|
52
|
+
programId: ASSOCIATED_TOKEN_PROGRAM,
|
|
53
|
+
keys: [
|
|
54
|
+
{ pubkey: payer, isSigner: true, isWritable: true },
|
|
55
|
+
{ pubkey: (0, token_1.associatedTokenAddress)(mint, owner), isSigner: false, isWritable: true },
|
|
56
|
+
{ pubkey: owner, isSigner: false, isWritable: false },
|
|
57
|
+
{ pubkey: mint, isSigner: false, isWritable: false },
|
|
58
|
+
{ pubkey: web3_js_1.SystemProgram.programId, isSigner: false, isWritable: false },
|
|
59
|
+
{ pubkey: token_1.TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
60
|
+
],
|
|
61
|
+
data: Buffer.from([1]),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function createLendingVault(program, o) {
|
|
65
|
+
const pid = program.programId;
|
|
66
|
+
const c = common(pid);
|
|
67
|
+
const a = lendingVaultAddresses(pid, o.creator, o.nonce);
|
|
68
|
+
return program.methods
|
|
69
|
+
.initZnlVault(new (require('bn.js'))(o.nonce.toString()), o.collateralAssetId, o.borrowIsZga, o.collateralRatioBps, o.liquidationThresholdBps, o.interestRateBps, o.originationFeeBps, o.maxLoanDurationDays)
|
|
70
|
+
.accountsPartial({
|
|
71
|
+
vault: a.vault, cashAccount: a.cash, collateralAccount: a.collateral, collateralMint: o.collateralMint,
|
|
72
|
+
borrowMint: o.borrowIsZga ? o.zgaMint : c.zgapMint, registry: c.registry, zgapAuthority: c.zgapAuthority, protocolConfig: c.config,
|
|
73
|
+
zgaMint: o.zgaMint, zgaCache: (0, chain_1.cachePda)(pid, chain_1.ZGA_ASSET_ID), creator: o.creator, tokenProgram: token_1.TOKEN_PROGRAM_ID, systemProgram: web3_js_1.SystemProgram.programId,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
function depositLendingLiquidity(program, o) {
|
|
77
|
+
const pid = program.programId;
|
|
78
|
+
const c = common(pid);
|
|
79
|
+
const BN = require('bn.js');
|
|
80
|
+
return program.methods.depositZnlLiquidity(new BN(o.amount.toString()), new BN(o.minShares.toString())).accountsPartial({
|
|
81
|
+
vault: o.vault, cashAccount: (0, chain_1.pda)(pid, text('znl_cash'), o.vault.toBuffer()), lenderPosition: (0, exports.lendingLenderAddress)(pid, o.vault, o.lender),
|
|
82
|
+
lenderTokenAccount: o.lenderTokenAccount, protocolConfig: c.config, lender: o.lender, authority: o.authority ?? o.lender,
|
|
83
|
+
tokenProgram: token_1.TOKEN_PROGRAM_ID, systemProgram: web3_js_1.SystemProgram.programId,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
async function withdrawLendingLiquidity(program, o) {
|
|
87
|
+
const pid = program.programId;
|
|
88
|
+
const BN = require('bn.js');
|
|
89
|
+
const v = await program.account.lendingVault.fetch(o.vault);
|
|
90
|
+
return program.methods.withdrawZnlLiquidity(new BN(o.shares.toString()), new BN(o.minAmount.toString()))
|
|
91
|
+
.accountsPartial({
|
|
92
|
+
vault: o.vault, cashAccount: (0, chain_1.pda)(pid, text('znl_cash'), o.vault.toBuffer()), lenderPosition: (0, exports.lendingLenderAddress)(pid, o.vault, o.lender),
|
|
93
|
+
lenderTokenAccount: o.lenderTokenAccount, collateralAccount: (0, chain_1.pda)(pid, text('znl_collateral'), o.vault.toBuffer()),
|
|
94
|
+
creator: v.creator, creatorCollateralAccount: (0, token_1.associatedTokenAddress)(v.collateralMint, v.creator),
|
|
95
|
+
lender: o.lender, authority: o.authority ?? o.lender, tokenProgram: token_1.TOKEN_PROGRAM_ID,
|
|
96
|
+
})
|
|
97
|
+
.preInstructions([ensureAssociatedAccountInstruction(o.lender, v.creator, v.collateralMint)]);
|
|
98
|
+
}
|
|
99
|
+
async function openLendingLoan(program, o) {
|
|
100
|
+
const pid = program.programId;
|
|
101
|
+
const c = common(pid);
|
|
102
|
+
const BN = require('bn.js');
|
|
103
|
+
const v = await program.account.lendingVault.fetch(o.vault);
|
|
104
|
+
return program.methods
|
|
105
|
+
.openZnlLoan(new BN(o.loanNonce.toString()), new BN(o.collateralAmount.toString()), new BN(o.principalAmount.toString()), o.durationDays)
|
|
106
|
+
.accountsPartial({
|
|
107
|
+
vault: o.vault, cashAccount: (0, chain_1.pda)(pid, text('znl_cash'), o.vault.toBuffer()), collateralAccount: (0, chain_1.pda)(pid, text('znl_collateral'), o.vault.toBuffer()),
|
|
108
|
+
loan: (0, exports.lendingLoanAddress)(pid, o.vault, o.borrower, o.loanNonce),
|
|
109
|
+
borrowerCollateralAccount: o.borrowerCollateralAccount, borrowerBorrowAccount: o.borrowerBorrowAccount,
|
|
110
|
+
collateralCache: (0, chain_1.cachePda)(pid, v.collateralAssetId), zgaCache: (0, chain_1.cachePda)(pid, chain_1.ZGA_ASSET_ID), registry: c.registry,
|
|
111
|
+
stakingVault: c.stakingVault, stakingPool: c.stakingPool, feeZgapAccount: c.fee, protocolConfig: c.config, zgaMint: o.zgaMint,
|
|
112
|
+
borrower: o.borrower, authority: o.authority ?? o.borrower, tokenProgram: token_1.TOKEN_PROGRAM_ID, systemProgram: web3_js_1.SystemProgram.programId,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function repayLendingLoan(program, o) {
|
|
116
|
+
const pid = program.programId;
|
|
117
|
+
const c = common(pid);
|
|
118
|
+
const BN = require('bn.js');
|
|
119
|
+
return program.methods.repayZnlLoan(new BN(o.amount.toString())).accountsPartial({
|
|
120
|
+
vault: o.vault, cashAccount: (0, chain_1.pda)(pid, text('znl_cash'), o.vault.toBuffer()), collateralAccount: (0, chain_1.pda)(pid, text('znl_collateral'), o.vault.toBuffer()),
|
|
121
|
+
loan: (0, exports.lendingLoanAddress)(pid, o.vault, o.borrower, o.loanNonce),
|
|
122
|
+
borrowerCollateralAccount: o.borrowerCollateralAccount, borrowerBorrowAccount: o.borrowerBorrowAccount,
|
|
123
|
+
stakingVault: c.stakingVault, stakingPool: c.stakingPool, feeZgapAccount: c.fee, borrower: o.borrower, authority: o.authority ?? o.borrower, tokenProgram: token_1.TOKEN_PROGRAM_ID,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function addLendingCollateral(program, o) {
|
|
127
|
+
const pid = program.programId;
|
|
128
|
+
const BN = require('bn.js');
|
|
129
|
+
return program.methods.addZnlCollateral(new BN(o.amount.toString())).accountsPartial({
|
|
130
|
+
vault: o.vault, collateralAccount: (0, chain_1.pda)(pid, text('znl_collateral'), o.vault.toBuffer()),
|
|
131
|
+
loan: (0, exports.lendingLoanAddress)(pid, o.vault, o.borrower, o.loanNonce),
|
|
132
|
+
borrowerCollateralAccount: o.borrowerCollateralAccount, borrower: o.borrower, authority: o.authority ?? o.borrower, tokenProgram: token_1.TOKEN_PROGRAM_ID,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
async function extendLendingLoan(program, o) {
|
|
136
|
+
const pid = program.programId;
|
|
137
|
+
const c = common(pid);
|
|
138
|
+
const v = await program.account.lendingVault.fetch(o.vault);
|
|
139
|
+
return program.methods.extendZnlLoan(o.durationDays).accountsPartial({
|
|
140
|
+
vault: o.vault, cashAccount: (0, chain_1.pda)(pid, text('znl_cash'), o.vault.toBuffer()),
|
|
141
|
+
loan: (0, exports.lendingLoanAddress)(pid, o.vault, o.borrower, o.loanNonce), borrowerBorrowAccount: o.borrowerBorrowAccount,
|
|
142
|
+
collateralCache: (0, chain_1.cachePda)(pid, v.collateralAssetId), zgaCache: (0, chain_1.cachePda)(pid, chain_1.ZGA_ASSET_ID),
|
|
143
|
+
stakingVault: c.stakingVault, stakingPool: c.stakingPool, feeZgapAccount: c.fee, protocolConfig: c.config,
|
|
144
|
+
borrower: o.borrower, authority: o.authority ?? o.borrower, tokenProgram: token_1.TOKEN_PROGRAM_ID,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
async function liquidateLendingLoan(program, o) {
|
|
148
|
+
const pid = program.programId;
|
|
149
|
+
const c = common(pid);
|
|
150
|
+
const loan = await program.account.lendingLoan.fetch(o.loan);
|
|
151
|
+
const v = await program.account.lendingVault.fetch(loan.vault);
|
|
152
|
+
return program.methods.liquidateZnlLoan()
|
|
153
|
+
.accountsPartial({
|
|
154
|
+
vault: loan.vault, cashAccount: (0, chain_1.pda)(pid, text('znl_cash'), loan.vault.toBuffer()),
|
|
155
|
+
collateralAccount: (0, chain_1.pda)(pid, text('znl_collateral'), loan.vault.toBuffer()), loan: o.loan,
|
|
156
|
+
borrowerWallet: loan.borrower, borrowerCollateralAccount: (0, token_1.associatedTokenAddress)(v.collateralMint, loan.borrower), collateralMint: v.collateralMint,
|
|
157
|
+
liquidatorBorrowAccount: (0, token_1.associatedTokenAddress)(v.borrowMint, o.liquidator),
|
|
158
|
+
liquidatorCollateralAccount: (0, token_1.associatedTokenAddress)(v.collateralMint, o.liquidator),
|
|
159
|
+
collateralCache: (0, chain_1.cachePda)(pid, v.collateralAssetId), zgaCache: (0, chain_1.cachePda)(pid, chain_1.ZGA_ASSET_ID),
|
|
160
|
+
stakingVault: c.stakingVault, stakingPool: c.stakingPool, feeZgapAccount: c.fee,
|
|
161
|
+
liquidator: o.liquidator, tokenProgram: token_1.TOKEN_PROGRAM_ID, associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM, systemProgram: web3_js_1.SystemProgram.programId,
|
|
162
|
+
})
|
|
163
|
+
.preInstructions([ensureAssociatedAccountInstruction(o.liquidator, o.liquidator, v.collateralMint)]);
|
|
164
|
+
}
|
package/dist/log.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface LogEntry {
|
|
2
|
+
seq: number;
|
|
3
|
+
player: Uint8Array;
|
|
4
|
+
action: Uint8Array;
|
|
5
|
+
}
|
|
6
|
+
export declare const MAX_ACTION_BYTES = 65536;
|
|
7
|
+
export declare const MAX_LOG_ENTRIES: number;
|
|
8
|
+
export declare function leafHash(e: LogEntry): Uint8Array;
|
|
9
|
+
export declare function nodeHash(left: Uint8Array, right: Uint8Array): Uint8Array;
|
|
10
|
+
export declare function rootOfLeaves(leaves: Uint8Array[]): Uint8Array;
|
|
11
|
+
export declare function logRoot(entries: LogEntry[]): Uint8Array;
|
|
12
|
+
export declare class LogRecorder {
|
|
13
|
+
private entries;
|
|
14
|
+
append(player: Uint8Array, action: Uint8Array): LogEntry;
|
|
15
|
+
get length(): number;
|
|
16
|
+
all(): LogEntry[];
|
|
17
|
+
root(): Uint8Array;
|
|
18
|
+
}
|
|
19
|
+
export interface InclusionProof {
|
|
20
|
+
index: number;
|
|
21
|
+
count: number;
|
|
22
|
+
siblings: Uint8Array[];
|
|
23
|
+
}
|
|
24
|
+
export declare function prove(entries: LogEntry[], index: number): InclusionProof;
|
|
25
|
+
export declare function verifyProof(entry: LogEntry, proof: InclusionProof, root: Uint8Array): boolean;
|
|
26
|
+
export declare function encodeLog(entries: LogEntry[]): Uint8Array;
|
|
27
|
+
export declare function decodeLog(bytes: Uint8Array): LogEntry[];
|
package/dist/log.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LogRecorder = exports.MAX_LOG_ENTRIES = exports.MAX_ACTION_BYTES = void 0;
|
|
4
|
+
exports.leafHash = leafHash;
|
|
5
|
+
exports.nodeHash = nodeHash;
|
|
6
|
+
exports.rootOfLeaves = rootOfLeaves;
|
|
7
|
+
exports.logRoot = logRoot;
|
|
8
|
+
exports.prove = prove;
|
|
9
|
+
exports.verifyProof = verifyProof;
|
|
10
|
+
exports.encodeLog = encodeLog;
|
|
11
|
+
exports.decodeLog = decodeLog;
|
|
12
|
+
const sha256_1 = require("./sha256");
|
|
13
|
+
exports.MAX_ACTION_BYTES = 65536;
|
|
14
|
+
exports.MAX_LOG_ENTRIES = 1 << 20;
|
|
15
|
+
const LEAF_TAG = Uint8Array.of(0x00);
|
|
16
|
+
const NODE_TAG = Uint8Array.of(0x01);
|
|
17
|
+
function u32le(n) {
|
|
18
|
+
const b = new Uint8Array(4);
|
|
19
|
+
new DataView(b.buffer).setUint32(0, n, true);
|
|
20
|
+
return b;
|
|
21
|
+
}
|
|
22
|
+
function equal(a, b) {
|
|
23
|
+
if (a.length !== b.length)
|
|
24
|
+
return false;
|
|
25
|
+
for (let i = 0; i < a.length; i++)
|
|
26
|
+
if (a[i] !== b[i])
|
|
27
|
+
return false;
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
function checkEntry(e) {
|
|
31
|
+
if (!Number.isInteger(e.seq) || e.seq < 0 || e.seq > 4294967295)
|
|
32
|
+
throw new Error('A log entry carries an invalid sequence number');
|
|
33
|
+
if (e.player.length !== 32)
|
|
34
|
+
throw new Error('A log entry names its player by a 32-byte key');
|
|
35
|
+
if (e.action.length > exports.MAX_ACTION_BYTES)
|
|
36
|
+
throw new Error(`An action is longer than ${exports.MAX_ACTION_BYTES} bytes`);
|
|
37
|
+
}
|
|
38
|
+
function leafHash(e) {
|
|
39
|
+
checkEntry(e);
|
|
40
|
+
return (0, sha256_1.sha256)(LEAF_TAG, u32le(e.seq), e.player, u32le(e.action.length), e.action);
|
|
41
|
+
}
|
|
42
|
+
function nodeHash(left, right) {
|
|
43
|
+
return (0, sha256_1.sha256)(NODE_TAG, left, right);
|
|
44
|
+
}
|
|
45
|
+
function levels(leaves) {
|
|
46
|
+
if (leaves.length === 0)
|
|
47
|
+
throw new Error('An empty log has no root');
|
|
48
|
+
const out = [leaves];
|
|
49
|
+
let current = leaves;
|
|
50
|
+
while (current.length > 1) {
|
|
51
|
+
const next = [];
|
|
52
|
+
for (let i = 0; i < current.length; i += 2) {
|
|
53
|
+
next.push(i + 1 < current.length ? nodeHash(current[i], current[i + 1]) : current[i]);
|
|
54
|
+
}
|
|
55
|
+
out.push(next);
|
|
56
|
+
current = next;
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
function leavesOf(entries) {
|
|
61
|
+
if (entries.length > exports.MAX_LOG_ENTRIES)
|
|
62
|
+
throw new Error(`A log holds at most ${exports.MAX_LOG_ENTRIES} entries`);
|
|
63
|
+
entries.forEach((e, i) => {
|
|
64
|
+
if (e.seq !== i)
|
|
65
|
+
throw new Error(`Log entry ${i} carries sequence ${e.seq}`);
|
|
66
|
+
});
|
|
67
|
+
return entries.map(leafHash);
|
|
68
|
+
}
|
|
69
|
+
function rootOfLeaves(leaves) {
|
|
70
|
+
const lv = levels(leaves);
|
|
71
|
+
return lv[lv.length - 1][0];
|
|
72
|
+
}
|
|
73
|
+
function logRoot(entries) {
|
|
74
|
+
return rootOfLeaves(leavesOf(entries));
|
|
75
|
+
}
|
|
76
|
+
class LogRecorder {
|
|
77
|
+
constructor() {
|
|
78
|
+
this.entries = [];
|
|
79
|
+
}
|
|
80
|
+
append(player, action) {
|
|
81
|
+
const entry = { seq: this.entries.length, player: Uint8Array.from(player), action: Uint8Array.from(action) };
|
|
82
|
+
checkEntry(entry);
|
|
83
|
+
if (this.entries.length >= exports.MAX_LOG_ENTRIES)
|
|
84
|
+
throw new Error(`A log holds at most ${exports.MAX_LOG_ENTRIES} entries`);
|
|
85
|
+
this.entries.push(entry);
|
|
86
|
+
return entry;
|
|
87
|
+
}
|
|
88
|
+
get length() {
|
|
89
|
+
return this.entries.length;
|
|
90
|
+
}
|
|
91
|
+
all() {
|
|
92
|
+
return this.entries.slice();
|
|
93
|
+
}
|
|
94
|
+
root() {
|
|
95
|
+
return logRoot(this.entries);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.LogRecorder = LogRecorder;
|
|
99
|
+
function prove(entries, index) {
|
|
100
|
+
const lv = levels(leavesOf(entries));
|
|
101
|
+
if (!Number.isInteger(index) || index < 0 || index >= entries.length)
|
|
102
|
+
throw new Error('The index is outside the log');
|
|
103
|
+
const siblings = [];
|
|
104
|
+
let at = index;
|
|
105
|
+
for (let l = 0; l < lv.length - 1; l++) {
|
|
106
|
+
const sibling = at ^ 1;
|
|
107
|
+
if (sibling < lv[l].length)
|
|
108
|
+
siblings.push(lv[l][sibling]);
|
|
109
|
+
at >>= 1;
|
|
110
|
+
}
|
|
111
|
+
return { index, count: entries.length, siblings };
|
|
112
|
+
}
|
|
113
|
+
function verifyProof(entry, proof, root) {
|
|
114
|
+
if (entry.seq !== proof.index || proof.index >= proof.count)
|
|
115
|
+
return false;
|
|
116
|
+
let hash = leafHash(entry);
|
|
117
|
+
let at = proof.index;
|
|
118
|
+
let width = proof.count;
|
|
119
|
+
let used = 0;
|
|
120
|
+
while (width > 1) {
|
|
121
|
+
const sibling = at ^ 1;
|
|
122
|
+
if (sibling < width) {
|
|
123
|
+
if (used >= proof.siblings.length)
|
|
124
|
+
return false;
|
|
125
|
+
const s = proof.siblings[used++];
|
|
126
|
+
hash = (at & 1) === 0 ? nodeHash(hash, s) : nodeHash(s, hash);
|
|
127
|
+
}
|
|
128
|
+
at >>= 1;
|
|
129
|
+
width = Math.ceil(width / 2);
|
|
130
|
+
}
|
|
131
|
+
return used === proof.siblings.length && equal(hash, root);
|
|
132
|
+
}
|
|
133
|
+
function encodeLog(entries) {
|
|
134
|
+
leavesOf(entries);
|
|
135
|
+
const size = entries.reduce((n, e) => n + 4 + 32 + 4 + e.action.length, 0);
|
|
136
|
+
const out = new Uint8Array(size);
|
|
137
|
+
const view = new DataView(out.buffer);
|
|
138
|
+
let at = 0;
|
|
139
|
+
for (const e of entries) {
|
|
140
|
+
view.setUint32(at, e.seq, true);
|
|
141
|
+
out.set(e.player, at + 4);
|
|
142
|
+
view.setUint32(at + 36, e.action.length, true);
|
|
143
|
+
out.set(e.action, at + 40);
|
|
144
|
+
at += 40 + e.action.length;
|
|
145
|
+
}
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
function decodeLog(bytes) {
|
|
149
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
150
|
+
const entries = [];
|
|
151
|
+
let at = 0;
|
|
152
|
+
while (at < bytes.length) {
|
|
153
|
+
if (at + 40 > bytes.length)
|
|
154
|
+
throw new Error('The log is truncated');
|
|
155
|
+
const seq = view.getUint32(at, true);
|
|
156
|
+
const length = view.getUint32(at + 36, true);
|
|
157
|
+
if (seq !== entries.length)
|
|
158
|
+
throw new Error(`Log entry ${entries.length} carries sequence ${seq}`);
|
|
159
|
+
if (length > exports.MAX_ACTION_BYTES)
|
|
160
|
+
throw new Error(`An action is longer than ${exports.MAX_ACTION_BYTES} bytes`);
|
|
161
|
+
if (at + 40 + length > bytes.length)
|
|
162
|
+
throw new Error('The log is truncated');
|
|
163
|
+
if (entries.length >= exports.MAX_LOG_ENTRIES)
|
|
164
|
+
throw new Error(`A log holds at most ${exports.MAX_LOG_ENTRIES} entries`);
|
|
165
|
+
entries.push({
|
|
166
|
+
seq,
|
|
167
|
+
player: bytes.slice(at + 4, at + 36),
|
|
168
|
+
action: bytes.slice(at + 40, at + 40 + length),
|
|
169
|
+
});
|
|
170
|
+
at += 40 + length;
|
|
171
|
+
}
|
|
172
|
+
return entries;
|
|
173
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ensureLookupTable = ensureLookupTable;
|
|
4
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
7
|
+
async function ensureLookupTable(connection, payer, wanted, cachePath) {
|
|
8
|
+
let address = null;
|
|
9
|
+
if ((0, fs_1.existsSync)(cachePath)) {
|
|
10
|
+
try {
|
|
11
|
+
address = new web3_js_1.PublicKey((0, fs_1.readFileSync)(cachePath, 'utf8').trim());
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
address = null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
if (address && !(await connection.getAddressLookupTable(address)).value)
|
|
18
|
+
address = null;
|
|
19
|
+
if (!address) {
|
|
20
|
+
const [createIx, created] = web3_js_1.AddressLookupTableProgram.createLookupTable({
|
|
21
|
+
authority: payer.publicKey, payer: payer.publicKey, recentSlot: await connection.getSlot('finalized'),
|
|
22
|
+
});
|
|
23
|
+
await (0, web3_js_1.sendAndConfirmTransaction)(connection, new web3_js_1.Transaction().add(createIx), [payer]);
|
|
24
|
+
address = created;
|
|
25
|
+
(0, fs_1.writeFileSync)(cachePath, address.toBase58());
|
|
26
|
+
}
|
|
27
|
+
let table = (await connection.getAddressLookupTable(address)).value;
|
|
28
|
+
const have = new Set((table?.state.addresses ?? []).map((a) => a.toBase58()));
|
|
29
|
+
const missing = wanted.filter((a) => !have.has(a.toBase58()));
|
|
30
|
+
for (let i = 0; i < missing.length; i += 20) {
|
|
31
|
+
const extend = web3_js_1.AddressLookupTableProgram.extendLookupTable({
|
|
32
|
+
lookupTable: address, authority: payer.publicKey, payer: payer.publicKey, addresses: missing.slice(i, i + 20),
|
|
33
|
+
});
|
|
34
|
+
await (0, web3_js_1.sendAndConfirmTransaction)(connection, new web3_js_1.Transaction().add(extend), [payer]);
|
|
35
|
+
}
|
|
36
|
+
for (let tries = 0; tries < 40; tries++) {
|
|
37
|
+
table = (await connection.getAddressLookupTable(address)).value;
|
|
38
|
+
if (table && wanted.every((w) => table.state.addresses.some((a) => a.equals(w))))
|
|
39
|
+
break;
|
|
40
|
+
await sleep(500);
|
|
41
|
+
}
|
|
42
|
+
if (!table)
|
|
43
|
+
throw new Error('The lookup table was not found');
|
|
44
|
+
if (missing.length > 0)
|
|
45
|
+
await sleep(2000);
|
|
46
|
+
return table;
|
|
47
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Connection, PublicKey } from '@solana/web3.js';
|
|
2
|
+
import { BillingTerms, UsageReceipt } from './billing';
|
|
3
|
+
import { ExplorerPolicy } from './explorer';
|
|
4
|
+
export declare function ed25519Sign(secretKey: Uint8Array, message: Uint8Array): Uint8Array;
|
|
5
|
+
export declare function ed25519Verify(publicKey: Uint8Array, message: Uint8Array, signature: Uint8Array): boolean;
|
|
6
|
+
export declare function envelopeHeaders(secretKey: Uint8Array, publicKey: PublicKey, id: string, nowSeconds?: number): Record<string, string>;
|
|
7
|
+
export declare class AvailabilityLog {
|
|
8
|
+
private readonly path;
|
|
9
|
+
private readonly keepMs;
|
|
10
|
+
private samples;
|
|
11
|
+
constructor(path?: string | null, keepMs?: number);
|
|
12
|
+
record(key: string, up: boolean, atMs?: number): void;
|
|
13
|
+
count(key: string): number;
|
|
14
|
+
save(): void;
|
|
15
|
+
coverage(key: string, fromMs: number, toMs: number, intervalMs: number): {
|
|
16
|
+
expected: number;
|
|
17
|
+
samples: number;
|
|
18
|
+
up: number;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export declare function availabilityAcceptable(c: {
|
|
22
|
+
expected: number;
|
|
23
|
+
samples: number;
|
|
24
|
+
up: number;
|
|
25
|
+
}, minCoverage?: number, minUp?: number): boolean;
|
|
26
|
+
export type UrlGuard = (url: string) => Promise<URL>;
|
|
27
|
+
export declare function probeGuild(base: string, guard?: UrlGuard): Promise<boolean>;
|
|
28
|
+
export interface PendingReceipt {
|
|
29
|
+
session: string;
|
|
30
|
+
player: string;
|
|
31
|
+
hours: number;
|
|
32
|
+
fromSlot: string;
|
|
33
|
+
toSlot: string;
|
|
34
|
+
hashHex: string;
|
|
35
|
+
guildSignature: string;
|
|
36
|
+
}
|
|
37
|
+
export declare function fetchPendingReceipts(base: string, secretKey: Uint8Array, publicKey: PublicKey, guard?: UrlGuard): Promise<PendingReceipt[]>;
|
|
38
|
+
export declare function postAttestation(base: string, secretKey: Uint8Array, publicKey: PublicKey, hashHex: string, signature: Uint8Array, guard?: UrlGuard): Promise<boolean>;
|
|
39
|
+
export declare function checkUsageReceipt(program: any, receipt: UsageReceipt, currentSlot: bigint, terms?: BillingTerms): Promise<string | null>;
|
|
40
|
+
export interface ObserverEnv {
|
|
41
|
+
program: any;
|
|
42
|
+
connection: Connection;
|
|
43
|
+
secretKey: Uint8Array;
|
|
44
|
+
publicKey: PublicKey;
|
|
45
|
+
log: AvailabilityLog;
|
|
46
|
+
guard?: UrlGuard;
|
|
47
|
+
terms?: BillingTerms;
|
|
48
|
+
probeIntervalMs?: number;
|
|
49
|
+
minCoverage?: number;
|
|
50
|
+
minUp?: number;
|
|
51
|
+
explorer?: ExplorerPolicy;
|
|
52
|
+
}
|
|
53
|
+
export declare function attestPendingReceipts(env: ObserverEnv, guildKey: PublicKey, base: string): Promise<{
|
|
54
|
+
attested: string[];
|
|
55
|
+
declined: Array<{
|
|
56
|
+
hashHex: string;
|
|
57
|
+
reason: string;
|
|
58
|
+
}>;
|
|
59
|
+
}>;
|