Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions light-sdk-ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"test-account": "ts-mocha --resolveJsonModule ./tsconfig.json -t 100000000 tests/account.test.ts --exit",
"test-relayer": "ts-mocha --resolveJsonModule ./tsconfig.json -t 100000000 tests/relayer.test.ts --exit",
"test-createOutUtxos": "ts-mocha --resolveJsonModule ./tsconfig.json -t 100000000 tests/createOutUtxos.test.ts --exit",
"test-provider": "ts-mocha --resolveJsonModule ./tsconfig.json -t 100000000 tests/provider.test.ts --exit",
"build": "yarn tsc",
"format": "prettier --write \"src/**/*.{ts,js}\"",
"lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
Expand Down
5 changes: 5 additions & 0 deletions light-sdk-ts/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ export const DEFAULT_PROGRAMS = {
clock: SYSVAR_CLOCK_PUBKEY,
};

// TODO: adjust according to relayer fees
// recommented minimum amount of lamports to be able to pay for transaction fees
// needs to be more than 100k to be rentexempt
export const MINIMUM_LAMPORTS = 150_000;

// TODO: make account object with important accounts
export const MERKLE_TREE_KEY = new PublicKey(
"DCxUdYgqjE6AR9m13VvqpkxJqGJYnk8jn8NEeD3QY3BU",
Expand Down
10 changes: 10 additions & 0 deletions light-sdk-ts/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ export enum ProviderErrorCode {
SOL_MERKLE_TREE_UNDEFINED = "SOL_MERKLE_TREE_UNDEFINED",
ANCHOR_PROVIDER_UNDEFINED = "ANCHOR_PROVIDER_UNDEFINED",
PROVIDER_UNDEFINED = "PROVIDER_UNDEFINED",
NODE_WALLET_AND_BROWSER_WALLET_UNDEFINED = "NODE_WALLET_AND_BROWSER_WALLET_UNDEFINED",
NODE_WALLET_UNDEFINED = "NODE_WALLET_UNDEFINED",
URL_UNDEFINED = "URL_UNDEFINED",
CONNECTION_UNDEFINED = "CONNECTION_UNDEFINED",
CONNECTION_DEFINED = "CONNECTION_DEFINED",
KEYPAIR_UNDEFINED = "KEYPAIR_UNDEFINED",
NODE_WALLET_AND_BROWSER_WALLET_DEFINED = "NODE_WALLET_AND_BROWSER_WALLET_DEFINED",
MERKLE_TREE_NOT_INITIALIZED = "MERKLE_TREE_NOT_INITIALIZED",
}

export enum VerifierErrorCode {
Expand Down Expand Up @@ -146,3 +154,5 @@ export class AccountError extends MetaError {}
export class RelayerError extends MetaError {}

export class CreateUtxoError extends MetaError {}

export class ProviderError extends MetaError {}
2 changes: 1 addition & 1 deletion light-sdk-ts/src/test-utils/functionalCircuit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export async function functionalCircuitTest(
});
let mockPubkey = SolanaKeypair.generate().publicKey;

let lightProvider = await LightProvider.loadMock(mockPubkey);
let lightProvider = await LightProvider.loadMock();
let txParams = new TransactionParameters({
outputUtxos: [deposit_utxo1],
merkleTreePubkey: mockPubkey,
Expand Down
10 changes: 1 addition & 9 deletions light-sdk-ts/src/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1556,15 +1556,7 @@ export class Transaction {
await this.provider.provider.connection.getRecentBlockhash("confirmed")
).blockhash;
const txMsg = new TransactionMessage({
payerKey:
this.params.relayer.accounts.relayerPubkey !==
this.provider.browserWallet?.publicKey &&
this.params.relayer.accounts.relayerPubkey !==
this.provider.nodeWallet?.publicKey
? this.params.relayer.accounts.relayerPubkey
: this.provider.browserWallet
? this.provider.browserWallet.publicKey
: this.provider.nodeWallet!.publicKey,
payerKey: this.params.relayer.accounts.relayerPubkey,
instructions: [
ComputeBudgetProgram.setComputeUnitLimit({ units: 1_400_000 }),
ix,
Expand Down
11 changes: 11 additions & 0 deletions light-sdk-ts/src/wallet/createOutUtxos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ const getRecipientsAmount = (mint: PublicKey, recipients: Recipient[]) => {
// transfer
// check no publics

// shield
// sumInSol +sumSolAmount
// sumInSpl +sumSplAmount
// publicMint

// create via recipients requested utxos and subtract amounts from sums
// beforeEach utxo check that no amount is negative

Expand Down Expand Up @@ -220,6 +225,12 @@ export function createOutUtxos({
"createOutUtxos",
"Shield and relayer fee defined",
);
if (!publicSolAmount && !publicSplAmount)
throw new CreateUtxoError(
CreateUtxoErrorCode.NO_PUBLIC_AMOUNTS_PROVIDED,
"createOutUtxos",
"publicSolAmount not initialized for unshield",
);
if (!publicSplAmount) publicSplAmount = new BN(0);
if (!publicSolAmount) publicSolAmount = new BN(0);
let publicSplAssetIndex = assets.findIndex(
Expand Down
96 changes: 59 additions & 37 deletions light-sdk-ts/src/wallet/provider.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
import {
AnchorError,
AnchorProvider,
setProvider,
Wallet,
} from "@coral-xyz/anchor";
import { AnchorProvider, setProvider } from "@coral-xyz/anchor";
import { SolMerkleTree } from "../merkleTree";
import {
PublicKey,
Keypair as SolanaKeypair,
Connection,
ConfirmOptions,
} from "@solana/web3.js";
import {
ADMIN_AUTH_KEYPAIR,
initLookUpTable,
initLookUpTableFromFile,
setUpMerkleTree,
} from "../test-utils";
import { ADMIN_AUTH_KEYPAIR, initLookUpTableFromFile } from "../test-utils";
import { MERKLE_TREE_HEIGHT, MERKLE_TREE_KEY } from "../constants";
import { MerkleTree } from "../merkleTree/merkleTree";
import { ProviderError, ProviderErrorCode } from "../errors";
const axios = require("axios");
const circomlibjs = require("circomlibjs");

Expand Down Expand Up @@ -46,8 +37,8 @@ export class Provider {
solMerkleTree?: SolMerkleTree;
provider?: AnchorProvider | { connection: Connection }; // temp -?
url?: string;
minimumLamports: number;

// TODO: refactor by streamlining everything towards using connection and not anchor provider
// - get rid of url
/**
* Init either with nodeWallet or browserWallet. Feepayer is the provided wallet
* Optionally provide confirmConfig, Default = 'confirmed'.
Expand All @@ -58,26 +49,38 @@ export class Provider {
confirmConfig,
connection,
url = "http://127.0.0.1:8899",
minimumLamports = 5000 * 30,
}: {
nodeWallet?: SolanaKeypair;
browserWallet?: BrowserWallet;
confirmConfig?: ConfirmOptions;
connection?: Connection;
url?: string;
minimumLamports?: number;
}) {
if (nodeWallet && browserWallet)
throw new Error("Both node and browser environments provided.");
if (!nodeWallet && !browserWallet) throw new Error("No wallet provided.");
if (nodeWallet && !url) throw new Error("No url provided.");
throw new ProviderError(
ProviderErrorCode.NODE_WALLET_AND_BROWSER_WALLET_DEFINED,
"constructor",
"Both node and browser environments provided chose one.",
);
if (!nodeWallet && !browserWallet)
throw new ProviderError(
ProviderErrorCode.NODE_WALLET_AND_BROWSER_WALLET_UNDEFINED,
"constructor",
"No wallet provided.",
);
if (browserWallet && !connection)
throw new Error("No connection provided.");
throw new ProviderError(
ProviderErrorCode.CONNECTION_UNDEFINED,
"constructor",
"No connection provided with browser wallet.",
);
if (nodeWallet && connection)
throw new Error(
throw new ProviderError(
ProviderErrorCode.CONNECTION_DEFINED,
"constructor",
"Connection provided in node environment. Provide a url instead",
);
this.minimumLamports = minimumLamports;

this.confirmConfig = confirmConfig || { commitment: "confirmed" };

if (nodeWallet) {
Expand All @@ -98,7 +101,7 @@ export class Provider {
}
}

static async loadMock(mockPubkey: PublicKey) {
static async loadMock() {
let mockProvider = new Provider({
nodeWallet: ADMIN_AUTH_KEYPAIR,
url: "mock",
Expand All @@ -107,7 +110,7 @@ export class Provider {
mockProvider.lookUpTable = SolanaKeypair.generate().publicKey;
mockProvider.solMerkleTree = new SolMerkleTree({
poseidon: mockProvider.poseidon,
pubkey: mockPubkey,
pubkey: MERKLE_TREE_KEY,
});

return mockProvider;
Expand All @@ -121,14 +124,15 @@ export class Provider {
return;
}
if (!this.provider) throw new Error("No provider set.");
// TODO: remove this should not exist
this.lookUpTable = await initLookUpTableFromFile(this.provider);
} catch (err) {
console.error(err);
throw err;
}
}

private async fetchMerkleTree() {
private async fetchMerkleTree(merkleTreePubkey: PublicKey) {
try {
if (this.browserWallet) {
const response = await axios.get("http://localhost:3331/merkletree");
Expand All @@ -145,20 +149,24 @@ export class Provider {

this.solMerkleTree = { ...response.data.data, merkleTree, pubkey };
}
// TODO: move to a seperate function

const merkletreeIsInited = await this.provider!.connection.getAccountInfo(
MERKLE_TREE_KEY,
merkleTreePubkey,
);
if (!merkletreeIsInited) {
await setUpMerkleTree(this.provider!);
// TODO: throw error
throw new ProviderError(
ProviderErrorCode.MERKLE_TREE_NOT_INITIALIZED,
"fetchMerkleTree",
`Merkle tree is not initialized if on local host run test utils setUpMerkleTree before initin the provider, on other networks check your merkle tree pubkey ${merkleTreePubkey}`,
);
}

const mt = await SolMerkleTree.build({
pubkey: MERKLE_TREE_KEY,
pubkey: merkleTreePubkey,
poseidon: this.poseidon,
provider: this.provider,
});

console.log("✔️ building merkletree done");
this.solMerkleTree = mt;
} catch (err) {
Expand All @@ -172,7 +180,7 @@ export class Provider {
this.poseidon = poseidon;
}
async latestMerkleTree() {
await this.fetchMerkleTree();
await this.fetchMerkleTree(MERKLE_TREE_KEY);
}
// TODO: add loadEddsa

Expand All @@ -183,18 +191,28 @@ export class Provider {
* @param connection get from useConnection() hook
*/
static async browser(
walletContext?: BrowserWallet,
connection?: Connection,
browserWallet: BrowserWallet,
connection: Connection,
confirmConfig?: ConfirmOptions,
): Promise<Provider> {
if (!browserWallet) {
throw new ProviderError(ProviderErrorCode.KEYPAIR_UNDEFINED, "browser");
}
if (!connection) {
throw new ProviderError(
ProviderErrorCode.CONNECTION_UNDEFINED,
"browser",
);
}

const provider = new Provider({
browserWallet: walletContext,
browserWallet,
confirmConfig,
connection,
});
await provider.loadPoseidon();
await provider.fetchLookupTable();
await provider.fetchMerkleTree();
await provider.fetchMerkleTree(MERKLE_TREE_KEY);
return provider;
}

Expand All @@ -205,18 +223,22 @@ export class Provider {
* @param url full-node rpc endpoint to instantiate a Connection
*/
static async native(
keypair?: SolanaKeypair,
keypair: SolanaKeypair,
url?: string,
confirmConfig?: ConfirmOptions,
): Promise<Provider> {
if (!keypair) {
throw new ProviderError(ProviderErrorCode.KEYPAIR_UNDEFINED, "native");
}

const provider = new Provider({
nodeWallet: keypair,
confirmConfig,
url,
});
await provider.loadPoseidon();
await provider.fetchLookupTable();
await provider.fetchMerkleTree();
await provider.fetchMerkleTree(MERKLE_TREE_KEY);
return provider;
}
}
15 changes: 5 additions & 10 deletions light-sdk-ts/src/wallet/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
MERKLE_TREE_KEY,
TOKEN_REGISTRY,
merkleTreeProgramId,
MINIMUM_LAMPORTS,
} from "../constants";
import {
ADMIN_AUTH_KEY,
Expand Down Expand Up @@ -511,9 +512,7 @@ export class User {
// TODO: implement browserWallet support; for UI
throw new Error("Browser wallet support not implemented yet!");
}
extraSolAmount = extraSolAmount
? extraSolAmount * 1e9
: this.provider.minimumLamports;
extraSolAmount = extraSolAmount ? extraSolAmount * 1e9 : MINIMUM_LAMPORTS;
} else {
// amount = amount * tokenCtx.decimals;
extraSolAmount = amount * tokenCtx.decimals;
Expand Down Expand Up @@ -562,7 +561,7 @@ export class User {
* @params token: string
* @params amount: number - in base units (e.g. lamports for 'SOL')
* @params recipient: PublicKey - Solana address
* @params extraSolAmount: number - optional, if not set, will use provider minimumLamports
* @params extraSolAmount: number - optional, if not set, will use MINIMUM_LAMPORTS
*/
async unshield({
token,
Expand All @@ -587,9 +586,7 @@ export class User {
recipient,
);

extraSolAmount = extraSolAmount
? extraSolAmount * 1e9
: this.provider.minimumLamports;
extraSolAmount = extraSolAmount ? extraSolAmount * 1e9 : MINIMUM_LAMPORTS;
} else {
extraSolAmount = amount;
amount = 0;
Expand Down Expand Up @@ -658,9 +655,7 @@ export class User {
amount = amount * tokenCtx.decimals;

if (!tokenCtx.isSol) {
extraSolAmount = extraSolAmount
? extraSolAmount * 1e9
: this.provider.minimumLamports;
extraSolAmount = extraSolAmount ? extraSolAmount * 1e9 : MINIMUM_LAMPORTS;
} else {
extraSolAmount = amount;
amount = 0;
Expand Down
Loading