npm package: @plenty-labs/v2-sdk
Description: A Typescript based library to enable interaction with Plenty v2 on Tezos.
Author: Plenty Labs
Latest version: 1.0.2

# Plenty V2 SDK
A Typescript based library to enable interaction with Plenty V2 on Tezos.

## Install
```bash
yarn add @plenty-labs/v2-sdk
```
or
```bash
npm install @plenty-labs/v2-sdk
```

## Usage
### Tezos configuration
```typescript
import { InMemorySigner } from "@taquito/signer";
// or
// import { BeaconWallet } from "@taquito/beacon-wallet";
import { Wallet } from "@plenty-labs/v2-sdk";

// If you're using private key
const privateKey = "<private_key>";
const tezos = Wallet.getTezosInstance(
  "https://mainnet.smartpy.io",
  new InMemorySigner(privateKey)
);

// If you're using wallet providers
const wallet = new BeaconWallet(DAppClientOptions);
const tezos = Wallet.getTezosInstance(
  "https://mainnet.smartpy.io",
  wallet
);
```
> Note: You can also use a `TezosToolkit` instance with any other provider as well for further steps.

### Token
- You need to create `Token` instances for further usage.
- `Token` instance requires contract address and id of the token along with token metadata.
- Token metadata can be obtained using the `MetaData.fetchTokenMetadata`.
- If the token metadata is already known the it can be directly passed in the following type structure
```typescript
{
  decimals: number;
  symbol?: string;
  name?: string;
}
```
> Note: If you want to create a tez token instance or get token metadata for tez token, use `tez` or `xtz` as token contract address.

```typescript
const tokenMetadata = await MetaData.fetchTokenMetadata(tezos, "tez");
const token = new Token(tezos, "xtz", tokenMetadata);
```

- `Token` instance creation

```typescript
import { Metadata, Token } from "@plenty-labs/v2-sdk";

(async () => {
  try {
    const tezos = new TezosToolkit(); // Full example in "Tezos configuration" section
    
    // For Tez token use "tez" or "xtz" (case insensitive) as token contract address
    const tokenContract = "KT1SjXiUX63QvdNMcM2m492f7kuf8JxXRLp4";
    
    // If you're using sdk to fetch metadata
    const tokenOneMetadata = await MetaData.fetchTokenMetadata(
      tezos,
      tokenContract
      // For FA2 tokens third argument of number type must be pass as token id.
    );
  
    // For FA2 tokens fourth argument of number type must be pass as token id.
    const tokenOne = new Token(tezos, tokenContract, tokenOneMetadata);
  } catch(e) {
    console.log(e);
  }
})();
```

### Swap
> Note: The order of tokens passes during `Swap` instance creation is very important. First token becomes the input token and second token becomes the output.

```typescript
import { Token, Swap, Wallet } from "@plenty-labs/v2-sdk";

(async () => {
  try {
    const tezos = new TezosToolkit(); // Full example in "Tezos configuration" section
    
    // Full example of token instance creation in "Token" section
    const tokenOne = new Token(tezos, tokenOneContract, tokenOneMetadata);
    const tokenTwo = new Token(tezos, tokenTwoContract, tokenTwoMetadata, tokenTwoId);
    
    const inputValue = "1.21"; // Value should be in string format (with decimals)
    const slippage = "0.5"; // 0.5%
    
    // Swap instance with tokenOne as input token and tokenTwo as expected output
    const swap = new Swap(tezos, tokenOne, tokenTwo);
    
    /* swapTokens method returns an array of TranferParams required for operation to execute.
      Third optional argument of toAccount(reciever) is available if one wants to send tokens bought to other account.
      Throws error if there is no AMM for the selected pair of tokens. */
    const swapTokensParams = await swap.swapTokens(inputValue, slippage); // slippage is optional. default value is 0.5%
    
    // Supports both tezos.wallet.batch() and tezos.contract.batch() as first argument
    const batchOp = Wallet.fetchOperationsBatch(tezos.contract.batch(), swapTokensParams);
    
    const op = batchOp.send();
    console.log(op.hash);
    await op.confirmation();
    console.log("Success");
  } catch(e) {
    console.log(e);
  }
})();
```

### Swap estimates
> Note: `estimateSwap` method accepts either `{inputValue: string}` or `{outputValue: string}` as argument.

```typescript
import { Token, Swap } from "@plenty-labs/v2-sdk";

(async () => {
  try {
    const tezos = new TezosToolkit(); // Full example in "Tezos configuration" section
    
    // Full example of token instance creation in "Token" section
    const tokenOne = new Token(tezos, tokenOneContract, tokenOneMetadata);
    const tokenTwo = new Token(tezos, tokenTwoContract, tokenTwoMetadata, tokenTwoId);
    
    const inputValue = "1.21"; // Value should be in string format (with decimals)
    const slippage = "0.5"; // 0.5%
    
    // Swap instance with tokenOne as input token and tokenTwo as expected output
    const swap = new Swap(tezos, tokenOne, tokenTwo);
    
    const swapEstimates = await swap.estimateSwap({inputValue: "1"});
    const outputValueEstimate = swapEstimates.estimatedAmount; // String value with decimals
    /* Other estimates like fees, fee percentage, minimum amount to be received and exchange rate
      are also calculated which can be access through the swapEstimates object as well */
    console.log(outputValueEstimate);
    
    const inverseSwapEstimates = await swap.estimateSwap({outputValue: "1"});
    const inputValueEstimate = inverseSwapEstimates.estimatedAmount; // String value with decimals
    console.log(inputValueEstimate);
  } catch(e) {
    // Throws error if there is no AMM for the selected pair of tokens
    console.log(e);
  }
})();
```

