Skip to content

Commit

Permalink
add testing
Browse files Browse the repository at this point in the history
  • Loading branch information
sherifahmed990 committed Aug 28, 2024
1 parent 45981cb commit 22c9c4e
Show file tree
Hide file tree
Showing 4 changed files with 1,780 additions and 17 deletions.
11 changes: 11 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#env values for testing
#sepolia chain example values
#make sure all public addresses are checksummed
CHAIN_ID=11155111
BUNDLER_URL=https://sepolia.test.voltaire.candidewallet.com/rpc
JSON_RPC_NODE_PROVIDER=
PUBLIC_ADDRESS1=
PRIVATE_KEY1=

PUBLIC_ADDRESS2=
PUBLIC_ADDRESS3=
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"clean": "rm -rf dist",
"format": "prettier --write src/*.ts src/**/*.ts src/**/**/*.ts",
"lint": "eslint -f unix \"src/**/*.{ts,tsx}\"",
"prepare": "husky install"
"prepare": "husky install",
"test": "jest"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -45,9 +46,11 @@
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^6.2.0",
"@typescript-eslint/parser": "^6.2.0",
"dotenv": "^16.4.5",
"eslint": "^8.46.0",
"eslint-plugin-tsdoc": "^0.2.17",
"husky": ">=6",
"jest": "^29.7.0",
"lint-staged": ">=10",
"microbundle": "^0.15.1",
"prettier": "3.0.0",
Expand Down
338 changes: 338 additions & 0 deletions test/safe/createAccount.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,338 @@
const accountAbstractionkit = require('../../dist/index.umd');
require('dotenv').config()

jest.setTimeout(300000);

