Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sdk bug fixes #21

Merged
merged 3 commits into from
Nov 20, 2023
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
7 changes: 2 additions & 5 deletions .github/workflows/testing.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name: CI/CD
name: tests

on:
push:
branches: [main, staging]
branches: [main, staging, develop]
pull_request:

jobs:
Expand All @@ -21,8 +21,5 @@ jobs:
- name: Install Dependencies
run: npm install

- name: Run Linting
run: npm run lint

- name: Run Tests
run: npm test
33 changes: 25 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ Import and initialise the Aarc SDK in your project.
import { ethers } from "ethers";
import { AarcSDK } from "aarc-sdk";

let aarcSDK = new AarcSDK.default({
let aarcSDK = new AarcSDK({
rpcUrl: rpcUrl,
signer: signer, // the user's ethers.signer object
chainId: chainId,
apiKey: "YOUR_API_KEY",
});

Expand All @@ -49,6 +49,7 @@ Retrieve balances of all tokens in an EOA wallet:

```typescript
let balances = await aarcSDK.fetchBalances(
eoaAddress: string,
tokenAddress: string[] // Optional: Array of specific token addresses
);
```
Expand All @@ -59,12 +60,14 @@ Transfer tokens from EOA to any receiver wallet address:

```typescript
await aarcSDK.executeMigration({
senderSigner: signer, // ethers.signer object
receiverAddress:'RECEIVER_WALLET_ADDRESS',
tokenAndAmount: // Optional. If not passed, the SDK will migrate all the tokens of the wallet
transferTokenDetails: // Optional. If not passed, the SDK will migrate all the tokens of the wallet
[
{
tokenAddress:TOKEN1_ADDRESS,
amount:TOKEN1_AMOUNT // ethers.BigNumber
amount:TOKEN1_AMOUNT, // ethers.BigNumber in case of erc20 and native token
tokenIds: string[] // tokenIds for nfts
},
...
]
Expand Down Expand Up @@ -92,12 +95,14 @@ Transfer tokens from EOA to any receiver wallet address without gas fees. Please

```typescript
await aarcSDK.executeMigration({
senderSigner: signer, // ethers.signer object
receiverAddress:RECEIVER_WALLET_ADDRESS,
tokenAndAmount: // Optional. If not passed, the SDK will migrate all the tokens of the wallet
transferTokenDetails: // Optional. If not passed, the SDK will migrate all the tokens of the wallet
[
{
tokenAddress:TOKEN1_ADDRESS,
amount:TOKEN1_AMOUNT // ethers.BigNumber
amount:TOKEN1_AMOUNT, // ethers.BigNumber in case of erc20 and native token
tokenIds: string[] // tokenIds for nfts
},
...
],
Expand Down Expand Up @@ -129,19 +134,31 @@ Fetching Existing Safes:

Retrieve a list of all Safe smart wallets associated with the user's EOA:
```typescript
const safes = await aarcSDK.getAllSafes();
const safes = await aarcSDK.getAllSafes(owner: string); // owner's eoaAddress
// This returns an array of Safe wallet addresses
```

Creating a New Safe Wallet:

Generate a new Safe smart wallet. The address returned is a counterfactual address, and the wallet needs to be deployed later. Asset migration can be directed to this address even before deployment.
```typescript
const newSafeAddress = await aarcSDK.generateSafeSCW();
const newSafeAddress = await aarcSDK.generateSafeSCW(
config: {owners: string[], threshold: number},
saltNonce?: number // default value is 0
);
// Returns a counterfactual address for the new Safe wallet
```

### Biconomy Smart Wallet

Fetching Existing Safes:

Retrieve a list of all Biconomy smart wallets associated with the user's EOA:
```typescript
const biconomySWs = await aarcSDK.getAllBiconomySCWs(owner: string); // owner's eoaAddress
// This returns an array of Biconomy wallet addresses
```

Creating a New Biconomy Wallet:

Similar to the Safe wallet, you can create a Biconomy smart wallet. The address provided is also a counterfactual address, requiring later deployment. The migration process can target this address immediately.
Expand Down
100 changes: 62 additions & 38 deletions src/AarcSDK.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import {
RelayTrxDto,
SingleTransferPermitDto,
TokenData,
} from './utils/Types';
TokenNftData,
} from './utils/AarcTypes';
import { PERMIT2_BATCH_TRANSFER_ABI } from './utils/abis/Permit2BatchTransfer.abi';
import { PERMIT2_SINGLE_TRANSFER_ABI } from './utils/abis/Permit2SingleTransfer.abi';
import { GelatoRelay } from '@gelatonetwork/relay-sdk';
Expand Down Expand Up @@ -72,8 +73,8 @@ class AarcSDK {
}

// Forward the methods from Safe
getAllSafes(eoaAddress: string) {
return this.safe.getAllSafes(this.chainId, eoaAddress);
getAllSafes(owner: string) {
return this.safe.getAllSafes(this.chainId, owner);
}

generateSafeSCW(config: {owners: string[], threshold: number}, saltNonce?: number) {
Expand Down Expand Up @@ -121,13 +122,13 @@ class AarcSDK {
try {
Logger.log('executeMigration ');

const { tokenAndAmount, receiverAddress, senderSigner } = executeMigrationDto;
const { transferTokenDetails, receiverAddress, senderSigner } = executeMigrationDto;
const owner = await senderSigner.getAddress();
const tokenAddresses = tokenAndAmount?.map((token) => token.tokenAddress);
const tokenAddresses = transferTokenDetails?.map((token) => token.tokenAddress);

let balancesList = await this.fetchBalances(owner, tokenAddresses);

tokenAndAmount?.map((tandA) => {
transferTokenDetails?.map((tandA) => {
const matchingToken = balancesList.data.find(
(mToken) =>
mToken.token_address.toLowerCase() ===
Expand All @@ -142,30 +143,52 @@ class AarcSDK {
}
});

const updatedTokens: TokenData[] = [];
for (const tokenInfo of balancesList.data) {
const matchingToken = tokenAndAmount?.find(
(token) =>
token.tokenAddress.toLowerCase() ===
tokenInfo.token_address.toLowerCase(),
);
if (transferTokenDetails){
const updatedTokens: TokenData[] = [];
for (const tokenInfo of balancesList.data) {
const matchingToken = transferTokenDetails?.find(
(token) =>
token.tokenAddress.toLowerCase() ===
tokenInfo.token_address.toLowerCase(),
);

if (
matchingToken &&
matchingToken.amount !== undefined &&
BigNumber.from(matchingToken.amount).gt(0) &&
BigNumber.from(matchingToken.amount).gt(tokenInfo.balance)
) {
response.push({
tokenAddress: tokenInfo.token_address,
amount: matchingToken?.amount,
message: 'Supplied amount is greater than balance',
});
} else updatedTokens.push(tokenInfo);
}
if (
matchingToken &&
matchingToken.amount !== undefined &&
BigNumber.from(matchingToken.amount).gt(0) &&
BigNumber.from(matchingToken.amount).gt(tokenInfo.balance)
) {
response.push({
tokenAddress: tokenInfo.token_address,
amount: matchingToken?.amount,
message: 'Supplied amount is greater than balance',
});
} else if (
matchingToken &&
matchingToken.tokenIds !== undefined &&
tokenInfo.nft_data !== undefined
){
const nftTokenIds: TokenNftData[] = [];
for (const tokenId of matchingToken.tokenIds) {
const tokenExist = tokenInfo.nft_data.find((nftData) => nftData.tokenId === tokenId);
if(tokenExist){
nftTokenIds.push(tokenExist);
} else {
response.push({
tokenAddress: tokenInfo.token_address,
tokenId: tokenId,
message: 'Supplied NFT does not exist',
});
}
}
tokenInfo.nft_data = nftTokenIds;
updatedTokens.push(tokenInfo);
} else if(matchingToken) updatedTokens.push(tokenInfo);
}

// Now, updatedTokens contains the filtered array without the undesired elements
balancesList.data = updatedTokens;
// Now, updatedTokens contains the filtered array without the undesired elements
balancesList.data = updatedTokens;
}

let tokens = balancesList.data.filter((balances) => {
return (
Expand All @@ -178,7 +201,7 @@ class AarcSDK {
Logger.log(' filtered tokens ', tokens);

tokens = tokens.map((element: TokenData) => {
const matchingToken = tokenAndAmount?.find(
const matchingToken = transferTokenDetails?.find(
(token) =>
token.tokenAddress.toLowerCase() ===
element.token_address.toLowerCase(),
Expand All @@ -192,13 +215,13 @@ class AarcSDK {
element.balance = matchingToken.amount;
}

// Case: tokenAndAmount contains amount for token but it's greater than the given allowance
// Case: transferTokenDetails contains amount for token but it's greater than the given allowance
// Then we assign the allowance amount 0 to perform normal token transfer
if (
element.type === COVALENT_TOKEN_TYPES.STABLE_COIN &&
COVALENT_TOKEN_TYPES.CRYPTO_CURRENCY &&
element.permit2Allowance.gte(BigNumber.from(0)) &&
element.balance.gt(element.permit2Allowance)
BigNumber.from(element.permit2Allowance).gte(BigNumber.from(0)) &&
BigNumber.from(element.balance).gt(element.permit2Allowance)
) {
element.permit2Allowance = BigNumber.from(0);
}
Expand All @@ -214,6 +237,7 @@ class AarcSDK {

Logger.log('nfts ', nfts);

// token address, tokenIds: array of tokenIds
for (const collection of nfts) {
if (collection.nft_data) {
for (const nft of collection.nft_data) {
Expand Down Expand Up @@ -430,14 +454,14 @@ class AarcSDK {
): Promise<MigrationResponse[]> {
const response: MigrationResponse[] = [];
try {
const { senderSigner, tokenAndAmount, receiverAddress, gelatoApiKey } =
const { senderSigner, transferTokenDetails, receiverAddress, gelatoApiKey } =
executeMigrationGaslessDto;
const owner = await senderSigner.getAddress();
const tokenAddresses = tokenAndAmount?.map((token) => token.tokenAddress);
const tokenAddresses = transferTokenDetails?.map((token) => token.tokenAddress);

const balancesList = await this.fetchBalances(owner, tokenAddresses);

tokenAndAmount?.map((tandA) => {
transferTokenDetails?.map((tandA) => {
const matchingToken = balancesList.data.find(
(mToken) =>
mToken.token_address.toLowerCase() ===
Expand All @@ -454,7 +478,7 @@ class AarcSDK {

const updatedTokens: TokenData[] = [];
for (const tokenInfo of balancesList.data) {
const matchingToken = tokenAndAmount?.find(
const matchingToken = transferTokenDetails?.find(
(token) =>
token.tokenAddress.toLowerCase() ===
tokenInfo.token_address.toLowerCase(),
Expand Down Expand Up @@ -525,7 +549,7 @@ class AarcSDK {
Logger.log(' filtered tokens ', tokens);

tokens = tokens.map((element: TokenData) => {
const matchingToken = tokenAndAmount?.find(
const matchingToken = transferTokenDetails?.find(
(token) =>
token.tokenAddress.toLowerCase() ===
element.token_address.toLowerCase(),
Expand All @@ -539,7 +563,7 @@ class AarcSDK {
element.balance = matchingToken.amount;
}

// Case: tokenAndAmount contains amount for token but it's greater than the given allowance
// Case: transferTokenDetails contains amount for token but it's greater than the given allowance
// Then we assign the allowance amount 0 to perform normal token transfer
if (
element.type === COVALENT_TOKEN_TYPES.STABLE_COIN &&
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/GelatoHelper.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { SponsoredCallRequest } from '@gelatonetwork/relay-sdk';
import { TaskState } from '@gelatonetwork/relay-sdk/dist/lib/status/types';
import { Logger } from '../utils/Logger';
import { GelatoTxStatusDto, RelayTrxDto } from '../utils/Types';
import { GelatoTxStatusDto, RelayTrxDto } from '../utils/AarcTypes';

export const relayTransaction = async (
relayTrxDto: RelayTrxDto,
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/PermitHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
TokenTransferDto,
NftTransferDto,
NativeTransferDto,
} from '../utils/Types';
} from '../utils/AarcTypes';
import {
TypedDataDomain,
TypedDataSigner,
Expand Down
9 changes: 5 additions & 4 deletions src/utils/types.ts → src/utils/AarcTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,22 @@ export type BalancesResponse = {
message: string;
};

export type TokenAndAmount = {
export type TransferTokenDetails = {
tokenAddress: string;
amount?: BigNumber;
amount?: BigNumber; // for ERC20
tokenIds?: string[]; // for ERC721
};

export type ExecuteMigrationDto = {
senderSigner: Signer;
receiverAddress: string;
tokenAndAmount?: TokenAndAmount[];
transferTokenDetails?: TransferTokenDetails[];
};

export type ExecuteMigrationGaslessDto = {
senderSigner: Signer;
receiverAddress: string;
tokenAndAmount?: TokenAndAmount[];
transferTokenDetails?: TransferTokenDetails[];
gelatoApiKey: string;
};

Expand Down
Loading
Loading