# Smart Contract Wallet - Zerodev

Polynomial core contracts supports  Account Abstracted (AA) Wallets based on[ ERC 4337](https://www.erc4337.io/).  Currently we uses Zerodev as our primary AA provider and this docs will be containing configurations and examples of using zerodev Smart contract wallets for trade in Polynomial perps.

*It is not mandatory to use AA wallets to trade on polynomial. But txs from AA wallet will be sponsored.  You can save gas fees by using AA wallets rather than directly interacting with your EOA.*&#x20;

### Bundler and Paymaster config

```typescript

bundlerAPI: 'https://polynomial-mainnet.g.alchemy.com/v2/nUkjX-R-WfZwctQu_TLm0xQ7KI8TVXaD',
paymasterAPI: 'https://polynomial-mainnet.g.alchemy.com/v2/nUkjX-R-WfZwctQu_TLm0xQ7KI8TVXaD',
policy: '14119bab-6c62-4fed-8fe7-27ad5fcc5754'

```

### Sample Code Snippets

#### AA client Setup (Typescript)

* Uses Wagmi , Viem and zerodev sdk

```typescript
import { getWalletClient } from '@wagmi/core';
import { signerToEcdsaValidator, getKernelAddressFromECDSA } from '@zerodev/ecdsa-validator';
import {createPublicClient} from 'viem';
import {
	addressToEmptyAccount,
	createKernelAccount,
	createKernelAccountClient
} from '@zerodev/sdk';

const client = await getWalletClient(wagmiConfig);

const publicClient = createPublicClient({
	transport: http(getZeroDevBundlerRPC(chain.id, true, ZERODEV_PROVIDER)),
	chain: chain
});

const ecdsaValidator = await signerToEcdsaValidator(publicClient, {
	signer: client,
	entryPoint,
	kernelVersion: KERNEL_V3_1
});

const account = await createKernelAccount(publicClient, {
	plugins: {
		sudo: ecdsaValidator
	},
	entryPoint,
	index: 8008n,
	kernelVersion: "0.3.1"

});

const aaClient = createKernelAccountClient({
	account,
	chain,
	pollingInterval: 500,
	bundlerTransport: http(getZeroDevBundlerRPC(chain.id, false, ZERODEV_PROVIDER)),
	paymaster: {
		getPaymasterData(userOperation) {
			return sponsorUserOperationPolynomial({
				userOperation,
				entryPoint,
				chain
			});
		}
	},
	userOperation: {
		estimateFeesPerGas() {
			return {
				maxFeePerGas: 0n,
				maxPriorityFeePerGas: 0n
			};
		}
	}
});

```

#### SponsorUserOperation function

```typescript
const sponsorUserOperationPolynomial = async (params: {
	userOperation: any;
	entryPoint: entryPointType;
	chain: Chain;
}) => {
	const { userOperation, entryPoint, chain } = params;
	if (chain.id !== polynomialSepolia.id && chain.id != polynomialChain.id) {
		throw new Error('Invalid chain id');
	}

	const policyId = config[chain.id].erc4337.policy;
	const bundlerAPI = config[chain.id].erc4337.bundlerAPI;
	const options = {
		method: 'POST',
		headers: {
			accept: 'application/json',
			'content-type': 'application/json'
		},
		body: JSON.stringify({
			id: 1,
			jsonrpc: '2.0',
			method: 'alchemy_requestGasAndPaymasterAndData',
			params: [
				{
					policyId: policyId,
					entryPoint: entryPoint.address,
					dummySignature: userOperation.signature,
					userOperation: {
						sender: userOperation.sender,
						nonce: `0x${userOperation.nonce.toString(16)}`,
						factory: userOperation.factory,
						factoryData: userOperation.factoryData,
						callData: userOperation.callData
					}
				}
			]
		})
	};

	const response = await (await fetch(bundlerAPI, options)).json();
	const data = response;

	const result: any = {
		...userOperation,
		paymaster: data.result.paymaster,
		paymasterData: data.result.paymasterData,
		preVerificationGas: BigInt(data.result.preVerificationGas),
		verificationGasLimit: BigInt(data.result.verificationGasLimit),
		callGasLimit: BigInt(data.result.callGasLimit),
		paymasterVerificationGasLimit: BigInt(data.result.paymasterVerificationGasLimit),
		paymasterPostOpGasLimit: BigInt(data.result.paymasterPostOpGasLimit),
		maxFeePerGas: BigInt(data.result.maxFeePerGas),
		maxPriorityFeePerGas: BigInt(data.result.maxPriorityFeePerGas)
	};
	return result;
};
```

#### Transaction Execution through Zerodev

```typescript
export const executeTransactionThroughZerodev = async (
	_smartContractWalletAddress: address,
	_target: address[],
	_callData: Hex[],
	value: bigint[],
	callType: string = CALL_TYPE.DELEGATE_CALL,
	retry = false
) => {

	const kernelClient = get(aaWalletClient); // Checkout setup code

	const encodedCallData = await kernelClient.account.encodeCalls(
		_target.map((target, index) => ({
			to: target,
			data: _callData[index],
			value: value[index],
		})),
		callType
	);

	const entryPoint = kernelClient.account.entryPoint;
	const userOp = await kernelClient.signUserOperation({
		callData: encodedCallData,
		preVerificationGas: ZERODEV_GAS_LIMITS.PRE_VERIFICATION_GAS,
		callGasLimit: ZERODEV_GAS_LIMITS.CALL_GAS_LIMIT,
		verificationGasLimit: ZERODEV_GAS_LIMITS.VERIFICATION_GAS_LIMIT,
		maxFeePerGas: retry ? 1n : 0n,
		maxPriorityFeePerGas: retry ? 1n : 0n
	});

	const userOpHash = await kernelClient.sendUserOperation({

		entryPoint,
		...userOp
	});

	return {
		executedType: EXECUTED_TYPE.ZERO_DEV,
		txData: userOpHash
	};
};

```