describe('safe account', () => {
const ownerPublicAddress=process.env.PUBLIC_ADDRESS1
const ownerPrivateKey=process.env.PRIVATE_KEY1
const chainId = process.env.CHAIN_ID
const jsonRpcNodeProvider=process.env.JSON_RPC_NODE_PROVIDER
const bundlerUrl=process.env.BUNDLER_URL
const safeAccountVersions = [
accountAbstractionkit.SafeAccountV0_3_0,
accountAbstractionkit.SafeAccountV0_2_0
]
let safeAccountVersionName;
safeAccountVersions.forEach((safeAccountVersion, index) => {
if(index == 0){
safeAccountVersionName = 'V3'
}else{
safeAccountVersionName = 'V2'
}
const expectedAccountAddress =
safeAccountVersion.createAccountAddress(
[ownerPublicAddress],
)
test('initialization - ' + safeAccountVersionName, () => {
//initilize account
//only needed if not deployed yet
const smartAccount =
safeAccountVersion.initializeNewAccount([ownerPublicAddress])
expect(smartAccount.accountAddress).toBe(expectedAccountAddress);
});

test(
'account funded - account needs to be funded with the chains native ' +
'token for the following tests to succeed ' + expectedAccountAddress +
' - ' + safeAccountVersionName, async() => {
const params = [
expectedAccountAddress,
"latest",
];

const balance = await accountAbstractionkit.sendJsonRpcRequest(
jsonRpcNodeProvider, "eth_getBalance", params);

expect(BigInt(balance)).toBeGreaterThan(0n);
});

test('mint nft and deploy account if not deployed - ' +
safeAccountVersionName, async() => {
const smartAccount = new safeAccountVersion(
expectedAccountAddress
)

//mint nft
nftContractAddress = "0x9a7af758aE5d7B6aAE84fe4C5Ba67c041dFE5336";
mintFunctionSignature = 'mint(address)';
mintFunctionSelector = accountAbstractionkit.getFunctionSelector(
mintFunctionSignature);
const mintTransactionCallData = accountAbstractionkit.createCallData(
mintFunctionSelector,
["address"],
[smartAccount.accountAddress]
);
const transaction1 = {
to: nftContractAddress,
value: 0n,
data: mintTransactionCallData,
}

const transaction2 = {
to: nftContractAddress,
value: 0n,
data: mintTransactionCallData,
}

//createUserOperation will determine the nonce, fetch the gas prices,
//estimate gas limits and return a useroperation to be signed.
//you can override all these values using the overrides parameter.
const userOperation = await smartAccount.createUserOperation(
[
//You can batch multiple transactions to be executed in one useroperation.
transaction1, transaction2,
],
jsonRpcNodeProvider, //the node rpc is used to fetch the current nonce and fetch gas prices.
bundlerUrl, //the bundler rpc is used to estimate the gas limits.
//uncomment the following values for polygon or any chains where
//gas prices change rapidly
{
// verificationGasLimitPercentageMultiplier:130
// maxFeePerGasPercentageMultiplier:130,
// maxPriorityFeePerGasPercentageMultiplier:130
}
)
expect(userOperation.sender).toBe(smartAccount.accountAddress);

const accountNonce =
await accountAbstractionkit.fetchAccountNonce(
jsonRpcNodeProvider,
safeAccountVersion.DEFAULT_ENTRYPOINT_ADDRESS,
smartAccount.accountAddress,
)
userOperation.signature = smartAccount.signUserOperation(
userOperation,
[ownerPrivateKey],
chainId,
BigInt(Math.ceil(Date.now()/1000)-(5*60)), //after (5 minutes in the past)
BigInt(Math.ceil(Date.now()/1000)+(50*60)) //until (50 minutes in the future)
)
//use the bundler rpc to send a userOperation
//sendUserOperation will return a SendUseroperationResponse object
//that can be awaited for the useroperation to be included onchain
let sendUserOperationResponse = await smartAccount.sendUserOperation(
userOperation, bundlerUrl
)

//included will return a UserOperationReceiptResult when
//useroperation is included onchain
let userOperationReceiptResult = await sendUserOperationResponse.included()

expect(accountNonce).toBe(userOperationReceiptResult.nonce);
});

async function removeOwner(
jsonRpcNodeProvider,
bundlerUrl,
smartAccount,
chainId,
ownerPrivateKey,
ownerPublicAddress,
) {
//remove the owner first
const removeOwnerMetaTransaction =
await smartAccount.createRemoveOwnerMetaTransaction(
jsonRpcNodeProvider,
ownerPublicAddress,
1
)

const removeOwnerUserOperation = await smartAccount.createUserOperation(
[
removeOwnerMetaTransaction
],
jsonRpcNodeProvider,
bundlerUrl,
)

removeOwnerUserOperation.signature = smartAccount.signUserOperation(
removeOwnerUserOperation,
[ownerPrivateKey],
chainId
)

sendUserOperationResponse = await smartAccount.sendUserOperation(
removeOwnerUserOperation, bundlerUrl
)

await sendUserOperationResponse.included()
}


async function addOwner(
jsonRpcNodeProvider,
bundlerUrl,
smartAccount,
chainId,
ownerPrivateKey,
newOwnerPublicAddress,
) {
const addOwnerMetaTransaction =
smartAccount.createAddOwnerWithThresholdMetaTransaction(
newOwnerPublicAddress, 1
)

const addOwnerUserOperation = await smartAccount.createUserOperation(
[
addOwnerMetaTransaction
],
jsonRpcNodeProvider,
bundlerUrl,
)

addOwnerUserOperation.signature = smartAccount.signUserOperation(
addOwnerUserOperation,
[ownerPrivateKey],
chainId
)

sendUserOperationResponse = await smartAccount.sendUserOperation(
addOwnerUserOperation, bundlerUrl
)

await sendUserOperationResponse.included()
}

test('add owner - ' + safeAccountVersionName, async() => {
const smartAccount = new safeAccountVersion(
expectedAccountAddress
)
let owners = await smartAccount.getOwners(
jsonRpcNodeProvider)

const newOwnerPublicAddress=process.env.PUBLIC_ADDRESS2

if(owners.includes(newOwnerPublicAddress)){
await removeOwner(
jsonRpcNodeProvider,
bundlerUrl,
smartAccount,
chainId,
ownerPrivateKey,
newOwnerPublicAddress,
)
}
await addOwner(
jsonRpcNodeProvider,
bundlerUrl,
smartAccount,
chainId,
ownerPrivateKey,
newOwnerPublicAddress,
)

owners = await smartAccount.getOwners(
jsonRpcNodeProvider)

expect(owners).toStrictEqual([newOwnerPublicAddress, ownerPublicAddress]);
});

test('swap owner - ' + safeAccountVersionName, async() => {
const smartAccount = new safeAccountVersion(
expectedAccountAddress
)

let owners = await smartAccount.getOwners(
jsonRpcNodeProvider)

const oldOwnerPublicAddress=process.env.PUBLIC_ADDRESS2

if(!owners.includes(oldOwnerPublicAddress)){
await addOwner(
jsonRpcNodeProvider,
bundlerUrl,
smartAccount,
chainId,
ownerPrivateKey,
oldOwnerPublicAddress,
)
}

const swapOwnerPublicAddress=process.env.PUBLIC_ADDRESS3
const swapOwnerMetaTransactions =
//notice createSwapOwnerMetaTransactions returns a list of MetaTransactions
await smartAccount.createSwapOwnerMetaTransactions(
jsonRpcNodeProvider,
swapOwnerPublicAddress,
oldOwnerPublicAddress
)

const swapOwnerUserOperation = await smartAccount.createUserOperation(
swapOwnerMetaTransactions,
jsonRpcNodeProvider,
bundlerUrl,
)

swapOwnerUserOperation.signature = smartAccount.signUserOperation(
swapOwnerUserOperation,
[ownerPrivateKey],
chainId
)

sendUserOperationResponse = await smartAccount.sendUserOperation(
swapOwnerUserOperation, bundlerUrl
)

await sendUserOperationResponse.included()
owners = await smartAccount.getOwners(
jsonRpcNodeProvider)

expect(owners).toStrictEqual([swapOwnerPublicAddress, ownerPublicAddress]);
});

test('remove owner - ' + safeAccountVersionName, async() => {
const smartAccount = new safeAccountVersion(
expectedAccountAddress
)

let owners = await smartAccount.getOwners(
jsonRpcNodeProvider)

const removeOwnerPublicAddress=process.env.PUBLIC_ADDRESS3

if(!owners.includes(removeOwnerPublicAddress)){
await addOwner(
jsonRpcNodeProvider,
bundlerUrl,
smartAccount,
chainId,
ownerPrivateKey,
removeOwnerPublicAddress,
)
}

const removeOwnerMetaTransaction =
await smartAccount.createRemoveOwnerMetaTransaction(
jsonRpcNodeProvider,
removeOwnerPublicAddress,
1
)

const removeOwnerUserOperation = await smartAccount.createUserOperation(
[
removeOwnerMetaTransaction
],
jsonRpcNodeProvider,
bundlerUrl,
)

removeOwnerUserOperation.signature = smartAccount.signUserOperation(
removeOwnerUserOperation,
[ownerPrivateKey],
chainId
)

sendUserOperationResponse = await smartAccount.sendUserOperation(
removeOwnerUserOperation, bundlerUrl
)

await sendUserOperationResponse.included()

owners = await smartAccount.getOwners(
jsonRpcNodeProvider)

expect(owners).toStrictEqual([ownerPublicAddress]);
});
});
});
Loading

0 comments on commit 22c9c4e

Please sign in to comment.