### Add liquidity
> Note: `addLiquidity` method accepts an object as argument with `token1Value` or `token2Value` or both as key(s). The other value is auto calculated if either one of them is provided.

```typescript
import { Token, Position, Wallet } from "@plenty-labs/v2-sdk";

(async () => {
  try {
    const tezos = new TezosToolkit(); // Full example in "Tezos configuration" section
    
    // Full example of token instance creation in "Token" section
    const tokenOne = new Token(tezos, tokenOneContract, tokenOneMetadata);
    const tokenTwo = new Token(tezos, tokenTwoContract, tokenTwoMetadata, tokenTwoId);
    
    const tokenOneValue = "1"; // Value should be in string format (with decimals)
    const tokenTwoValue = "1.21"; // Value should be in string format (with decimals)
    
    const myPosition = new Position(tezos, tokenOne, tokenTwo);
    
    /* addLiquidity method returns an array of TranferParams required for operation to execute.
       Throws error if there is no pool of the selected pair of tokens. */
    const addLiquidityParams = await myPosition.addLiquidity({token1Value: tokenOneValue});
    // or
    // const addLiquidityParams = await myPosition.addLiquidity({token2Value: tokenTwoValue});
    // or
    // const addLiquidityParams = await myPosition.addLiquidity({token1Value: tokenOneValue, token2Value: tokenTwoValue});
    
    // Supports both tezos.wallet.batch() and tezos.contract.batch() as first argument
    const batchOp = Wallet.fetchOperationsBatch(tezos.contract.batch(), addLiquidityParams);
    
    const op = batchOp.send();
    console.log(op.hash);
    await op.confirmation();
    console.log("Success");
  } catch(e) {
    console.log(e);
  }
})();
```

### Remove liquidity
```typescript
import { Token, Position, Wallet } from "@plenty-labs/v2-sdk";

(async () => {
  try {
    const tezos = new TezosToolkit(); // Full example in "Tezos configuration" section
    
    // Full example of token instance creation in "Token" section
    const tokenOne = new Token(tezos, tokenOneContract, tokenOneMetadata);
    const tokenTwo = new Token(tezos, tokenTwoContract, tokenTwoMetadata, tokenTwoId);
    
    const myPosition = new Position(tezos, tokenOne, tokenTwo);
    
    // Fetch lp token balance for the user(signer)
    const lpTokenBalance = await myPosition.fetchLiquidityBalance(); // Returns string with decimals
    
    /* removeLiquidity method returns an array of TranferParams required for operation to execute.
       Throws error if there is no pool of the selected pair of tokens. */
    const removeLiquidityParams = await myPosition.removeLiquidity(lpTokenBalance);
    // or (with desired lpToken value)
    // const removeLiquidityParams = await myPosition.removeLiquidity("2.34");
    
    // Supports both tezos.wallet.batch() and tezos.contract.batch() as first argument
    const batchOp = Wallet.fetchOperationsBatch(tezos.contract.batch(), removeLiquidityParams);
    
    const op = batchOp.send();
    console.log(op.hash);
    await op.confirmation();
    console.log("Success");
  } catch(e) {
    console.log(e);
  }
})();
```

### Liquidity estimates
```typescript
import { Token, Position } from "@plenty-labs/v2-sdk";

(async () => {
  try {
    const tezos = new TezosToolkit(); // Full example in "Tezos configuration" section
    
    // Full example of token instance creation in "Token" section
    const tokenOne = new Token(tezos, tokenOneContract, tokenOneMetadata);
    const tokenTwo = new Token(tezos, tokenTwoContract, tokenTwoMetadata, tokenTwoId);
    
    const tokenOneValue = "1"; // Value should be in string format (with decimals)
    const tokenTwoValue = "1.21"; // Value should be in string format (with decimals)
    const lpTokenValue = "2.31"; // Value should be in string format (with decimals)
    
    const myPosition = new Position(tezos, tokenOne, tokenTwo);
    
    // Estimates while adding liquidity
    const tokenTwoAmount = await myPosition.estimateOtherTokenAmount({token1Value: tokenOneValue}); // Returns string with decimals
    console.log(tokenTwoAmount);

    const tokenOneAmount = await myPosition.estimateOtherTokenAmount({token2Value: tokenTwoValue});
    console.log(tokenOneAmount);
    
    const lpTokensRecivedEstimate = await myPosition.estimateLiquidityTokenAmount({token1Value: tokenOneValue}); // Returns string with decimals
    // or
    // const lpTokensRecivedEstimate = await myPosition.estimateLiquidityTokenAmount({token2Value: tokenTwoValue});
    // or
    // const lpTokensRecivedEstimate = await myPosition.estimateLiquidityTokenAmount({token1Value: tokenOneValue, token2Value: tokenTwoValue});
    console.log(lpTokensRecivedEstimate);
    
    // Estimates while removing liquidity
    const outputTokenAmountEstimate = await myPosition.estimateOutputAmounts(lpTokenValue);
    const tokenOneEstimate = outputTokenAmountEstimate.token1Amount;
    const tokenTwoEstimate = outputTokenAmountEstimate.token2Amount;
    console.log(tokenOneEstimate);
    console.log(tokenTwoEstimate);
  } catch(e) {
    console.log(e);
  }
})();
```

### Token balance
```typescript
import { Token } from "@plenty-labs/v2-sdk";

(async () => {
  try {
    const tezos = new TezosToolkit(); // Full example in "Tezos configuration" section
    
    // Full example of token instance creation in "Token" section
    const tokenOne = new Token(tezos, tokenOneContract, tokenOneMetadata);
    
    // Fetch token balance for the user(signer)
    const balance = await tokenOne.fetchBalance(); // Returns string with decimals
    console.log(balance);
  } catch(e) {
    console.log(e);
  }
})();
```

## License

MIT